Loop de auto-referência JSON.Net detectado

111

Eu tenho um banco de dados mssql para meu site dentro de 4 tabelas.

Quando eu uso isso:

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

O código resulta no seguinte erro:

Newtonsoft.Json.JsonSerializationException: Loop de auto-referência detectado para a propriedade 'CyberUser' com o tipo 'DAL.CyberUser'. Caminho '[0] .EventRegistrations [0] .CyberUser.UserLogs [0]'.

PassionateDeveloper
fonte
2
possível duplicata de loop de auto-referência de erro JSON.NET detectada para o tipo
Chris Moschini
Você poderia marcar minha resposta como correta se for? @Kovu
Muhammad Omar ElShourbagy
Possível duplicata do loop de autorreferência da estrutura
Michael Freidgeim

Respostas:

212

Eu simplesmente tive o mesmo problema com as coleções Pai / Filho e encontrei aquele post que resolveu meu caso. Eu só queria mostrar a lista de itens da coleção pai e não precisava de nenhum dos dados filho, portanto usei o seguinte e funcionou bem:

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

Erro JSON.NET Loop de auto-referência detectado para o tipo

também se refere à página codeplex Json.NET em:

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

Documentação: configuração ReferenceLoopHandling

Muhammad Omar ElShourbagy
fonte
2
Dependendo do caso, você também pode usar PreserveReferencesHandling = PreserveReferencesHandling.Objects;conforme explicado aqui: solve-self-referencing-loop-issue-when-using-newtonsoft-json
Dimitri Troncquo
No WebAPI OData v4, descobri que alguns tipos de dados exigiam ReferenceLoopHandling.Ignore e PreserveReferencesHandling.Objects
Chris Schaller
1
Sings Allelluiah Muito obrigado, apenas uma votação positiva por 1 não é suficiente
JP Chapleau
42

A correção é ignorar as referências de loop e não serializá-las. Este comportamento é especificado em JsonSerializerSettings.

SolteiroJsonConvert com sobrecarga:

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

Se quiser que esse seja o comportamento padrão, adicione uma configuração global com o código Application_Start()em Global.asax.cs:

JsonConvert.DefaultSettings = () => new JsonSerializerSettings {
     Formatting = Newtonsoft.Json.Formatting.Indented,
     ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
};

Referência: https://github.com/JamesNK/Newtonsoft.Json/issues/78

bata
fonte
3
A serialização com isso leva muito tempo para mim
daniel
Isso não parece funcionar quando o objeto com loops circulares são POCOs do modelo NHibernate (nesse caso, a serialização recupera uma tonelada de lixo ou, às vezes, apenas atinge o tempo limite).
Fernando Gonzalez Sanchez
"IsSecuritySafeCritical": false, "IsSecurityTransparent": false, "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 "," Name ": null," HasDefaultValue ": true," DefaultValue ": null," RawDefaultValue ": null," MetadataToken ": 134217728," Attributes ": 0," Position ": - 1, "IsIn": falso, "IsLcid": falso ,. ... etc.
37

Se estiver usando ASP.NET Core MVC, adicione isso ao método ConfigureServices do seu arquivo startup.cs:

services.AddMvc()
    .AddJsonOptions(
        options => options.SerializerSettings.ReferenceLoopHandling =            
        Newtonsoft.Json.ReferenceLoopHandling.Ignore
    );
andreisrob
fonte
2
Confirmei que esta solução também funciona com WebAPI EntityFramework Core 2.0
cesar-moya
13

Isso pode te ajudar.

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
fonte
4
Essa é a melhor maneira de abordá-lo se você também estiver usando métodos assíncronos. Pode ser uma dor real, mas resolve muitos problemas que você teria de outra forma (incluindo este) e também pode ter muito mais desempenho, pois você só está perguntando o que vai usar.
Josh McKearin
Em seu xyz.edmx, abra o arquivo xyz.Context.vb que ficará oculto por padrão. Isso terá codePublic Sub New () Mybase.New ("name = EntityConName") End Sub code. Agora, antes de End Sub, adicione codeMe.Configuration.LazyLoadingEnabled = False Me.Configuration.ProxyCreationEnabled = False code Isso eliminará o erro 'Loop de auto-referência' em sua saída json do webapi.
Venkat de
Eu descobri que isso não funcionou para mim. Eu usei AsNoTracking () e ele consertou. Talvez ajudar alguém
scottsanpedro
@scottsanpedro seria melhor se pudéssemos ver seu código.
ddagsan
6

Você deve definir Preservando referências de objeto:

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

Em seguida, chame sua consulta var q = (from a in db.Events where a.Active select a).ToList();como

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

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

Cyrus
fonte
4

Adicione "[JsonIgnore]" à sua classe 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
fonte
3

Estou usando o Dot.Net Core 3.1 e fiz uma pesquisa por

"Newtonsoft.Json.JsonSerializationException: Loop de auto-referência detectado para a propriedade"

Estou adicionando isso a esta pergunta, pois será uma referência fácil. Você deve usar o seguinte no arquivo Startup.cs:

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

para asp.net core 3.1.3 isso funcionou para mim

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

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

user3824027
fonte
6
Embora este código possa responder à pergunta, fornecer contexto adicional sobre por que e / ou como este código responde à pergunta melhora seu valor a longo prazo.
Alex Riabov
1

Às vezes você tem loops porque sua classe de tipo tem referências a outras classes e essas classes têm referências à sua classe de tipo, portanto, você deve selecionar os parâmetros que você precisa exatamente na string 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
fonte