ตรวจพบลูปการอ้างอิง JSON.Net ด้วยตนเอง


117

ฉันมีฐานข้อมูล mssql สำหรับเว็บไซต์ของฉันภายใน 4 ตาราง

เมื่อฉันใช้สิ่งนี้:

public static string GetAllEventsForJSON()
{
    using (CyberDBDataContext db = new CyberDBDataContext())
    {
        return JsonConvert.SerializeObject((from a in db.Events where a.Active select a).ToList(), new JavaScriptDateTimeConverter());
    }
}

รหัสส่งผลให้เกิดข้อผิดพลาดต่อไปนี้:

Newtonsoft.Json.JsonSerializationException: ตรวจพบลูปการอ้างอิงตนเองสำหรับคุณสมบัติ 'CyberUser' ด้วยประเภท 'DAL.CyberUser' เส้นทาง '[0] .EventRegistrations [0] .CyberUser.UserLogs [0]'



คุณช่วยทำเครื่องหมายคำตอบของฉันว่าถูกต้องได้ไหม @Kovu
มูฮัมหมัดโอมาร์ ElShourbagy

คำตอบ:


216

ฉันเพิ่งมีปัญหาเดียวกันกับคอลเล็กชันผู้ปกครอง / เด็กและพบว่าโพสต์นั้นได้แก้ไขกรณีของฉัน ฉันต้องการแสดงรายการคอลเล็กชันของผู้ปกครองเท่านั้นและไม่ต้องการข้อมูลลูกใด ๆ ดังนั้นฉันจึงใช้สิ่งต่อไปนี้และมันก็ใช้ได้ดี:

JsonConvert.SerializeObject(ResultGroups, Formatting.None,
                        new JsonSerializerSettings()
                        { 
                            ReferenceLoopHandling = ReferenceLoopHandling.Ignore
                        });

ข้อผิดพลาด JSON.NET ตรวจพบลูปการอ้างอิงตัวเองสำหรับชนิด

นอกจากนี้ยังอ้างอิงไปยังหน้า codeplex Json.NET ที่:

http://json.codeplex.com/discussions/272371

เอกสารประกอบ: การตั้งค่า ReferenceLoopHandling


2
ขึ้นอยู่กับกรณีที่คุณสามารถใช้ PreserveReferencesHandling = PreserveReferencesHandling.Objects;ตามที่อธิบายไว้ที่นี่: แก้ปัญหาการอ้างอิงตัวเองลูปปัญหาเมื่อใช้ newtonsoft-json
Dimitri Troncquo

ใน WebAPI OData v4 ฉันพบว่าข้อมูลบางประเภทต้องการทั้ง ReferenceLoopHandling.Ignore และ PreserveReferencesHandling.Objects
Chris Schaller

1
Sings Allelluiahขอบคุณมากการโหวตด้วย 1 เท่านั้นไม่เพียงพอ
JP Chapleau

44

การแก้ไขคือละเว้นการอ้างอิงแบบวนซ้ำและไม่ต้องทำให้เป็นอนุกรม JsonSerializerSettingsลักษณะการทำงานนี้ระบุไว้ใน

เดี่ยวJsonConvertกับเกิน:

JsonConvert.SerializeObject((from a in db.Events where a.Active select a).ToList(), Formatting.Indented,
    new JsonSerializerSettings() {
        ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
    }
);

หากคุณต้องการกำหนดให้เป็นพฤติกรรมเริ่มต้นให้เพิ่มการ ตั้งค่าส่วนกลางพร้อมรหัสApplication_Start()ใน Global.asax.cs:

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

อ้างอิง: https://github.com/JamesNK/Newtonsoft.Json/issues/78


3
การทำให้เป็นอนุกรมกับสิ่งนี้ใช้เวลานานมากสำหรับฉัน
daniel

สิ่งนี้ดูเหมือนจะใช้ไม่ได้เมื่อวัตถุที่มีลูปแบบวงกลมเป็น POCO แบบจำลอง NHibernate (ในกรณีนี้การทำให้เป็นอนุกรมจะดึงขยะจำนวนมากหรือบางครั้งก็หมดเวลา)
Fernando Gonzalez Sanchez

