with type tutorial referencing property mvc loop framework for ejemplo detected c# entity-framework serialization asp.net-web-api json.net

type - web api c# ejemplo



Se detectó un bucle de referencia automática: cómo recuperar datos de WebApi en el navegador (13)

Estoy usando Entity Framework y tengo un problema para obtener datos de padres e hijos en el navegador. Aquí están mis clases:

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

Estoy usando el siguiente código para devolver los datos de pregunta y respuesta:

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

En el lado de C # esto parece funcionar, sin embargo, noto que los objetos de respuesta tienen referencias a la pregunta. Cuando uso WebAPI para obtener los datos en el navegador, recibo el siguiente mensaje:

El tipo ''ObjectContent`1'' no pudo serializar el cuerpo de la respuesta para el tipo de contenido ''application / json; charset = utf-8 ''.

Bucle de autorreferencia detectado para la propiedad ''pregunta'' con el tipo ''Modelos.Cuestión.de.Pregunta''.

¿Esto es porque la pregunta tiene respuestas y las respuestas tienen una referencia a la pregunta? Todos los lugares que he buscado sugieren una referencia al padre en el niño, así que no estoy seguro de qué hacer. ¿Puede alguien darme un consejo sobre esto?


¿Esto es porque la pregunta tiene respuestas y las respuestas tienen una referencia a la pregunta?

Sí. No puede ser serializado.

EDITAR: Vea la respuesta de Tallmaris y el comentario de OttO ya que es más simple y puede establecerse globalmente.

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

Vieja respuesta:

Proyecte la Question objeto EF en su propio intermediario o DataTransferObject. Este Dto se puede serializar con éxito.

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

Algo como:

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


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


Debido a la carga diferida estás recibiendo este error. Por lo tanto, mi sugerencia es eliminar la clave virtual de la propiedad. Si está trabajando con API, la carga lenta no es buena para el estado de su API.

No es necesario agregar una línea adicional en su archivo de configuración.

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


Descubrí que este error se debía a que generé un edmx (archivo XML que define un modelo conceptual) de una base de datos existente y tenía propiedades de navegación para las tablas padre e hijo. Eliminé todos los enlaces de navegación a los objetos principales, ya que solo quería navegar a niños, y el problema fue resuelto.


En ASP.NET Core, la solución es la siguiente:

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


Entidades db = nuevas Entidades ()

db.Configuration.ProxyCreationEnabled = false;

db.Configuration.LazyLoadingEnabled = false;


Para una nueva aplicación web Asp.Net usando .Net Framework 4.5:

Web Api: Goto App_Start -> WebApiConfig.cs:

Debería verse algo como esto:

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


Puede crear dinámicamente una nueva colección de elementos secundarios para solucionar este problema fácilmente.

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).Select(b=> new { b.QuestionId, b.Title Answers = b.Answers.Select(c=> new { c.AnswerId, c.Text, c.QuestionId })) .ToList(); return questions; }


ReferenceLoopHandling.Ignore no funcionó para mí. La única forma de evitarlo era eliminar mediante el código los enlaces al padre que no quería y conservar los que yo tenía.

parent.Child.Parent = null;


Si usa DNX / MVC 6 / ASP.NET vNext blah blah, incluso HttpConfiguration falta. Debe configurar formateadores utilizando los siguientes códigos en su archivo 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); }); }


Si usa OWIN, recuerde, ¡no más GlobalSettings para usted! Debe modificar esta misma configuración en un objeto HttpConfiguration que pasa a la función IAppBuilder UseWebApi (o en cualquier plataforma de servicio en la que se encuentre)

Se vería algo como esto.

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


También puedes probar esto en tu Application_Start() :

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

Debería solucionar tu problema sin pasar por muchos aros.

EDITAR: Según el comentario de OttO a continuación, use: ReferenceLoopHandling.Ignore lugar.

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


Usando esto:

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

no funcionó para mí En su lugar, creé una versión nueva y simplificada de mi clase de modelo solo para probar, y eso resultó bien. Este artículo aborda algunos de los problemas que tenía en mi modelo que funcionaban muy bien para EF, pero que no eran serializables:

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