it-swarm.it

Errore JSON.NET Rilevato ciclo di riferimento automatico per tipo

Ho provato a serializzare la classe POCO che è stata generata automaticamente da Entity Data Model .edmx e quando l'ho usata

JsonConvert.SerializeObject 

Ho ricevuto il seguente errore:

Errore Rilevato loop autoreferenziale rilevato per tipo System.data.entity.

Come risolvo questo problema?

416
NevenHuynh

Questa era la soluzione migliore https://code.msdn.Microsoft.com/Loop-Reference-handling-in-caaffaf7

Fix 1: ignorare il riferimento circolare globalmente

(Ho scelto/provato questo, come molti altri)

Il serializzatore json.net ha un'opzione per ignorare i riferimenti circolari. Inserisci il seguente codice nel file WebApiConfig.cs:

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

La semplice correzione farà sì che il serializzatore ignori il riferimento che causerà un loop. Tuttavia, ha limitazioni:

  • I dati perdono le informazioni di riferimento del loop
  • La correzione si applica solo a JSON.net
  • Il livello dei riferimenti non può essere controllato se esiste una catena di riferimento profonda

Se si desidera utilizzare questa correzione in un progetto ASP.NET non API, è possibile aggiungere la riga sopra a Global.asax.cs, ma prima aggiungere:

var config = GlobalConfiguration.Configuration;

Se vuoi usare questo in . Progetto Net Core , puoi cambiare Startup.cs come:

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

Correzione 2: conservazione del riferimento circolare globalmente

Questa seconda correzione è simile alla prima. Basta cambiare il codice per:

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

La forma dei dati verrà modificata dopo aver applicato questa impostazione.

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

$ Id e $ ref mantengono tutti i riferimenti e rendono piatto il livello dell'oggetto, ma il codice client deve conoscere la modifica della forma per consumare i dati e si applica solo al serializzatore JSON.NET.

Fix 3: Ignora e conserva gli attributi di riferimento

Questa correzione è decorare gli attributi sulla classe del modello per controllare il comportamento della serializzazione a livello di modello o di proprietà. Per ignorare la proprietà:

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

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

JsonIgnore è per JSON.NET e IgnoreDataMember è per XmlDCSerializer. Per conservare il riferimento:

 // 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)]is per JSON.NET e [DataContract(IsReference = true)] è per XmlDCSerializer. Si noti che: dopo aver applicato DataContract sulla classe, è necessario aggiungere DataMember alle proprietà che si desidera serializzare.

Gli attributi possono essere applicati su serializer json e xml e forniscono più controlli sulla classe del modello.

392
Bishoy Hanna

Usa JsonSerializerSettings

  • ReferenceLoopHandling.Error (predefinito) errore se viene rilevato un loop di riferimento. Ecco perché ottieni un'eccezione.
  • ReferenceLoopHandling.Serialize è utile se gli oggetti sono nidificati ma non indefinitamente.
  • ReferenceLoopHandling.Ignore non serializzerà un oggetto se è un oggetto figlio di se stesso.

Esempio:

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

Se si deve serializzare un oggetto che è annidato indefinitamente, è possibile utilizzare PreserveObjectReferences per evitare StackOverflowException.

Esempio:

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

Scegli cosa ha senso per l'oggetto che stai serializzando.

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

419
DalSoft

La soluzione è ignorare i riferimenti del ciclo e non serializzarli. Questo comportamento è specificato in JsonSerializerSettings.

Single JsonConvert con sovraccarico:

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

Impostazioni globali con codice in Application_Start() in Global.asax.cs:

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

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

48
smockle

Il modo più semplice per farlo è installare Json.NET da nuget e aggiungere l'attributo [JsonIgnore] alla proprietà virtuale nella classe, ad esempio:

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

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

Anche se in questi giorni, creo un modello con solo le proprietà che voglio passare, quindi è più leggero, non include le raccolte indesiderate e non perdo le mie modifiche quando ricostruisco i file generati ...

39
Sam Jones

In .NET Core 1.0, è possibile impostarlo come impostazione globale nel file Startup.cs:

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

Possiamo aggiungere queste due linee nel costruttore della classe DbContext per disabilitare il loop di Self referencing, come

public TestContext()
        : base("name=TestContext")
{
    this.Configuration.LazyLoadingEnabled = false;
    this.Configuration.ProxyCreationEnabled = false;
}
7
Sanjay Nishad

Per serializzare in NEWTONSOFTJSON quando si ha un problema di loop, nel mio caso non avevo bisogno di modificare global.asax o apiconfig. Io uso solo JsonSerializesSettings ignorando la gestione del Looping.

