Read More on Telerik Blogs
January 25, 2010 Web, ASP.NET MVC
Get A Free Trial

Sometimes when performing ajax databinding with the MVC grid you may end up with unexpected result: server error 500.

What is even stranger is that server-side binding works as expected with the same data binding code. Let’s demystify this problem:

The problem

You will see the following  if you use FireBug or Fiddler to inspect the response:

The error message is “A circular reference was detected while serializing an object of type” followed by some type. If you google this up you will find out that this exception is thrown by the JavaScriptSerializer class because of circular references detected. “What the heck is a circular reference anyway?” you may ask. In my example it is the well known Orders-Customers relationship:

Most O/R mapping tools (it is Entity Framework in my case) would create reference properties. In this case the Orders object will have a Categories property and the Categories object will have an Orders prooperty:

Since the MVC grid is ajax-bound to Orders the JavaScriptSerializer will try to serialize the data. During that process it tries to serialize all properties of the Orders type which includes “Categories” as well. However when traversing the Categories object the JavaScriptSerializer discovers the circular reference (the Orders property) and gives up by throwing the aforementioned exception.

 

Solutions

There are three possible solutions of this problem:

  1. Use server binding (if this is an option at all).
  2. Avoid generating reference properties.
    If using EF you can change the visibility of the association property (make it anything but public):
     
    In case of Linq To Sql you can prevent the property generation altogether:
  3. Use ViewModel object instead of the original object created by the O/R mapping tool. This one is my favorite as it does not require any modifications to the model objects. The whole idea is explained in this blog post but I will cover it here as well:
    1. Create a new class which will contain only the properties required for databinding the grid (properties mapped to grid columns that is). If binding to EF make sure you add the key property (OrderID in this case) to the ViewModel even if you are not displaying it in the grid. Otherwise you will end up with NotSupportedException saying “Cannot find primitive type or property to sort by”.
    2. public class OrderViewModel
      {
      public int OrderID
      {
      get;
      set;
      }

      public DateTime? OrderDate
      {
      get;
      set;
      }
      }
    3. Modify your controller (or repository) to return object of the ViewModel type:
    4. public ActionResult Index()
      {
      var model = from o in new NorthwindEntities().Orders
      select new OrderViewModel
      {
      OrderID = o.OrderID,
      OrderDate = o.OrderDate
      };
      return View(model);
      }

      [GridAction]
      public ActionResult AjaxIndex()
      {
      var model = from o in new NorthwindEntities().Orders
      select new OrderViewModel
      {
      OrderID = o.OrderID,
      OrderDate = o.OrderDate
      };

      return View(new GridModel
      {
      Data = model
      });
      }

I hope this helps!


About the Author

Atanas Korchev

 is Team Leader in Kendo UI Team

Related Posts