Se detectó un bucle de auto referencia de error JSON.NET para el tipo
serialization (18)
En .NET Core 1.0, puede establecer esto como una configuración global en su archivo Startup.cs:
using System.Buffers;
using Microsoft.AspNetCore.Mvc.Formatters;
using Newtonsoft.Json;
// beginning of Startup class
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.OutputFormatters.Clear();
options.OutputFormatters.Add(new JsonOutputFormatter(new JsonSerializerSettings(){
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
}, ArrayPool<char>.Shared));
});
}
Intenté serializar la clase POCO que se generó automáticamente desde el modelo de datos de entidad .edmx y cuando lo usé
JsonConvert.SerializeObject
Tuve el siguiente error:
Se ha producido un error en el bucle de autoreferencia para el tipo System.data.entity.
¿Cómo resuelvo este problema?
Equipo:
Esto funciona con ASP.NET Core; El desafío a lo anterior es cómo ''configura la configuración para ignorar''. Dependiendo de cómo configure su aplicación, puede ser bastante desafiante. Esto es lo que funcionó para mí.
Esto se puede colocar en su sección pública de servicios de configuración (servicios IServiceCollection).
services.AddMvc().AddJsonOptions(opt =>
{
opt.SerializerSettings.ReferenceLoopHandling =
Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
Esa fue la mejor solución https://code.msdn.microsoft.com/Loop-Reference-handling-in-caaffaf7
Arreglo 1: ignorando la referencia circular globalmente
(He elegido / probado este, como muchos otros)
El serializador json.net tiene una opción para ignorar referencias circulares. Coloque el siguiente código en el archivo WebApiConfig.cs
:
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling
= Newtonsoft.Json.ReferenceLoopHandling.Ignore;
La solución simple hará que el serializador ignore la referencia que causará un bucle. Sin embargo, tiene limitaciones:
Los datos pierden la información de referencia del bucle. La solución solo se aplica a JSON.net. El nivel de referencias no se puede controlar si hay una cadena de referencia profunda.
Si desea usar esta solución en un proyecto ASP.NET no api, puede agregar la línea anterior a Global.asax.cs
, pero primero agregue:
var config = GlobalConfiguration.Configuration;
Si desea usar esto en el proyecto .Net Core , puede cambiar Startup.cs
como:
var mvc = services.AddMvc(options =>
{
...
})
.AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
Arreglo 2: Preservando la referencia circular globalmente
Esta segunda solución es similar a la primera. Solo cambia el código a:
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling
= Newtonsoft.Json.ReferenceLoopHandling.Serialize;
config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling
= Newtonsoft.Json.PreserveReferencesHandling.Objects;
La forma de los datos se cambiará después de aplicar esta configuración.
[
{
"$id":"1",
"Category":{
"$id":"2",
"Products":[
{
"$id":"3",
"Category":{
"$ref":"2"
},
"Id":2,
"Name":"Yogurt"
},
{
"$ref":"1"
}
],
"Id":1,
"Name":"Diary"
},
"Id":1,
"Name":"Whole Milk"
},
{
"$ref":"3"
}
]
$ Id y $ ref mantienen todas las referencias y hacen que el nivel del gráfico del objeto sea plano, pero el código del cliente necesita saber el cambio de forma para consumir los datos y solo se aplica al serializador JSON.NET también.
Solución 3: ignorar y preservar los atributos de referencia
Esta solución es decorar atributos en la clase de modelo para controlar el comportamiento de serialización en el nivel de modelo o propiedad. Para ignorar la propiedad:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
[JsonIgnore]
[IgnoreDataMember]
public virtual ICollection<Product> Products { get; set; }
}
JsonIgnore es para JSON.NET e IgnoreDataMember es para XmlDCSerializer. Para preservar la referencia:
// Fix 3
[JsonObject(IsReference = true)]
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
// Fix 3
//[JsonIgnore]
//[IgnoreDataMember]
public virtual ICollection<Product> Products { get; set; }
}
[DataContract(IsReference = true)]
public class Product
{
[Key]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public virtual Category Category { get; set; }
}
JsonObject(IsReference = true)]
es para JSON.NET y [DataContract(IsReference = true)]
es para XmlDCSerializer. Tenga en cuenta que: después de aplicar DataContract
en la clase, debe agregar DataMember
a las propiedades que desea serializar.
Los atributos se pueden aplicar tanto en el serializador json como en el xml y ofrecen más controles en la clase del modelo.
La forma más sencilla de hacer esto es instalar Json.NET desde nuget y agregar el atributo [JsonIgnore]
a la propiedad virtual en la clase, por ejemplo:
public string Name { get; set; }
public string Description { get; set; }
public Nullable<int> Project_ID { get; set; }
[JsonIgnore]
public virtual Project Project { get; set; }
Aunque en estos días, creo un modelo con solo las propiedades que quiero que se transfieran para que sea más liviano, no incluya colecciones no deseadas y no pierdo mis cambios cuando reconstruyo los archivos generados ...
La gente ya ha hablado sobre [JsonIgnore] para agregarse a la propiedad virtual en la clase, por ejemplo:
[JsonIgnore]
public virtual Project Project { get; set; }
También compartiré otra opción, [JsonProperty (NullValueHandling = NullValueHandling.Ignore)] que omite la propiedad de la serialización solo si es nula.
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public virtual Project Project { get; set; }
La solución es ignorar las referencias de bucle y no serializarlas. Este comportamiento se especifica en JsonSerializerSettings
.
Single JsonConvert
con una sobrecarga:
JsonConvert.SerializeObject(YourObject, Formatting.Indented,
new JsonSerializerSettings() {
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
}
);
Configuración global con código en Application_Start()
en Global.asax.cs:
JsonConvert.DefaultSettings = () => new JsonSerializerSettings {
Formatting = Newtonsoft.Json.Formatting.Indented,
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
};
Referencia: https://github.com/JamesNK/Newtonsoft.Json/issues/78
Me gustó la solución que lo hace desde Application_Start()
como en la respuesta here
Aparentemente no pude acceder a los objetos json en JavaScript usando la configuración dentro de mi función como en la respuesta de DalSoft, ya que el objeto devuelto tenía "/ n / r" en toda la (clave, val) del objeto.
De todos modos, cualquier cosa que funcione es excelente (porque los diferentes enfoques funcionan en diferentes escenarios según los comentarios y las preguntas), aunque una forma estándar de hacerlo sería preferible con una buena documentación que respalde el enfoque.
Para ignorar las referencias de bucle y no serializarlas globalmente en MVC 6, use lo siguiente en startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().Configure<MvcOptions>(options =>
{
options.OutputFormatters.RemoveTypesOf<JsonOutputFormatter>();
var jsonOutputFormatter = new JsonOutputFormatter();
jsonOutputFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
options.OutputFormatters.Insert(0, jsonOutputFormatter);
});
}
Para mí tenía que ir por un camino diferente. En lugar de intentar arreglar el serializador JSON.Net, tuve que ir tras la carga perezosa en mi contexto de datos.
Acabo de agregar esto a mi repositorio base:
context.Configuration.ProxyCreationEnabled = false;
El objeto "contexto" es un parámetro de constructor que uso en mi repositorio base porque uso la inyección de dependencia. Podría cambiar la propiedad ProxyCreationEnabled en cualquier lugar donde cree una instancia de su datacontext.
http://techie-tid-bits.blogspot.com/2015/09/jsonnet-serializer-and-error-self.html
Para no hacer un bucle esto funcionó para mí.
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
Lo he resuelto todo aquí: la serialización de los niños de Entity Framework con .Net Core 2 WebAPI https://gist.github.com/Kaidanov/f9ad0d79238494432f32b8407942c606
Apreciaremos cualquier comentario. Tal vez alguien pueda usarlo alguna vez.
Para serializar usin NEWTONSOFTJSON cuando tenga un problema de bucle, en mi caso no necesitaba modificar global.asax ni apiconfig. Solo uso JsonSerializesSettings ignorando el manejo de bucles.
JsonSerializerSettings jss = new JsonSerializerSettings();
jss.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
var lst = db.shCards.Where(m => m.CardID == id).ToList();
string json = JsonConvert.SerializeObject(lst, jss);
Podemos agregar estas dos líneas en el constructor de clases DbContext para deshabilitar el bucle de referencia automática, como
public TestContext()
: base("name=TestContext")
{
this.Configuration.LazyLoadingEnabled = false;
this.Configuration.ProxyCreationEnabled = false;
}
Si está utilizando .NET Core 2.0, actualice la sección de ConfigureServices en Startup.cs
https://docs.microsoft.com/en-us/ef/core/querying/related-data#related-data-and-serialization
public void ConfigureServices(IServiceCollection services)
{
...
services.AddMvc()
.AddJsonOptions(
options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);
...
}
Simplemente coloque Configuration.ProxyCreationEnabled = false;
dentro del archivo de contexto; Esto solucionará el problema.
public demEntities()
: base("name=demEntities")
{
Configuration.ProxyCreationEnabled = false;
}
También puede aplicar un atributo a la propiedad. El [JsonProperty( ReferenceLoopHandling = ... )]
es adecuado para esto.
Por ejemplo:
/// <summary>
/// Represents the exception information of an event
/// </summary>
public class ExceptionInfo
{
// ...code omitted for brevity...
/// <summary>
/// An inner (nested) error.
/// </summary>
[JsonProperty( ReferenceLoopHandling = ReferenceLoopHandling.Ignore, IsReference = true )]
public ExceptionInfo Inner { get; set; }
// ...code omitted for brevity...
}
Espero que ayude, Jaans
Tuve esta excepción y mi solución de trabajo es Fácil y Simple,
Ignore la propiedad referenciada agregándole el atributo JsonIgnore:
[JsonIgnore]
public MyClass currentClass { get; set; }
Reinicie la propiedad cuando lo deserialice:
Source = JsonConvert.DeserializeObject<MyObject>(JsonTxt);
foreach (var item in Source)
{
Source.MyClass = item;
}
utilizando Newtonsoft.Json;
Use esto en la clase WebApiConfig.cs
:
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
Use JsonSerializerSettings
-
ReferenceLoopHandling.Error
(predeterminado) producirá un error si se encuentra un bucle de referencia. Es por esto que obtienes una excepción. -
ReferenceLoopHandling.Serialize
es útil si los objetos están anidados pero no de forma indefinida. -
ReferenceLoopHandling.Ignore
no serializará un objeto si es un objeto secundario de sí mismo.
Ejemplo:
JsonConvert.SerializeObject(YourPOCOHere, Formatting.Indented,
new JsonSerializerSettings {
ReferenceLoopHandling = ReferenceLoopHandling.Serialize
});
Si tiene que serializar un objeto que está anidado indefinidamente, puede usar PreserveObjectReferences para evitar una excepción Exception.
Ejemplo:
JsonConvert.SerializeObject(YourPOCOHere, Formatting.Indented,
new JsonSerializerSettings {
PreserveReferencesHandling = PreserveReferencesHandling.Objects
});
Elija lo que tenga sentido para el objeto que está serializando.
Referencia http://james.newtonking.com/json/help/