J'ai essayé de sérialiser la classe POCO qui a été générée automatiquement à partir de Entity Data Model .edmx et quand j'ai utilisé
JsonConvert.SerializeObject
J'ai eu l'erreur suivante:
Erreur Une boucle d'auto-référencement détectée pour le type System.data.entity se produit.
Comment résoudre ce problème?
C'était la meilleure solution https://code.msdn.Microsoft.com/Loop-Reference-handling-in-caaffaf7
(j'ai choisi/essayé celui-ci, comme beaucoup d'autres)
Le sérialiseur json.net a une option pour ignorer les références circulaires. Placez le code suivant dans le fichier WebApiConfig.cs
:
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling
= Newtonsoft.Json.ReferenceLoopHandling.Ignore;
Le correctif simple fera que le sérialiseur ignore la référence, ce qui provoquera une boucle. Cependant, il a des limites:
Si vous souhaitez utiliser ce correctif dans un projet ASP.NET non-api, vous pouvez ajouter la ligne ci-dessus à Global.asax.cs
, mais ajoutez d'abord:
var config = GlobalConfiguration.Configuration;
Si vous souhaitez utiliser cela dans le projet . Net Core , vous pouvez modifier Startup.cs
en tant que:
var mvc = services.AddMvc(options =>
{
...
})
.AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
Ce deuxième correctif est similaire au premier. Il suffit de changer le code en:
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling
= Newtonsoft.Json.ReferenceLoopHandling.Serialize;
config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling
= Newtonsoft.Json.PreserveReferencesHandling.Objects;
La forme des données sera modifiée après l'application de ce paramètre.
[
{
"$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 et $ ref conservent toutes les références et rendent le niveau de graphe d'objet plat, mais le code client a besoin de connaître le changement de forme pour consommer les données et s'applique également au sérialiseur JSON.NET.
Ce correctif consiste à décorer les attributs de la classe de modèle pour contrôler le comportement de la sérialisation au niveau du modèle ou de la propriété. Pour ignorer la propriété:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
[JsonIgnore]
[IgnoreDataMember]
public virtual ICollection<Product> Products { get; set; }
}
JsonIgnore est pour JSON.NET et IgnoreDataMember est pour XmlDCSerializer. Pour conserver la référence:
// 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 pour JSON.NET et [DataContract(IsReference = true)]
est pour XmlDCSerializer. Notez que: après avoir appliqué DataContract
à la classe, vous devez ajouter DataMember
aux propriétés que vous souhaitez sérialiser.
Les attributs peuvent être appliqués sur les sérialiseurs json et xml et donnent plus de contrôles sur la classe de modèle.
Utilisez JsonSerializerSettings
ReferenceLoopHandling.Error
(valeur par défaut) générera une erreur si une boucle de référence est rencontrée. C'est pourquoi vous obtenez une exception. ReferenceLoopHandling.Serialize
est utile si les objets sont imbriqués mais pas indéfiniment.ReferenceLoopHandling.Ignore
ne sérialisera pas un objet s'il s'agit d'un objet enfant de lui-même.Exemple:
JsonConvert.SerializeObject(YourPOCOHere, Formatting.Indented,
new JsonSerializerSettings {
ReferenceLoopHandling = ReferenceLoopHandling.Serialize
});
Si vous devez sérialiser un objet imbriqué indéfiniment, vous pouvez utiliser PreserveObjectReferences pour éviter une exception StackOverflowException.
Exemple:
JsonConvert.SerializeObject(YourPOCOHere, Formatting.Indented,
new JsonSerializerSettings {
PreserveReferencesHandling = PreserveReferencesHandling.Objects
});
Choisissez ce qui a du sens pour l'objet que vous sérialisez.
Référence http://james.newtonking.com/json/help/
Le correctif consiste à ignorer les références de boucle et non à les sérialiser. Ce comportement est spécifié dans JsonSerializerSettings
.
Unique JsonConvert
avec une surcharge:
JsonConvert.SerializeObject(YourObject, Formatting.Indented,
new JsonSerializerSettings() {
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
}
);
Paramètre global avec un code dans Application_Start()
dans Global.asax.cs:
JsonConvert.DefaultSettings = () => new JsonSerializerSettings {
Formatting = Newtonsoft.Json.Formatting.Indented,
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
};
Référence: https://github.com/JamesNK/Newtonsoft.Json/issues/78
La façon la plus simple de procéder consiste à installer Json.NET à partir de nuget et à ajouter l'attribut [JsonIgnore]
à la propriété virtuelle de la classe, par exemple:
public string Name { get; set; }
public string Description { get; set; }
public Nullable<int> Project_ID { get; set; }
[JsonIgnore]
public virtual Project Project { get; set; }
Bien que ces jours-ci, je crée un modèle avec uniquement les propriétés que je souhaite transmettre; il est donc plus clair, n'inclut pas les collections non désirées et je ne perds pas mes modifications lorsque je reconstruis les fichiers générés ...
Dans .NET Core 1.0, vous pouvez définir cela comme paramètre global dans votre fichier 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));
});
}
Nous pouvons ajouter ces deux lignes dans le constructeur de la classe DbContext pour désactiver la boucle d'auto-référencement, comme
public TestContext()
: base("name=TestContext")
{
this.Configuration.LazyLoadingEnabled = false;
this.Configuration.ProxyCreationEnabled = false;
}
Pour sérialiser usin NEWTONSOFTJSON lorsque vous avez un problème de boucle, dans mon cas, je n'avais pas besoin de modifier global.asax ni d'apiconfig. Je viens d'utiliser JsonSerializesSettings en ignorant la gestion en boucle.
JsonSerializerSettings jss = new JsonSerializerSettings();
jss.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
var lst = db.shCards.Where(m => m.CardID == id).ToList();
string json = JsonConvert.SerializeObject(lst, jss);
Si vous utilisez .NET Core 2.0, mettez à jour votre section ConfigureServices dans 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
);
...
}
Vous pouvez également appliquer un attribut à la propriété. L'attribut [JsonProperty( ReferenceLoopHandling = ... )]
est bien adapté à cela.
Par exemple:
/// <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...
}
J'espère que ça aide, Jaans
Pour ignorer les références de boucle et ne pas les sérialiser globalement dans MVC 6, utilisez ce qui suit dans 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);
});
}
Pour moi, je devais prendre un chemin différent. Au lieu d'essayer de réparer le sérialiseur JSON.Net, je devais rechercher le chargement paresseux sur mon contexte de données.
Je viens d'ajouter ceci à mon référentiel de base:
context.Configuration.ProxyCreationEnabled = false;
L'objet "context" est un paramètre de constructeur que j'utilise dans mon référentiel de base car j'utilise l'injection de dépendances. Vous pouvez modifier la propriété ProxyCreationEnabled à n'importe quel endroit où vous instanciez votre contexte de données.
http://techie-tid-bits.blogspot.com/2015/09/jsonnet-serializer-and-error-self.html
J'ai eu cette exception et ma solution de travail est facile et simple,
Ignorez la propriété référencée en y ajoutant l'attribut JsonIgnore:
[JsonIgnore]
public MyClass currentClass { get; set; }
Réinitialisez la propriété lorsque vous la désérialisez:
Source = JsonConvert.DeserializeObject<MyObject>(JsonTxt);
foreach (var item in Source)
{
Source.MyClass = item;
}
using Newtonsoft.Json;
Utilisez ceci dans la classe WebApiConfig.cs
:
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
Équipe:
Cela fonctionne avec ASP.NET Core; Le défi de ce qui précède est de savoir comment définir le paramètre pour ignorer. En fonction de la configuration de votre application, cela peut être assez difficile. Voici ce qui a fonctionné pour moi.
Cela peut être placé dans votre section ConfigureServices (services IServiceCollection) vide publique.
services.AddMvc().AddJsonOptions(opt =>
{
opt.SerializerSettings.ReferenceLoopHandling =
Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
On a déjà parlé de l'ajout de [JsonIgnore] à la propriété virtuelle de la classe, par exemple:
[JsonIgnore]
public virtual Project Project { get; set; }
Je partagerai également une autre option, [JsonProperty (NullValueHandling = NullValueHandling.Ignore)], qui omet la propriété de la sérialisation uniquement si elle est null:
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public virtual Project Project { get; set; }
Mon problème résolu avec la configuration personnalisée JsonSerializerSettings:
services.AddMvc(
// ...
).AddJsonOptions(opt =>
{
opt.SerializerSettings.ReferenceLoopHandling =
Newtonsoft.Json.ReferenceLoopHandling.Serialize;
opt.SerializerSettings.PreserveReferencesHandling =
Newtonsoft.Json.PreserveReferencesHandling.Objects;
});
Il suffit de placer Configuration.ProxyCreationEnabled = false;
dans le fichier de contexte; cela résoudra le problème.
public demEntities()
: base("name=demEntities")
{
Configuration.ProxyCreationEnabled = false;
}