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

image

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:

image

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:

image

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:

image

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):
     image
    In case of Linq To Sql you can prevent the property generation altogether:
    image
  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

Comments

Comments are disabled in preview mode.