Wykryto pętlę odwołań do JSON.Net


111

Mam bazę danych mssql dla mojej witryny w 4 tabelach.

Kiedy używam tego:

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

Kod powoduje następujący błąd:

Newtonsoft.Json.JsonSerializationException: wykryto pętlę odwołującą się do siebie dla właściwości „CyberUser” o typie „DAL.CyberUser”. Ścieżka „[0] .EventRegistrations [0] .CyberUser.UserLogs [0]”.



Czy mógłbyś oznaczyć moją odpowiedź jako poprawną, jeśli tak jest? @Kovu
Muhammad Omar ElShourbagy

Odpowiedzi:


212

Właśnie miałem ten sam problem z kolekcjami Parent / Child i znalazłem ten post, który rozwiązał moją sprawę. Chciałem tylko pokazać Listę elementów kolekcji rodziców i nie potrzebowałem żadnych danych dziecka, dlatego użyłem następujących i działało dobrze:

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

Błąd JSON.NET Wykryto pętlę odwołującą się do siebie dla typu

odnosi się również do strony codeplex Json.NET pod adresem:

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

Dokumentacja: Ustawienie ReferenceLoopHandling


2
W zależności od przypadku możesz również użyć, PreserveReferencesHandling = PreserveReferencesHandling.Objects;jak wyjaśniono tutaj: rozwiąż problem z odwoływaniem się do siebie w pętli podczas używania-newtonsoft-json
Dimitri Troncquo

W WebAPI OData v4 stwierdziłem, że niektóre typy danych wymagały zarówno ReferenceLoopHandling.Ignore, jak i PreserveReferencesHandling.Objects
Chris Schaller

1
Śpiewa Allelluiah Dzięki wielkie, tylko pozytywne głosowanie o 1 nie wystarczy
JP Chapleau

42

Rozwiązaniem jest ignorowanie odwołań do pętli i nie ich serializacja. To zachowanie jest określone w JsonSerializerSettings.

PojedynczyJsonConvert z przeciążeniem:

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

Jeśli chcesz, aby było to zachowanie domyślne, dodaj ustawienie globalne z kodem Application_Start()w Global.asax.cs:

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

Źródła: https://github.com/JamesNK/Newtonsoft.Json/issues/78


3
Serializacja z tym zajmuje mi bardzo dużo czasu
daniel

Wydaje się, że to nie działa, gdy obiekt z pętlami cyklicznymi jest POCO modelu NHibernate (w tym przypadku serializacja pobiera tonę śmieci lub czasami po prostu przekracza limit czasu).
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”: false, „IsLcid”: false ,. ... itd.

37

Jeśli używasz ASP.NET Core MVC, dodaj to do metody ConfigureServices pliku startup.cs: If using ASP.NET Core MVC, add this to the ConfigureServices method of your startup.cs file:

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

2
Potwierdziłem, że to rozwiązanie działa również z WebAPI EntityFramework Core 2.0
cesar-moya

13

To może ci pomóc.

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


4
Jest to najlepszy sposób podejścia do tego problemu, jeśli używasz również metod asynchronicznych. Może to być prawdziwy ból, ale rozwiązuje wiele problemów, które miałbyś w przeciwnym razie (w tym ten), a także może być znacznie bardziej wydajne, ponieważ pytasz tylko o to, czego użyjesz.
Josh McKearin

W swoim xyz.edmx otwórz plik xyz.Context.vb, który będzie domyślnie ukryty. To będzie mieć codePublic Sub New () Mybase.New ("name = EntityConName") End Sub code. Teraz przed End Sub dodaj codeMe.Configuration.LazyLoadingEnabled = False Me.Configuration.ProxyCreationEnabled = False code To usunie błąd „Pętla odwołująca się do siebie” w danych wyjściowych json z webapi.
Venkat

Okazało się, że to nie działa dla mnie. Użyłem AsNoTracking () i to naprawiłem. Może pomóc komuś innemu
scottsanpedro

@scottsanpedro byłoby lepiej, gdybyśmy mogli zobaczyć twój kod.
ddagsan

6

Musisz ustawić Zachowywanie odwołań do obiektów:

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

Następnie wywołać zapytanie var q = (from a in db.Events where a.Active select a).ToList();jak

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

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


4

Dodaj „[JsonIgnore]” do swojej klasy modelu

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

3

Używam Dot.Net Core 3.1 i wyszukałem

„Newtonsoft.Json.JsonSerializationException: wykryto pętlę odwołań do siebie dla właściwości”

Dodam to do tego pytania, ponieważ będzie to łatwe odniesienie. W pliku Startup.cs należy użyć następujących elementów:

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

2

dla asp.net core 3.1.3 to zadziałało

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

1

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


6
Chociaż ten kod może odpowiedzieć na pytanie, zapewnia dodatkowy kontekst dotyczący tego, dlaczego i / lub jak ten kod odpowiada, poprawia jego długoterminową wartość.
Alex Riabov,

1

Czasami masz pętle, ponieważ twoja klasa typu ma odwołania do innych klas, a klasy mają odniesienia do twojej klasy typu, dlatego musisz wybrać parametry, których potrzebujesz, dokładnie w ciągu json, jak w tym kodzie.

List<ROficina> oficinas = new List<ROficina>();
oficinas = /*list content*/;
var x = JsonConvert.SerializeObject(oficinas.Select(o => new
            {
                o.IdOficina,
                o.Nombre
            }));
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.