È stato rilevato un riferimento circolare durante la serializzazione di un object di tipo “SubSonic.Schema .DatabaseColumn”.

Sto provando a fare un semplice ritorno JSON ma sto riscontrando dei problemi che ho di seguito.

public JsonResult GetEventData() { var data = Event.Find(x => x.ID != 0); return Json(data); } 

Ottengo un HTTP 500 con l’eccezione come mostrato nel titolo di questa domanda. Ho anche provato

 var data = Event.All().ToList() 

Questo ha dato lo stesso problema.

È un bug o la mia implementazione?

Sembra che ci siano riferimenti circolari nella gerarchia dell’object che non è supportata dal serializzatore JSON. Hai bisogno di tutte le colonne? Puoi vedere solo le proprietà che ti servono nella vista:

 return Json(new { PropertyINeed1 = data.PropertyINeed1, PropertyINeed2 = data.PropertyINeed2 }); 

Ciò renderà il tuo object JSON più leggero e più facile da capire. Se hai molte proprietà, AutoMapper potrebbe essere usato per mappare automaticamente tra oggetti DTO e oggetti View.

Ho avuto lo stesso problema e ho risolto using Newtonsoft.Json;

 var list = JsonConvert.SerializeObject(model, Formatting.None, new JsonSerializerSettings() { ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore }); return Content(list, "application/json"); 

Questo in realtà accade perché gli oggetti complessi sono ciò che rende fallito l’object json risultante. E fallisce perché quando l’object è mappato mappa i bambini, che mappano i loro genitori, facendo in modo che si verifichi un riferimento circolare. Json avrebbe impiegato un tempo infinito per serializzarlo, quindi impedisce il problema con l’eccezione.

Anche il mapping di Entity Framework produce lo stesso comportamento e la soluzione è di eliminare tutte le proprietà indesiderate.

Semplicemente spiegando la risposta finale, l’intero codice sarebbe:

 public JsonResult getJson() { DataContext db = new DataContext (); return this.Json( new { Result = (from obj in db.Things select new {Id = obj.Id, Name = obj.Name}) } , JsonRequestBehavior.AllowGet ); } 

Potrebbe anche essere il seguente nel caso in cui non si vogliano gli oggetti all’interno di una proprietà Result :

 public JsonResult getJson() { DataContext db = new DataContext (); return this.Json( (from obj in db.Things select new {Id = obj.Id, Name = obj.Name}) , JsonRequestBehavior.AllowGet ); } 

Per riassumere, ci sono 3 soluzioni a questo:

  private DBEntities db = new DBEntities();//dbcontext //Solution 1: turn off ProxyCreation for the DBContext and restore it in the end public ActionResult Index() { bool proxyCreation = db.Configuration.ProxyCreationEnabled; try { //set ProxyCreation to false db.Configuration.ProxyCreationEnabled = false; var data = db.Products.ToList(); return Json(data, JsonRequestBehavior.AllowGet); } catch (Exception ex) { Response.StatusCode = (int)HttpStatusCode.BadRequest; return Json(ex.Message); } finally { //restore ProxyCreation to its original state db.Configuration.ProxyCreationEnabled = proxyCreation; } } //Solution 2: Using JsonConvert by Setting ReferenceLoopHandling to ignore on the serializer settings. //using using Newtonsoft.Json; public ActionResult Index() { try { var data = db.Products.ToList(); JsonSerializerSettings jss = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }; var result = JsonConvert.SerializeObject(data, Formatting.Indented, jss); return Json(result, JsonRequestBehavior.AllowGet); } catch (Exception ex) { Response.StatusCode = (int)HttpStatusCode.BadRequest; return Json(ex.Message); } } //Solution 3: return a new dynamic object which includes only the needed properties. public ActionResult Index() { try { var data = db.Products.Select(p => new { Product_ID = p.Product_ID, Product_Name = p.Product_Name, Product_Price = p.Product_Price }).ToList(); return Json(data, JsonRequestBehavior.AllowGet); } catch (Exception ex) { Response.StatusCode = (int)HttpStatusCode.BadRequest; return Json(ex.Message); } } 

JSON, come xml e vari altri formati, è un formato di serializzazione ad albero. Non ti amerà se hai riferimenti circolari nei tuoi oggetti, come “l’albero” sarebbe:

 root B => child A => parent B => child A => parent B => ... 

Esistono spesso modi per distriggersre la navigazione lungo un determinato percorso; ad esempio, con XmlSerializer puoi contrassegnare la proprietà parent come XmlIgnore . Non so se questo è ansible con il serializzatore json in questione, né se DatabaseColumn ha marcatori adatti ( molto improbabile, in quanto avrebbe bisogno di fare riferimento a tutte le API di serializzazione)

È dovuto al nuovo modello DbContext T4 utilizzato per generare le quadro EntityFramework. Per essere in grado di eseguire il rilevamento delle modifiche, questo modello utilizza il modello Proxy, avvolgendo con essi i tuoi bei POCO. Ciò quindi causa i problemi durante la serializzazione con JavaScriptSerializer.

Quindi le 2 soluzioni sono:

  1. O semplicemente serializzi e restituisci le proprietà di cui hai bisogno sul client
  2. È ansible distriggersre la generazione automatica di proxy impostandola sulla configurazione del contesto

    context.Configuration.ProxyCreationEnabled = false;