JsonSerializerSettings jss = new JsonSerializerSettings();
jss.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
var lst = db.shCards.Where(m => m.CardID == id).ToList();
string json = JsonConvert.SerializeObject(lst, jss);
7
Carlos Barini

Se utilizzi .NET Core 2.0, aggiorna la sezione ConfiguraServices in Startup.cs

https://docs.Microsoft.com/en-us/ef/core/querying/related-data#related-data-and-serialization

public void ConfigureServices(IServiceCollection services)
{
...

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

...
}
5
Dave

Puoi anche applicare un attributo alla proprietà. L'attributo [JsonProperty( ReferenceLoopHandling = ... )] è adatto a questo.

Per esempio:

/// <summary>
/// Represents the exception information of an event
/// </summary>
public class ExceptionInfo
{
    // ...code omitted for brevity...

    /// <summary>
    /// An inner (nested) error.
    /// </summary>
    [JsonProperty( ReferenceLoopHandling = ReferenceLoopHandling.Ignore, IsReference = true )]
    public ExceptionInfo Inner { get; set; }

    // ...code omitted for brevity...    
}

Spero che aiuti, Jaans

4
Jaans

Per ignorare i riferimenti del ciclo e non serializzarli globalmente in MVC 6, utilizzare quanto segue in startup.cs:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().Configure<MvcOptions>(options =>
        {
            options.OutputFormatters.RemoveTypesOf<JsonOutputFormatter>();
            var jsonOutputFormatter = new JsonOutputFormatter();
            jsonOutputFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
            options.OutputFormatters.Insert(0, jsonOutputFormatter);
        });
    }
4
GerardBeckerleg

Per me ho dovuto seguire una strada diversa. Invece di provare a sistemare il serializzatore JSON.Net, ho dovuto seguire il Lazy Loading sul mio datacontext.

Ho appena aggiunto questo al mio repository di base:

context.Configuration.ProxyCreationEnabled = false;

L'oggetto "context" è un parametro costruttore che utilizzo nel mio repository di base perché utilizzo dependency injection. È possibile modificare la proprietà ProxyCreationEnabled ovunque si instanzia invece il proprio datacontext.

http://techie-tid-bits.blogspot.com/2015/09/jsonnet-serializer-and-error-self.html

2
Xipooo

Ho avuto questa eccezione e la mia soluzione di lavoro è semplice e facile,

Ignora la proprietà di riferimento aggiungendo l'attributo JsonIgnore ad esso:

[JsonIgnore]
public MyClass currentClass { get; set; }

Resetta la proprietà quando la deserializzi:

Source = JsonConvert.DeserializeObject<MyObject>(JsonTxt);
foreach (var item in Source)
        {
            Source.MyClass = item;
        }

utilizzando Newtonsoft.Json;

2
Mayer Spitzer

Usalo nella classe WebApiConfig.cs:

var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
2
Anand Kumar

Squadra:

Funziona con ASP.NET Core; La sfida a quanto sopra è come si imposta l'impostazione da ignorare. A seconda di come si imposta la propria applicazione, può essere piuttosto difficile. Ecco cosa ha funzionato per me.

Questo può essere inserito nella sezione pubblica ConfigureServices (servizi IServiceCollection).

services.AddMvc().AddJsonOptions(opt => 
        { 
      opt.SerializerSettings.ReferenceLoopHandling =
      Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        });
1
FlyingV

Le persone hanno già parlato di [JsonIgnore] che viene aggiunto alla proprietà virtuale nella classe, ad esempio:

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

Condividerò anche un'altra opzione, [JsonProperty (NullValueHandling = NullValueHandling.Ignore)] che omette la proprietà dalla serializzazione solo se è nullo:

[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public virtual Project Project { get; set; }
1
Ali Raza

Il mio problema risolto con la configurazione personalizzata JsonSerializerSettings:

services.AddMvc(
  // ...
               ).AddJsonOptions(opt =>
                 {
                opt.SerializerSettings.ReferenceLoopHandling =
                    Newtonsoft.Json.ReferenceLoopHandling.Serialize;
                opt.SerializerSettings.PreserveReferencesHandling =
                    Newtonsoft.Json.PreserveReferencesHandling.Objects;
                 });
0
AminGolmahalle

Inserisci semplicemente Configuration.ProxyCreationEnabled = false; all'interno del file di contesto; questo risolverà il problema.

public demEntities()
    : base("name=demEntities")
{
    Configuration.ProxyCreationEnabled = false;
}
0
fraka