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?

JMP
  • 7,734
  • 6
  • 33
  • 34

5 Answers5

28

[ScriptIgnore] should work for you.

Matthieu
  • 4,605
  • 4
  • 40
  • 60
Marc
  • 9,254
  • 2
  • 29
  • 31
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.

Tom Mayfield
  • 6,235
  • 2
  • 32
  • 43
Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689
  • 2
    +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. – JMP Aug 13 '09 at 15:46
  • 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) – Simon_Weaver Aug 13 '09 at 18:23
  • I like this approach in the case where you might need a few different JSON serializations of the same underlying model. – David Hay Dec 17 '14 at 05:12
2

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

Dmytrii Nagirniak
  • 23,696
  • 13
  • 75
  • 130
2

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

Wyatt Barnett
  • 15,573
  • 3
  • 34
  • 53
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.

ShadowChaser
  • 5,520
  • 2
  • 31
  • 33