Ich habe ein Problem beim Abrufen einiger ordnungsgemäß serialisierter Daten von meinem ASP.NET-Web-API-Controller mit Newtonsoft.Json.Wie "really" Sie zirkuläre Referenzierungsobjekte mit Newtonsoft.Json serialisieren?
Hier ist, was ich denke geht - bitte korrigieren Sie mich, wenn ich falsch liege. Unter bestimmten Umständen (insbesondere wenn keine Zirkelverweise in den Daten vorhanden sind) funktioniert alles so, wie Sie es erwarten würden - eine Liste der aufgefüllten Objekte wird serialisiert und zurückgegeben. Wenn ich Daten einführe, die einen Zirkelverweis im Modell verursachen (unten beschrieben und sogar mit PreserveReferencesHandling.Objects
), werden nur die Elemente der Liste, die zum ersten Objekt mit einem Zirkelverweis führen, so serialisiert, dass der Klient "damit arbeiten kann ". Die "Elemente, die zu" führen, können irgendwelche der Elemente in den Daten sein, wenn sie anders angeordnet sind, bevor sie an den Serialisierer gesendet werden, aber mindestens einer wird auf eine Weise serialisiert, mit der der Client "arbeiten kann". Die leeren Objekte werden als Newtonsoft-Referenzen serialisiert ({$ref:X}
).
Zum Beispiel, wenn ich ein EF-Modell mit Navigationseigenschaften komplett haben, die wie folgt aussieht:
In meinem global.asax:
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
Hier ist die grundlegende Abfrage I‘ m mit Entity Framework (lazy-loading ist aus, so dass hier keine Proxy-Klassen vorhanden sind):
[HttpGet]
[Route("starting")]
public IEnumerable<Balance> GetStartingBalances()
{
using (MyContext db = new MyContext())
{
var data = db.Balances
.Include(x => x.Source)
.Include(x => x.Place)
.ToList()
return data;
}
}
So weit so gut, data
ist bestückt.
Wenn es keine Zirkelverweise gibt, ist das Leben großartig. Sobald jedoch 2 Balance
Entities mit dem gleichen Source
oder Place
vorliegen, werden durch die Serialisierung die späteren Objekte der obersten Liste, die ich in Newtonsoft-Referenzen zurückgebe, anstelle ihrer vollwertigen Objekte in die späteren Objekte umgewandelt, weil sie bereits vorhanden waren in der Balances
Eigenschaft des Source
oder Place
Objekts serialisiert (e):
[{"$id":"1","BalanceID":4,"SourceID":2,"PlaceID":2 ...Omitted for clarity...},{"$ref":"4"}]
das Problem dabei ist, dass der Kunde nicht weiß, was mit {$ref:4}
zu tun, auch wenn wir Menschen verstehen, was los ist. In meinem Fall bedeutet dies, dass ich AngularJS nicht zu ng-repeat
über meine gesamte Liste von Salden mit diesem JSON verwenden kann, da sie nicht alle Balance
Objekte mit einer Balance
-Eigenschaft sind, die gebunden werden soll. Ich bin mir sicher, dass es viele andere Anwendungsfälle gibt, die das gleiche Problem haben.
Ich kann die json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects
nicht ausschalten, weil viele andere Dinge brechen würden (was in 100 anderen Fragen hier und anderswo gut dokumentiert ist).
Gibt es eine bessere Abhilfe für diesen außer in dem Web-API-Controller durch die Einheiten gehen und
Balance.Source.Balances = null;
auf alle Navigationseigenschaften machen die zirkulären Verweise zu brechen? Weil das auch nicht richtig scheint.