Self referencing loop detected - Getting back data from WebApi to the browser

88,451

Solution 1

Is this because the Question has Answers and the Answers have a reference back to Question?

Yes. It cannot be serialized.

EDIT: See Tallmaris's answer and OttO's comment as it is simpler and can be set globally.

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.Re‌​ferenceLoopHandling = ReferenceLoopHandling.Ignore;

Old Answer:

Project the EF object Question to your own intermediate or DataTransferObject. This Dto can then be serialized successfully.

public class QuestionDto
{
    public QuestionDto()
    {
        this.Answers = new List<Answer>();
    } 
    public int QuestionId { get; set; }
    ...
    ...
    public string Title { get; set; }
    public List<Answer> Answers { get; set; }
}

Something like:

public IList<QuestionDto> GetQuestions(int subTopicId, int questionStatusId)
{
    var questions = _questionsRepository.GetAll()
        .Where(a => a.SubTopicId == subTopicId &&
               (questionStatusId == 99 ||
                a.QuestionStatusId == questionStatusId))
        .Include(a => a.Answers)
        .ToList();

    var dto = questions.Select(x => new QuestionDto { Title = x.Title ... } );

    return dto; 
}

Solution 2

You can also try this in your Application_Start():

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;

It should fix your problem without going through many hoops.


EDIT: As per OttO's comment below, use: ReferenceLoopHandling.Ignore instead.

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;

Solution 3

In ASP.NET Core the fix is as follows:

services
.AddMvc()
.AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);

Solution 4

If using OWIN, remember, no more GlobalSettings for you! You must modify this same setting in an HttpConfiguration object which gets passed to the IAppBuilder UseWebApi function (or whatever service platform you're on)

Would look something like this.

    public void Configuration(IAppBuilder app)
    {      
       //auth config, service registration, etc      
       var config = new HttpConfiguration();
       config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
       //other config settings, dependency injection/resolver settings, etc
       app.UseWebApi(config);
}

Solution 5

ASP.NET Core Web-API (.NET Core 2.0):

// Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.Configure<MvcJsonOptions>(config =>
    {
        config.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
    });
}
Share:
88,451

Related videos on Youtube

Admin
Author by

Admin

Updated on March 19, 2022

Comments

  • Admin
    Admin about 2 years

    I am using Entity Framework and having a problem with getting parent and child data to the browser. Here are my classes:

     public class Question
     {
        public int QuestionId { get; set; }
        public string Title { get; set; }
        public virtual ICollection<Answer> Answers { get; set; }
    }
    
    public class Answer
    {
        public int AnswerId { get; set; }
        public string Text { get; set; }
        public int QuestionId { get; set; }
        public virtual Question Question { get; set; }
    }
    

    I am using the following code to return the question and answer data:

        public IList<Question> GetQuestions(int subTopicId, int questionStatusId)
        {
            var questions = _questionsRepository.GetAll()
                .Where(a => a.SubTopicId == subTopicId &&
                       (questionStatusId == 99 ||
                        a.QuestionStatusId == questionStatusId))
                .Include(a => a.Answers)
                .ToList();
            return questions; 
        }
    

    On the C# side this seems to work however I notice that the answer objects have references back to the question. When I use the WebAPI to get the data to the browser I get the following message:

    The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.

    Self referencing loop detected for property 'question' with type 'Models.Core.Question'.

    Is this because the Question has Answers and the Answers have a reference back to Question? All the places I have looked suggest having a reference to the parent in the child so I am not sure what to do. Can someone give me some advice on this.

    • cuongle
      cuongle almost 11 years
      Use Dto for your web api, avoiding return Entity directly in your reaponse
    • Admin
      Admin almost 11 years
      What is Dto? Our whole application uses EF, we are using AngularJS on the client, and we have no problems other than for this one case.
    • cuongle
      cuongle almost 11 years
      What I meant you should define your Dto for your Web Api, Dto is kind of similar with ViewModel in MVC. Dto is like a wrapper o your EF model to provide data your your client (angularjs).
    • mayabelle
      mayabelle over 10 years
    • Murat Yıldız
      Murat Yıldız almost 6 years
      You might have a look at my answer on “Self Referencing Loop Detected” exception with JSON.Net page.
  • OttO
    OttO over 10 years
    I know this is an old thread but for those who stumble upon it in the future, try: GlobalConfiguration.Configuration.Formatters.JsonFormatter.S‌​erializerSettings.Re‌​ferenceLoopHandling = ReferenceLoopHandling.Ignore;
  • J86
    J86 almost 10 years
    @OttO, your suggestions worked for me. Thanks very much.
  • Claiton Lovato
    Claiton Lovato over 8 years
    I would like to add, for me setting ReferenceLoopHandling.Ignore did not work, setting it globaly or on the API startup didnt work at all. I managed to get it working by decorating the navigation property of the child class with [JsonIgnore] . I still get the ParentId but the Parent navigation is ignored while serialising.
  • Michał W.
    Michał W. over 8 years
    In asp-net rc-1-final i believe it is "services.Configure<MvcOptions>" now
  • Admin
    Admin almost 8 years
    JsonOutputFormatter is in the namespace Microsoft.AspNet.Mvc.Formatters
  • Microsoft Developer
    Microsoft Developer almost 8 years
    Code goes into infinite loop and shows stack overflow exception after adding this line.
  • aherrick
    aherrick almost 8 years
    For .NET Core 1.0 RTM: new JsonOutputFormatter(serializerSettings, ArrayPool<char>.Shared);
  • Dragos Durlut
    Dragos Durlut over 7 years
    GlobalConfiguration.Configuration.Formatters.JsonFormatter.S‌​erializerSettings.Re‌​ferenceLoopHandling = ReferenceLoopHandling.Ignore; works better
  • Sithu
    Sithu over 7 years
    You saved my day. I was wondering why the answer above was not working. Yes, using OWIN setting in Global.asax will not work.
  • Tallmaris
    Tallmaris over 7 years
    @Demodave you have to create your JsonSerializer using the static Create() method that accepts a setting as parameter. Docs: newtonsoft.com/json/help/html/…
  • Bartosz
    Bartosz almost 7 years
    Hello, Ignoring the serialization will break the circular dependency Question>Answer>Question. Does the DTO approach preserve it?
  • Ren
    Ren over 5 years
    I have this problem in an old ASP.NET MVC project. GlobalConfiguration.Configuration does not have Formatters. Can you plz suggest what can be done for that?
  • anhtv13
    anhtv13 almost 4 years
    GlobalConfiguration.Configuration.Formatters.JsonFormatter.S‌​erializerSettings.Re‌​‌​ferenceLoopHandlin‌​g = ReferenceLoopHandling.Ignore; -> Where to put this line of code???
  • Christopher
    Christopher over 2 years
    This is what I needed - thank you!