Sto riscontrando un problema nel rendere alcuni dati serializzati correttamente dal mio controller API Web ASP.NET utilizzando Newtonsoft.Json.In che modo "Really" serializza oggetti di riferimento circolari con Newtonsoft.Json?
Ecco cosa I pensa sta succedendo - correggimi se ho torto. In determinate circostanze (in particolare quando non ci sono riferimenti circolari nei dati) tutto funziona come ci si aspetterebbe: un elenco di oggetti popolati viene serializzato e restituito. Se introduco dati che causano un riferimento circolare nel modello (descritto di seguito, e anche con PreserveReferencesHandling.Objects
impostato), solo gli elementi dell'elenco che portano al primo oggetto con un riferimento circolare vengono serializzati in un modo che il client può "lavorare con ". Gli "elementi che precedono" possono essere uno qualsiasi degli elementi nei dati se vengono ordinati diversamente prima di inviare le cose al serializzatore, ma almeno uno sarà serializzato in un modo in cui il client può "lavorare con". Gli oggetti vuoti finiscono per essere serializzati come riferimenti Newtonsoft ({$ref:X}
).
Per esempio, se ho un modello EF completo di proprietà di navigazione che assomiglia a questo:
Nel mio global.asax:
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
Ecco la domanda fondamentale I' facendo uso di Entity Framework (il caricamento lazy è disattivato quindi non ci sono classi proxy qui):
[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;
}
}
Finora tutto bene, data
è popolato.
Se non ci sono riferimenti circolari, la vita è grandiosa. Tuttavia, non appena ci sono 2 entità con lo stesso Source
o Place
, la serializzazione trasforma gli ultimi oggetti Balance
dell'elenco più in alto che sto tornando nei riferimenti Newtonsoft invece dei loro oggetti completi perché erano già serializzato nel Balances
proprietà dell'oggetto (s) Source
o Place
:
[{"$id":"1","BalanceID":4,"SourceID":2,"PlaceID":2 ...Omitted for clarity...},{"$ref":"4"}]
il problema di questo è che il cliente non sa cosa fare con {$ref:4}
anche se noi esseri umani capire che cosa sta succedendo. Nel mio caso, ciò significa che non posso utilizzare AngularJS a ng-repeat
sull'intero elenco di Saloni con questo JSON, perché non sono tutti veri oggetti Balance
con una proprietà Balance
da associare. Sono sicuro che ci sono tonnellate di altri casi d'uso che avrebbero lo stesso problema.
Non riesco a spegnere il json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects
perché molte altre cose si spezzerebbero (che è ben documentato in altre 100 domande qui e altrove).
C'è una soluzione migliore per questo oltre a passare attraverso le entità nel controller API Web e facendo
Balance.Source.Balances = null;
a tutte le proprietà di navigazione per rompere i riferimenti circolari? Perché anche quello non sembra giusto.