17

While developing an ASP.NET MVC app, I'm finding a few places where my JsonResult actions throw an exception "A circular reference was detected while serializing an object".

For now, I'm removing the references in question, but ideally I'd like to simply mark the property such that the JSON serializer ignores it.

Can anyone suggest how I might do this?

4
  • What serializer are you using? Commented Aug 12, 2009 at 22:38
  • JsonResult is my return type, so I'm assuming the serializer that is default in ASP.NET MVC 1.0's controller class. Commented Aug 12, 2009 at 22:53
  • Which is the JavaScriptSerializer. Commented Aug 12, 2009 at 22:54
  • I had the exact same problem, except in MVC2, the error seems to be "RecursionLimit was exceeded!". Kudos to Marc, [ScriptIgnore] solves it perfectly. Commented Aug 19, 2010 at 1:36

5 Answers 5

28

[ScriptIgnore] should work for you.

Sign up to request clarification or add additional context in comments.

3 Comments

This should work because a JsonResult uses the JavaScriptSerializer internally.
Note to others: you may have to add a reference to the System.Web.Extensions assembly in order to make this available, at least in .NET 4.
System.Web.Script.Serialization.ScriptIgnore
13

I've generally found that for complex objects its best to just serialize by creating a temporary 'inbetween' object :

For instance for testimonials I do the following. I actually do this in the codebehind for my ASPX model page.

This creates a nice JSON object. You'll notice I can even refactor my model and the page will still work. Its just another layer of abstraction between the data model and the page. I dont think my controller should know about JSON as much as possible, but the ASPX 'codebehind' certainly can.

/// <summary>
/// Get JSON for testimonials
/// </summary>
public string TestimonialsJSON
{
    get
    {
        return Model.Testimonials.Select(
            x => new
            {
                testimonial = x.TestimonialText,
                name = x.name
            }
            ).ToJSON();
    }
}

In my ASPX I just do this in a block:

var testimonials = <%= TestimonialsJSON %>;

// oh and ToJSON() is an extension method
public static class ObjectExtensions
{
    public static string ToJSON(this Object obj)
    {
        return new JavaScriptSerializer().Serialize(obj);
    }
}

I'm ready for the backlash against this suggestion... bring it on...

I'm not accessing data, merely reformatting a model for the View. This is 'view model' logic, not 'controller model' logic.

3 Comments

+1. At first I wanted to provide some backlash "I don't want to create multiple models", but you mention "view model" which is starting to make some sense to me: you make models for business logic, why not make models for view logic? Brilliant! Not the answer to my specific situation, but def worth an upvote.
i dont want to create multiple models either! this is the easiest way to do so without having to create another class (unnecessary here). the model should be the data and only the data, not how that data is displayed and while not always practical you should always minimize the coupling between view and model incase that view changes to a different technology or you need to provide multiple different views (ajax/flash/plain html)
I like this approach in the case where you might need a few different JSON serializations of the same underlying model.
2

I would advise to use JSON.NET. It allows to serialize circular references and provides much more serialization options.

Comments

2

What Simon said. Add a little AutoMapper action to keep code weight under control.

Comments

1

The cleanest approach i've found is to use a combination of [DataContract] on the class and [DataMember] on the properties you want to serialize. The DataContract attribute tells the various serializers to ignore any property that doesn't have the DataMember attribute.

There are two major benefits compared to using ScriptIgnoreAttribute. First, it doesn't have a dependency on the System.Web.Extensions assembly. Second, it works with other types of serialization, not just JSON. For example, if you're using the new Web API in MVC 4, the DataContract/DataMember approach will work with the XML serializer as well.

Consider the scenario where your entities are stored in an shared library and reused across various projects - you don't want a dependency on System.Web.Extensions, and you want to loosely describe serialization rules - not hardcode behavior specific to JSON, XML, etc.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.