627 Stimmen

JSON.NET-Fehler Selbstreferenzierende Schleife für Typ entdeckt

Ich habe versucht, die POCO-Klasse zu serialisieren, die automatisch aus dem Entity Data Model .edmx generiert wurde, und als ich

JsonConvert.SerializeObject 

Ich habe den folgenden Fehler erhalten:

Fehler Selbstreferenzierungsschleife für Typ System.data.entity entdeckt.

Wie kann ich dieses Problem lösen?

587voto

Bishoy Hanna Punkte 11268

Das war die beste Lösung https://learn.microsoft.com/en-us/archive/blogs/hongyes/loop-reference-handling-in-web-api

Fix 1: Globales Ignorieren der Kreisreferenz

(Ich habe diese Option gewählt/ausprobiert, wie viele andere auch)

Der json.net-Serializer verfügt über eine Option zum Ignorieren zirkulärer Referenzen. Fügen Sie den folgenden Code in WebApiConfig.cs Datei:

 config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling 
= Newtonsoft.Json.ReferenceLoopHandling.Ignore; 

Die einfache Lösung führt dazu, dass der Serialisierer den Verweis ignoriert, was zu einer Schleife führt. Sie hat jedoch Einschränkungen:

  • Die Daten verlieren die Schleifenreferenzinformationen
  • Die Korrektur gilt nur für JSON.net
  • Die Ebene der Referenzen kann nicht kontrolliert werden, wenn es eine tiefe Referenzkette gibt

Wenn Sie diesen Fix in einem Nicht-API-ASP.NET-Projekt verwenden möchten, können Sie die obige Zeile zu Global.asax.cs , aber zuerst hinzufügen:

var config = GlobalConfiguration.Configuration;

Wenn Sie dies in .Net-Kern Projekt, können Sie die Startup.cs als:

  var mvc = services.AddMvc(options =>
        {
           ...
        })
        .AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);

Fix 2: Globale Beibehaltung der Kreisreferenz

Diese zweite Korrektur ist ähnlich wie die erste. Ändern Sie einfach den Code in:

config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling 
     = Newtonsoft.Json.ReferenceLoopHandling.Serialize;     
config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling 
     = Newtonsoft.Json.PreserveReferencesHandling.Objects;

Die Datenform wird nach Anwendung dieser Einstellung geändert.

[
   {
      "$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"
   }
]

Die $id und $ref hält die alle Verweise und macht das Objekt Graphen Ebene flach, aber der Client-Code muss wissen, die Form zu ändern, um die Daten zu konsumieren und es gilt nur für JSON.NET serializer als gut.

Fix 3: Referenzattribute ignorieren und beibehalten

Dieser Fix schmückt Attribute der Modellklasse, um das Serialisierungsverhalten auf Modell- oder Eigenschaftsebene zu steuern. Um die Eigenschaft zu ignorieren:

 public class Category 
    { 
        public int Id { get; set; } 
        public string Name { get; set; } 

        [JsonIgnore] 
        [IgnoreDataMember] 
        public virtual ICollection<Product> Products { get; set; } 
    } 

JsonIgnore ist für JSON.NET und IgnoreDataMember ist für XmlDCSerializer. Um die Referenz zu erhalten:

 // 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)] ist für JSON.NET und [DataContract(IsReference = true)] ist für XmlDCSerializer. Beachten Sie, dass: nach der Anwendung DataContract auf Klasse, müssen Sie hinzufügen DataMember auf Eigenschaften, die Sie serialisieren möchten.

Die Attribute können sowohl auf json als auch auf xml serializer angewendet werden und bieten mehr Kontrolle über die Modellklasse.

566voto

DalSoft Punkte 9849

JsonSerializerSettings verwenden

  • ReferenceLoopHandling.Error (Standard) führt zu einem Fehler, wenn eine Referenzschleife auftritt. Aus diesem Grund wird eine Ausnahme gemacht.
  • ReferenceLoopHandling.Serialize ist nützlich, wenn Objekte verschachtelt sind, aber nicht unbegrenzt.
  • ReferenceLoopHandling.Ignore serialisiert ein Objekt nicht, wenn es ein untergeordnetes Objekt von sich selbst ist.

Exemple :

JsonConvert.SerializeObject(YourPOCOHere, Formatting.Indented, 
new JsonSerializerSettings 
{ 
        ReferenceLoopHandling = ReferenceLoopHandling.Serialize
});

Wenn Sie ein Objekt serialisieren müssen, das auf unbestimmte Zeit verschachtelt ist, können Sie PreserveObjectReferences um eine StackOverflowException zu vermeiden.

Exemple :

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

Wählen Sie aus, was für das Objekt, das Sie serialisieren, sinnvoll ist.

Referenz http://james.newtonking.com/json/help/

85voto

smockle Punkte 2072

Die Lösung besteht darin, Schleifenverweise zu ignorieren und sie nicht zu serialisieren. Dieses Verhalten ist festgelegt in JsonSerializerSettings .

Einzeln JsonConvert mit einer Überlast:

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

Globale Einstellung mit Code in Application_Start() in Global.asax.cs:

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

Referenz: https://github.com/JamesNK/Newtonsoft.Json/issues/78

52voto

Sam Jones Punkte 4179

Der einfachste Weg, dies zu tun, ist die Installation von Json.NET aus Nuget und fügen Sie die [JsonIgnore] Attribut an die virtuelle Eigenschaft in der Klasse an:

    public string Name { get; set; }
    public string Description { get; set; }
    public Nullable<int> Project_ID { get; set; }

    [JsonIgnore]
    public virtual Project Project { get; set; }

Heutzutage erstelle ich jedoch ein Modell, das nur die Eigenschaften enthält, die ich weitergeben möchte, damit es leichter ist, keine unerwünschten Sammlungen enthält und ich meine Änderungen nicht verliere, wenn ich die generierten Dateien neu erstelle...

21voto

Caleb Punkte 2127

In .NET Core 1.0 können Sie dies als globale Einstellung in Ihrer Startup.cs-Datei festlegen:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X