It is common to have circular references in the model. For example, the following model shows bidirectional navigation properties:
1: Public classCategory2: { 3: PublicCategory ()4: { 5: Products =NewCollection<product>(); 6: } 7: 8: Public intId {Get;Set; } 9: Public stringName {Get;Set; } Ten: Public VirtualIcollection<product> Products {Get;Set; } One: } A: -: Public classProduct -: { the: Public intId {Get;Set; } -: Public stringName {Get;Set; } -: Public VirtualCategory Category {Get;Set; } -: }
When used with the Web API by generating the EF API controller, it does not work by default. The following error occurs when serializing with the Json.NET serializer:
This error occurs because the serializer does not know how to handle a circular reference. (similar errors occur in the XML serializer)
disable the agent and include references
EF proxies are not available for Poco data serialization. There are several workarounds . for the sake of simplicity, we just disable it in the data context class:
1: PublicCircularreferencesamplecontext ():Base("Name=circularreferencesamplecontext") 2: { 3: Database.setinitializer (NewCircularreferencedatainitializer ()); 4: This. configuration.lazyloadingenabled =false; 5: This. configuration.proxycreationenabled =false; 6: }
However, after the proxy is disabled, the navigation properties are not delayed loading. Therefore, you must include references when retrieving data from the database. Change the Scaffold controller code to:
1 Public IEnumerable <Product> getproducts () 2: { 3: return db. Products.include (p = p.category). AsEnumerable (); 4
Contains reference data that the call will contain for all records.
fix 1: Ignore circular references globally
the Json.NET serializer supports circular references that ignore global settings. A quick solution is to put the following code in the WebApiConfig.cs file:
1: CONFIG. Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore ;
A simple fix causes the serializer to ignore references that cause loops. However, it has limitations:
- Data Loss Cycle reference information
- This hotfix is only available for json.net
- The reference level cannot be controlled if there is a depth reference chain
Fix 2: Keep Global circular references
The second fix is similar to the first one. Just change the code to:
1 : CONFIG. Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling 2: = Newtonsoft.Json.ReferenceLoopHandling.Serialize; 3 : CONFIG. Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling 4: = Newtonsoft.Json.PreserveReferencesHandling.Objects;
The data shape changes after you apply this setting.
1: [{"$ id": "1", "category": {"$ id": "2", "Product": [{"$ id": "3", "category": {"$ REF": "2< /c5> "}," id ":2," name ":" Yogurt "},{" $ REF ":"1"}]," id ":1," name ":" Diary "}," id ":1ref
":"3"}]
$ ID and $ ref keep all references and keep the object graph level intact, but client code needs to know that the shape changes to consume data, and it only applies to the Json.NET serializer.
Fix 3: Ignore and preserve reference properties
This hotfix decorates properties on model classes to control the serialization behavior at the model or attribute level. Ignore this property:
1: Public classCategory2: { 3: Public intId {Get;Set; } 4: Public stringName {Get;Set; } 5: 6: [Jsonignore]7: [Ignoredatamember]8: Public VirtualIcollection<product> Products {Get;Set; } 9: }The Jsonignore is used for Json.net,ignoredatamember for Xmldcserializer.
in order to maintain the reference:
1://Fix 3 2: [Jsonobject (isreference =true)] 3: Public classCategory4: { 5: Public intId {Get;Set; } 6: Public stringName {Get;Set; } 7: 8://Fix 3 9://[Jsonignore] Ten://[Ignoredatamember] One: Public VirtualIcollection<product> Products {Get;Set; } A: } -: -: [DataContract (isreference =true)] the: Public classProduct -: { -: [Key] -: Public intId {Get;Set; } +: -: [DataMember] +: Public stringName {Get;Set; } A: at: [DataMember] -: Public VirtualCategory Category {Get;Set; } -: }
[Jsonobject (IsReference = True)] applies to json.net,[datacontract (IsReference = True)] for Xmldcserializer. Note: After applying datacontract on a class, you need to add DataMember to the property you want to serialize.
These properties can be applied to JSON and XML serializers, and can provide more control for model classes.
Refer to the official solution: HTTPS://CODE.MSDN.MICROSOFT.COM/LOOP-REFERENCE-HANDLING-IN-CAAFFAF7
Json. NET self-referencing loop detected with type reason and workaround