Molto ben spiegato nel seguente articolo.

http://juristr.com/blog/2011/08/javascriptserializer-circular-reference/

Usando Newtonsoft.Json: Nel tuo metodo Global.asax Application_Start aggiungi questa riga:

 GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; 

aggiungi [JsonIgnore] alle proprietà dei [JsonIgnore] nel tuo modello.

Evitare di convertire direttamente l’object tabella. Se le relazioni sono impostate tra altre tabelle, potrebbe generare questo errore. Piuttosto, è ansible creare una class modello, assegnare valori all’object class e quindi serializzarlo.

Le risposte fornite sono buone, ma penso che possano essere migliorate aggiungendo una prospettiva “architettonica”.

Indagine

MVC's Controller.Json funzione MVC's Controller.Json sta svolgendo il lavoro, ma in questo caso è molto scarso nel fornire un errore rilevante. Usando Newtonsoft.Json.JsonConvert.SerializeObject , l’errore specifica esattamente qual è la proprietà che sta triggersndo il riferimento circolare. Ciò è particolarmente utile quando si serializzano gerarchie di oggetti più complesse.

Architettura corretta

Non si dovrebbe mai provare a serializzare modelli di dati (es. Modelli EF), poiché le proprietà di navigazione di ORM sono la strada da percorrere per quanto riguarda la serializzazione. Il stream di dati dovrebbe essere il seguente:

 Database -> data models -> service models -> JSON string 

I modelli di servizio possono essere ottenuti da modelli di dati utilizzando auto mapper (ad esempio Automapper ). Anche se ciò non garantisce la mancanza di riferimenti circolari, la corretta progettazione dovrebbe farlo: i modelli di servizio dovrebbero contenere esattamente ciò che il consumatore del servizio richiede (cioè le proprietà).

In quei rari casi, quando il client richiede una gerarchia che coinvolge lo stesso tipo di object su livelli diversi, il servizio può creare una struttura lineare con parent-> relazione figlio (usando solo identificatori, non riferimenti).

Le applicazioni moderne tendono ad evitare di caricare strutture dati complesse in una volta e i modelli di servizio dovrebbero essere snelli. Per esempio:

  1. accedere ad un evento – vengono caricati solo i dati di intestazione (identificatore, nome, data ecc.) -> modello di servizio (JSON) contenente solo dati di intestazione
  2. elenco dei partecipanti gestiti – accedi a un popup e pigro carica l’elenco -> modello di servizio (JSON) contenente solo l’elenco dei partecipanti

Sto utilizzando la correzione, perché utilizzo di Knockout nelle viste MVC5.

In azione

 return Json(ModelHelper.GetJsonModel(viewModel)); 

funzione

  public static TEntity GetJsonModel(TEntity Entity) where TEntity : class { TEntity Entity_ = Activator.CreateInstance(typeof(TEntity)) as TEntity; foreach (var item in Entity.GetType().GetProperties()) { if (item.PropertyType.ToString().IndexOf("Generic.ICollection") == -1 && item.PropertyType.ToString().IndexOf("SaymenCore.DAL.") == -1) item.SetValue(Entity_, Entity.GetPropValue(item.Name)); } return Entity_; } 

È ansible notare le proprietà che causano il riferimento circolare. Quindi puoi fare qualcosa come:

 private Object DeCircular(Object object) { // Set properties that cause the circular reference to null return object } 
 //first: Create a class as your view model public class EventViewModel { public int Id{get;set} public string Property1{get;set;} public string Property2{get;set;} } //then from your method [HttpGet] public async Task GetEvent() { var events = await db.Event.Find(x => x.ID != 0); List model = events.Select(event => new EventViewModel(){ Id = event.Id, Property1 = event.Property1, Property1 = event.Property2 }).ToList(); return Json(new{ data = model }, JsonRequestBehavior.AllowGet); } 

Un’alternativa più semplice per risolvere questo problema è restituire una stringa e formattare quella stringa in json con JavaScriptSerializer.

 public string GetEntityInJson() { JavaScriptSerializer j = new JavaScriptSerializer(); var entityList = dataContext.Entitites.Select(x => new { ID = x.ID, AnotherAttribute = x.AnotherAttribute }); return j.Serialize(entityList ); } 

È importante la parte “Seleziona”, che sceglie le proprietà che vuoi nella tua vista. Alcuni oggetti hanno un riferimento per il genitore. Se non si scelgono gli attributi, potrebbe apparire il riferimento circolare, se si prendono solo le tabelle nel loro complesso.

Non farlo:

 public string GetEntityInJson() { JavaScriptSerializer j = new JavaScriptSerializer(); var entityList = dataContext.Entitites.toList(); return j.Serialize(entityList ); } 

Fatelo invece se non volete l’intera tabella:

 public string GetEntityInJson() { JavaScriptSerializer j = new JavaScriptSerializer(); var entityList = dataContext.Entitites.Select(x => new { ID = x.ID, AnotherAttribute = x.AnotherAttribute }); return j.Serialize(entityList ); } 

Questo aiuta a rendere una vista con meno dati, solo con gli attributi che ti servono, e rende il tuo web più veloce.