"IsSecuritySafeCritical": false, "IsSecurityTransparent": false, "MethodHandle": {"Value": {"value": 140716810003120}}, "Attributes": 150, "CallingConvention": 1, "ReturnType": "System.Void , System.Private.CoreLib, เวอร์ชัน = 4.0.0.0, วัฒนธรรม = เป็นกลาง, PublicKeyToken = 7cec85d7bea7798e "," ReturnTypeCustomAttributes ": {" ParameterType ":" System.Void, System.Private.CoreLib, เวอร์ชัน = 4.0.0.0, วัฒนธรรม = เป็นกลาง PublicKeyToken = 7cec85d7bea7798e "," Name ": null," HasDefaultValue ": true," DefaultValue ": null," RawDefaultValue ": null," MetadataToken ": 134217728," Attributes ": 0," Position ": - 1, "IsIn": false, "IsLcid": false,. ... ฯลฯ

38

หากใช้ ASP.NET Core MVC ให้เพิ่มสิ่งนี้ลงในวิธี ConfigureServices ของไฟล์ startup.cs ของคุณ:

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

2
ฉันยืนยันว่าโซลูชันนี้ใช้ได้กับ WebAPI EntityFramework Core 2.0
cesar-moya

13

สิ่งนี้อาจช่วยคุณได้

public MyContext() : base("name=MyContext") 
{ 
    Database.SetInitializer(new MyContextDataInitializer()); 
    this.Configuration.LazyLoadingEnabled = false; 
    this.Configuration.ProxyCreationEnabled = false; 
} 

http://code.msdn.microsoft.com/Loop-Reference-handling-in-caaffaf7


4
นี่เป็นวิธีที่ดีที่สุดในการเข้าถึงหากคุณใช้วิธี async ด้วย อาจเป็นความเจ็บปวดอย่างแท้จริง แต่ก็ช่วยแก้ปัญหาต่างๆที่คุณอาจมีได้ (รวมถึงปัญหานี้ด้วย) และยังสามารถมีประสิทธิภาพมากขึ้นเนื่องจากคุณเพียงแค่ค้นหาสิ่งที่คุณจะใช้
Josh McKearin

ใน xyz.edmx ของคุณให้เปิดไฟล์ xyz.Context.vb ซึ่งจะถูกซ่อนไว้ตามค่าเริ่มต้น นี้จะมี codeSub สาธารณะใหม่ () Mybase.New ( "name = EntityConName") End codeSub ก่อนที่ End Sub จะเพิ่ม codeMe.Configuration.LazyLoadingEnabled = False Me.Configuration.ProxyCreationEnabled = False code ซึ่งจะกำจัดข้อผิดพลาด 'Self referencing loop' ในเอาต์พุต json ของคุณจาก webapi
Venkat

ฉันพบว่าสิ่งนี้ไม่ได้ผลสำหรับฉัน ฉันใช้ AsNoTracking () และแก้ไขแล้ว อาจจะช่วยคนอื่น
scottsanpedro

@scottsanpedro จะดีกว่าถ้าเราเห็นรหัสของคุณ
ddagsan

6

คุณต้องตั้งค่าการอ้างอิงวัตถุรักษา:

var jsonSerializerSettings = new JsonSerializerSettings
{
    PreserveReferencesHandling = PreserveReferencesHandling.Objects
};

จากนั้นเรียกคำถามของคุณvar q = (from a in db.Events where a.Active select a).ToList();เช่น

string jsonStr = Newtonsoft.Json.JsonConvert.SerializeObject(q, jsonSerializerSettings);

ดู: https://www.newtonsoft.com/json/help/html/PreserveObjectReferences.htm


4

เพิ่ม "[JsonIgnore]" ในคลาสโมเดลของคุณ

{
  public Customer()
  {
    Orders = new Collection<Order>();
  }

public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }

[JsonIgnore]
public ICollection<Order> Orders { get; set; }
}

4

ฉันใช้ Dot.Net Core 3.1 และค้นหาไฟล์

"Newtonsoft.Json.JsonSerializationException: ตรวจพบลูปการอ้างอิงตัวเองสำหรับคุณสมบัติ"

ฉันกำลังเพิ่มคำถามนี้ในคำถามนี้เนื่องจากจะเป็นข้อมูลอ้างอิงที่ง่าย คุณควรใช้สิ่งต่อไปนี้ในไฟล์ Startup.cs:

 services.AddControllers()
                .AddNewtonsoftJson(options =>
                {
                    // Use the default property (Pascal) casing
                    options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                    options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                });

2

สำหรับ asp.net core 3.1.3 สิ่งนี้ใช้ได้สำหรับฉัน

services.AddControllers().AddNewtonsoftJson(opt=>{
            opt.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        });

1

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


7
แม้ว่ารหัสนี้อาจตอบคำถาม แต่การให้บริบทเพิ่มเติมเกี่ยวกับสาเหตุและ / หรือวิธีที่รหัสนี้ตอบคำถามช่วยเพิ่มคุณค่าในระยะยาว
Alex Riabov

1

บางครั้งคุณมีลูปเนื่องจากคลาส type ของคุณมีการอ้างอิงถึงคลาสอื่นและคลาสนั้นมีการอ้างอิงถึงคลาส type ของคุณดังนั้นคุณต้องเลือกพารามิเตอร์ที่คุณต้องการในสตริง json เช่นโค้ดนี้

List<ROficina> oficinas = new List<ROficina>();
oficinas = /*list content*/;
var x = JsonConvert.SerializeObject(oficinas.Select(o => new
            {
                o.IdOficina,
                o.Nombre
            }));

0

อินสแตนซ์ JsonSerializer สามารถกำหนดค่าให้ละเว้นการอ้างอิงลูป ดังต่อไปนี้ฟังก์ชั่นนี้อนุญาตให้บันทึกไฟล์ที่มีเนื้อหาของวัตถุอนุกรม json:

    public static void SaveJson<T>(this T obj, string FileName)
    {
   
       JsonSerializer serializer = new JsonSerializer();
        serializer.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
        using (StreamWriter sw = new StreamWriter(FileName))
        {
            using (JsonWriter writer = new JsonTextWriter(sw))
            {
                writer.Formatting = Formatting.Indented;
                serializer.Serialize(writer, obj);
            }
        }
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.