Search code examples
c#jsonjsonserializer

.net circularReferenceException when converting to JSON. How to Limit references?


I have two model classes, Address and Product, they are in a many-to-many relationship on the Database.

When I try to load Addresses using Include() to also get the Products, I get a circularReferenceException when I try to convert it to a JSON. That makes perfect sense, the JSON would become infinitly long.

I know, that I can resolve this problem by putting [ScriptIgnore] on top of one referencing lists.

But that causes a new problem: I need to resolve the relationship in both directions and put them into a JSON, depending on the situation. By that I mean that, depending on the situation, I need Products and the referenced Addresses at another point I need Addresses an their Product references;

Here are my classes(shortened):

public class Product
{

    ...

    [ScriptIgnore]
    public List<Address> Addresses { get; set; }
}

Address class:

   public class Address
{
    ....

    public List<Product> Products { get; set; }

    ...
}

Getting the Data:

        public JsonResult GetAllOrders()
    {
        EFDbContext context = new EFDbContext();
        return Json(context.Addresses.Include(a => a.Products).ToList(), JsonRequestBehavior.AllowGet);
    }

Is there a Way to tell the serializer which references to ignore and which to honor? In the above situation I would like the Address->Product reference to be honored but the Product->Address in their children to be ignored.

The only solution that comes to my mind is to loop over each address and their Product and remove the references. But I hope there is a more elegant way.


Solution

  • You need to go through a new object which doesn't have a circular reference. For example:

    public static object ToAnonymousType(this Address address)
    {
        var products = address.Products.Select(p => p.ToAnonymousType());
        return new { Id = address.Id, Products=products };
    }
    
    public static object ToAnonymousType(this Product product)
    {
        return new { Id = product.Id };
    }
    
    public JsonResult GetAllOrders()
    {
        using(var context = new EFDbContext())
        {
            var addresses = context.Addresses.Include(a => a.Products).ToList().Select(a => a.ToAnonymousType());
            return Json(addresses, JsonRequestBehavior.AllowGet);
        }
    }