C# 检测到自引用循环 - 将数据从 WebApi 返回到浏览器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17313632/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 09:08:46  来源:igfitidea点击:

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

c#entity-frameworkserializationasp.net-web-apijson.net

提问by

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:

在 C# 方面,这似乎有效,但是我注意到答案对象引用了问题。当我使用 WebAPI 将数据发送到浏览器时,我收到以下消息:

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'.

“ObjectContent`1”类型无法序列化内容类型“application/json”的响应主体;字符集=utf-8'。

检测到类型为“Models.Core.Question”的属性“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.

这是因为问题有答案并且答案有对问题的引用吗?我看过的所有地方都建议参考孩子的父母,所以我不知道该怎么做。有人可以就此给我一些建议。

采纳答案by Sam Leach

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.

编辑:请参阅 Tallmaris 的回答和 OttO 的评论,因为它更简单并且可以全局设置。

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

Old Answer:

旧答案:

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

将 EF 对象Question投影到您自己的中间或 DataTransferObject。然后可以成功序列化此 Dto。

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; 
}

回答by Tallmaris

You can also try this in your Application_Start():

你也可以在你的Application_Start()

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

It should fix your problem without going through many hoops.

它应该可以解决您的问题,而不会遇到很多麻烦。



EDIT:编辑:根据下面 OttO 的评论,使用:ReferenceLoopHandling.IgnoreReferenceLoopHandling.Ignore代替。

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

回答by Mike

Using this:

使用这个:

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

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

didn't work for me. Instead I created a new, simplified version of my model class just to test, and that returned fine. This article goes into some of the issues I was having in my model that worked great for EF, but weren't serializable:

对我不起作用。相反,我创建了一个新的简化版本的模型类来测试,结果很好。这篇文章讨论了我在模型中遇到的一些问题,这些问题对 EF 很有用,但不能序列化:

http://www.asp.net/web-api/overview/data/using-web-api-with-entity-framework/part-4

http://www.asp.net/web-api/overview/data/using-web-api-with-entity-framework/part-4

回答by Rob Sedgwick

ReferenceLoopHandling.Ignore didn't work for me. The only way I could get round it was to remove via code the links back to the parent I didn't want and keep the ones I did.

ReferenceLoopHandling.Ignore 对我不起作用。我能绕过它的唯一方法是通过代码删除链接回我不想要的父级并保留我做的那些。

parent.Child.Parent = null;

回答by Bon

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)

如果使用 OWIN,请记住,不再需要 GlobalSettings!您必须在传递给 IAppBuilder UseWebApi 函数(或您所在的任何服务平台)的 HttpConfiguration 对象中修改相同的设置

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);
}

回答by Stewart Hou

If using DNX / MVC 6 / ASP.NET vNext blah blah, even HttpConfigurationis missing. You must config formatters by using following codes in your Startup.csfile.

如果使用 DNX / MVC 6 / ASP.NET vNext 等等,甚至HttpConfiguration会丢失。您必须在Startup.cs文件中使用以下代码来配置格式化程序。

public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().Configure<MvcOptions>(option => 
        {
            //Clear all existing output formatters
            option.OutputFormatters.Clear();
            var jsonOutputFormatter = new JsonOutputFormatter();
            //Set ReferenceLoopHandling
            jsonOutputFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
            //Insert above jsonOutputFormatter as the first formatter, you can insert other formatters.
            option.OutputFormatters.Insert(0, jsonOutputFormatter);
        });
    }

回答by PAWAN RAJ Shakya

Due to lazy loading you are getting this error. Hence my suggestion is to remove virtual key from property. If you are working with API then lazy loading is not good for your API health.

由于延迟加载,您会收到此错误。因此我的建议是从财产中删除虚拟钥匙。如果您正在使用 API,那么延迟加载对您的 API 健康不利。

No need to add extra line in your config file.

无需在配置文件中添加额外的行。

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

public class Answer
{
    public int AnswerId { get; set; }
    public string Text { get; set; }
    public int QuestionId { get; set; }
    public Question Question { get; set; }
}

回答by Zymotik

I found this error was being caused when I generated an edmx (XML file that defines a conceptual model) of an existing database and it had Navigation properties to both the parent and child tables. I deleted all the navigation links to the parent objects, as I only wanted to navigate to children, and the problem was solved.

我发现这个错误是在我生成现有数据库的 edmx(定义概念模型的 XML 文件)时引起的,并且它具有到父表和子表的导航属性。我删除了所有到父对象的导航链接,因为我只想导航到子对象,问题就解决了。

回答by Mohsen Afshin

In ASP.NET Core the fix is as follows:

在 ASP.NET Core 中,修复如下:

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

回答by Imran

Entities db = new Entities()

实体数据库 = 新实体()

db.Configuration.ProxyCreationEnabled = false;

db.Configuration.ProxyCreationEnabled = false;

db.Configuration.LazyLoadingEnabled = false;

db.Configuration.LazyLoadingEnabled = false;