检测到自检参考循环 – 从WebApi获取数据到浏览器
我正在使用entity framework,并有父母和孩子的数据到浏览器的问题。 这是我的课程:
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; } }
我正在使用下面的代码来返回问题和答案的数据:
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; }
在C#方面,这似乎工作,但我注意到答案对象的引用回到问题。 当我使用WebAPI来获取数据到浏览器时,我收到以下消息:
“ObjectContent`1”types未能序列化内容types为“application / json; 字符集= UTF-8' 。
对于types为“Models.Core.Question”的属性“问题”检测到自回参考循环。
这是因为问题有答案和答案有一个参考回到问题? 我所看过的所有地方都build议参考孩子的父母,所以我不知道该怎么做。 有人可以给我一些build议吗?
这是因为问题有答案和答案有一个参考回到问题?
是。 它不能被序列化。
编辑:看到Tallmaris的答案和OttO的评论,因为它更简单,可以设置全球。
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
老答案:
将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; } }
就像是:
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; }
你也可以在你的Application_Start()
试试这个:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
它应该解决您的问题,而不会经过很多的箍。
如果使用OWIN,请记住,没有更多的GlobalSettings给你! 您必须修改HttpConfiguration对象中的相同设置,该对象将传递给IAppBuilder UseWebApi函数(或您所在的任何服务平台)
会看起来像这样。
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); }
在ASP.NET Core中,修复如下所示:
services .AddMvc() .AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
如果使用DNX / MVC 6 / ASP.NET vNext等等,甚至HttpConfiguration
丢失。 您必须在Startup.cs
文件中使用以下代码来configuration格式化程序。
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); }); }
使用这个:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore
没有为我工作。 相反,我创build了一个新的,我的模型类的简化版本只是为了testing,并返回罚款。 这篇文章进入了我的模型中,EF的伟大工作,但不是可序列化的一些问题:
http://www.asp.net/web-api/overview/data/using-web-api-with-entity-framework/part-4
ReferenceLoopHandling.Ignore没有为我工作。 唯一的办法就是通过代码去掉我不想要的父母的链接,并保留我所做的。
parent.Child.Parent = null;
由于延迟加载你得到这个错误。 因此,我的build议是从属性中删除虚拟键。 如果您正在使用API,则延迟加载对您的API健康状况不利。
无需在configuration文件中添加额外的行。
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; } }
我发现这个错误是在我生成一个现有的数据库的edmx(XML文件,定义了一个概念模型)并导航属性到父和子表时导致的。 我删除了所有的父对象的导航链接,因为我只想导航到孩子,问题就解决了。
实体db =新实体()
db.Configuration.ProxyCreationEnabled = false;
db.Configuration.LazyLoadingEnabled = false;
对于使用.Net Framework 4.5的新的Asp.Net Web应用程序:
Web Api:转到App_Start – > WebApiConfig.cs:
应该看起来像这样:
public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API configuration and services // Configure Web API to use only bearer token authentication. config.SuppressDefaultHostAuthentication(); config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType)); // ReferenceLoopHandling.Ignore will solve the Self referencing loop detected error config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; //Will serve json as default instead of XML config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html")); // Web API routes config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } }