Se detectó un bucle de autorreferencia JSON.Net

111

Tengo una base de datos mssql para mi sitio web dentro de 4 tablas.

Cuando uso esto:

public static string GetAllEventsForJSON()
{
    using (CyberDBDataContext db = new CyberDBDataContext())
    {
        return JsonConvert.SerializeObject((from a in db.Events where a.Active select a).ToList(), new JavaScriptDateTimeConverter());
    }
}

El código da como resultado el siguiente error:

Newtonsoft.Json.JsonSerializationException: bucle de autorreferencia detectado para la propiedad 'CyberUser' con el tipo 'DAL.CyberUser'. Ruta '[0] .EventRegistrations [0] .CyberUser.UserLogs [0]'.

Desarrollador apasionado
fuente
¿Podría marcar mi respuesta como correcta si lo es? @Kovu
Muhammad Omar ElShourbagy
Se detectó un
Michael Freidgeim

Respuestas:

211

Acabo de tener el mismo problema con las colecciones de padres / hijos y encontré esa publicación que resolvió mi caso. Solo quería mostrar la Lista de elementos de la colección principal y no necesitaba ninguno de los datos secundarios, por lo tanto, usé lo siguiente y funcionó bien:

JsonConvert.SerializeObject(ResultGroups, Formatting.None,
                        new JsonSerializerSettings()
                        { 
                            ReferenceLoopHandling = ReferenceLoopHandling.Ignore
                        });

Error de JSON.NET Se detectó un bucle de autorreferencia para el tipo

también hace referencia a la página del codeplex Json.NET en:

http://json.codeplex.com/discussions/272371

Documentación: Configuración ReferenceLoopHandling

Muhammad Omar ElShourbagy
fuente
2
Dependiendo del caso, también podría usarlo PreserveReferencesHandling = PreserveReferencesHandling.Objects;como se explica aquí: resolver-problema-de-bucle-de-referencia-automática-al-usar-newtonsoft-json
Dimitri Troncquo
En WebAPI OData v4, encontré que algunos tipos de datos requerían tanto ReferenceLoopHandling.Ignore como PreserveReferencesHandling.Objects
Chris Schaller
1
Sings Allelluiah Muchas gracias, solo la votación a favor de 1 no es suficiente
JP Chapleau
42

La solución es ignorar las referencias de bucle y no serializarlas. Este comportamiento se especifica en JsonSerializerSettings.

SolteroJsonConvert con sobrecarga:

JsonConvert.SerializeObject((from a in db.Events where a.Active select a).ToList(), Formatting.Indented,
    new JsonSerializerSettings() {
        ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
    }
);

Si desea que este sea el comportamiento predeterminado, agregue una Configuración global con código 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

smockle
fuente
3
La serialización con esto me lleva mucho tiempo
Daniel
Esto no parece funcionar cuando el objeto con bucles circulares son POCO del modelo NHibernate (en ese caso, la serialización recupera una tonelada de basura o, a veces, simplemente agota el tiempo de espera).
Fernando Gonzalez Sanchez
"IsSecuritySafeCritical": falso, "IsSecurityTransparent": falso, "MethodHandle": {"Value": {"value": 140716810003120}}, "Attributes": 150, "CallingConvention": 1, "ReturnType": "System.Void , System.Private.CoreLib, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = 7cec85d7bea7798e "," ReturnTypeCustomAttributes ": {" ParameterType ":" System.Void, System.Private.CoreLib, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = 7cec85d7bea7798e "," Nombre ": nulo," HasDefaultValue ": verdadero," DefaultValue ": nulo," RawDefaultValue ": nulo," MetadataToken ": 134217728," Atributos ": 0," Posición ": - 1, "IsIn": falso, "IsLcid": falso ,. ... etc.
37

Si usa ASP.NET Core MVC, agregue esto al método ConfigureServices de su archivo startup.cs:

services.AddMvc()
    .AddJsonOptions(
        options => options.SerializerSettings.ReferenceLoopHandling =            
        Newtonsoft.Json.ReferenceLoopHandling.Ignore
    );
andreisrob
fuente
2
Confirmé que esta solución también funciona con WebAPI EntityFramework Core 2.0
cesar-moya
13

Esto puede ayudarte.

public MyContext() : base("name=MyContext") 
{ 
    Database.SetInitializer(new MyContextDataInitializer()); 
    this.Configuration.LazyLoadingEnabled = false; 
    this.Configuration.ProxyCreationEnabled = false; 
} 

http://code.msdn.microsoft.com/Loop-Reference-handling-in-caaffaf7

ddagsan
fuente
4
Esta es la mejor manera de abordarlo si también está utilizando métodos asíncronos. Puede ser un verdadero dolor de cabeza, pero resuelve muchos problemas que tendrías de otra manera (incluido este) y también puede ser mucho más eficaz ya que solo estás preguntando qué usarás.
Josh McKearin
En su xyz.edmx, abra el archivo xyz.Context.vb que estará oculto por defecto. Esto tendrá codePublic Sub New () Mybase.New ("nombre = EntityConName") End Sub code. Ahora, antes de End Sub, agregue codeMe.Configuration.LazyLoadingEnabled = False Me.Configuration.ProxyCreationEnabled = False code Eso eliminará el error de 'bucle de autorreferencia' en su salida json de webapi.
Venkat
Descubrí que esto no funcionó para mí. Usé AsNoTracking () y lo arregló. Quizás ayudar a alguien más
scottsanpedro
@scottsanpedro, sería mejor si pudiéramos ver su código.
Ddagsan
6

Debe establecer Conservar referencias a objetos:

var jsonSerializerSettings = new JsonSerializerSettings
{
    PreserveReferencesHandling = PreserveReferencesHandling.Objects
};

Luego llame a su consulta var q = (from a in db.Events where a.Active select a).ToList();como

string jsonStr = Newtonsoft.Json.JsonConvert.SerializeObject(q, jsonSerializerSettings);

Ver: https://www.newtonsoft.com/json/help/html/PreserveObjectReferences.htm

Ciro
fuente
4

Agrega "[JsonIgnore]" a tu clase de modelo

{
  public Customer()
  {
    Orders = new Collection<Order>();
  }

public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }

[JsonIgnore]
public ICollection<Order> Orders { get; set; }
}
Samet Sunman
fuente
3

Estoy usando Dot.Net Core 3.1 e hice una búsqueda de

"Newtonsoft.Json.JsonSerializationException: bucle de autorreferencia detectado para la propiedad"

Estoy agregando esto a esta pregunta, ya que será una referencia fácil. Debe utilizar lo siguiente en el archivo Startup.cs:

 services.AddControllers()
                .AddNewtonsoftJson(options =>
                {
                    // Use the default property (Pascal) casing
                    options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                    options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                });
krishnan2784
fuente
2

para asp.net core 3.1.3 esto funcionó para mí

services.AddControllers().AddNewtonsoftJson(opt=>{
            opt.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        });
Karim Tingdis
fuente
1

JsonConvert.SerializeObject(ObjectName, new JsonSerializerSettings(){ PreserveReferencesHandling = PreserveReferencesHandling.Objects, Formatting = Formatting.Indented });

user3824027
fuente
6
Si bien este código puede responder a la pregunta, proporcionar un contexto adicional sobre por qué y / o cómo este código responde a la pregunta mejora su valor a largo plazo.
Alex Riabov
1

A veces tiene bucles porque su clase de tipo tiene referencias a otras clases y esas clases tienen referencias a su clase de tipo, por lo tanto, debe seleccionar los parámetros que necesita exactamente en la cadena json, como este código.

List<ROficina> oficinas = new List<ROficina>();
oficinas = /*list content*/;
var x = JsonConvert.SerializeObject(oficinas.Select(o => new
            {
                o.IdOficina,
                o.Nombre
            }));
Angélica Tovar
fuente