Đã phát hiện vòng lặp tự tham chiếu JSON.Net


111

Tôi có một cơ sở dữ liệu mssql cho trang web của mình trong vòng 4 bảng.

Khi tôi sử dụng cái này:

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());
    }
}

Mã dẫn đến lỗi sau:

Newtonsoft.Json.JsonSerializationException: Đã phát hiện vòng lặp tự tham chiếu cho thuộc tính 'CyberUser' với loại 'DAL.CyberUser'. Đường dẫn '[0] .EventRegistrations [0] .CyberUser.UserLogs [0]'.



Bạn có vui lòng đánh dấu câu trả lời của tôi là đúng nếu đúng không? @Kovu
Muhammad Omar ElShourbagy

Câu trả lời:


211

Tôi vừa gặp vấn đề tương tự với bộ sưu tập Parent / Child và nhận thấy bài đăng đó đã giải quyết được trường hợp của tôi. Tôi chỉ muốn hiển thị Danh sách các mục bộ sưu tập cha và không cần bất kỳ dữ liệu con nào, do đó tôi đã sử dụng những thứ sau và nó hoạt động tốt:

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

Lỗi JSON.NET Đã phát hiện thấy vòng lặp tự tham chiếu cho loại

nó cũng tham chiếu đến trang codeplex Json.NET tại:

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

Tài liệu: Cài đặt ReferenceLoopHandling


2
Tùy thuộc vào trường hợp bạn cũng có thể sử dụng PreserveReferencesHandling = PreserveReferencesHandling.Objects;như đã giải thích ở đây: giải quyết-tự tham khảo-loop-vấn đề-khi-dùng-newtonsoft-json
Dimitri Troncquo

Trong WebAPI OData v4, tôi thấy rằng một số loại dữ liệu yêu cầu cả ReferenceLoopHandling.Ignore và PreserveRefutionsHandling.Objects
Chris Schaller

1
Sings Allelluiah Cảm ơn rất nhiều chỉ lên có quyền biểu quyết bởi 1 là không đủ
JP Chapleau

42

Cách khắc phục là bỏ qua các tham chiếu vòng lặp và không tuần tự hóa chúng. Hành vi này được chỉ định trong JsonSerializerSettings.

ĐơnJsonConvert với quá tải:

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

Nếu bạn muốn đặt điều này làm hành vi mặc định, hãy thêm Cài đặt chung với mã Application_Start()trong Global.asax.cs:

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

Tham khảo: https://github.com/JamesNK/Newtonsoft.Json/issues/78


3
Việc tuần tự hóa với điều này mất một thời gian dài đối với tôi
daniel

Điều này dường như không hoạt động khi đối tượng có vòng lặp là POCO mô hình NHibernate (trong trường hợp đó, việc tuần tự hóa lấy ra hàng tấn rác, hoặc đôi khi chỉ hết thời gian).
Fernando Gonzalez Sanchez

"IsSecuritySafeCritical": false, "IsSecurityTransparent": false, "MethodHandle": {"Value": {"value": 140716810003120}}, "Attributes": 150, "CallingConvention": 1, "ReturnType": "System.Void , System.Private.CoreLib, Version = 4.0.0.0, Culture = trung lập, PublicKeyToken = 7cec85d7bea7798e "," ReturnTypeCustomAttributes ": {" ParameterType ":" System.Void, System.Private.CoreLib, Version = 4.0.0.0, Culture = trung tính, PublicKeyToken = 7cec85d7bea7798e "," Tên ": null," HasDefaultValue ": true," DefaultValue ": null," RawDefaultValue ": null," MetadataToken ": 134217728," Thuộc tính ": 0," Vị trí ": - 1, "IsIn": sai, "IsLcid": sai,. ... Vân vân.

37

Nếu sử dụng ASP.NET Core MVC, hãy thêm nó vào phương thức ConfigureServices của tệp startup.cs của bạn:

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

2
Tôi đã xác nhận giải pháp này cũng hoạt động với WebAPI EntityFramework Core 2.0
cesar-moya

13

Điều này có thể giúp bạn.

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
Đây là cách tốt nhất để tiếp cận nó nếu bạn cũng đang sử dụng các phương pháp không đồng bộ. Nó có thể là một nỗi đau thực sự, nhưng nó giải quyết được nhiều vấn đề bạn sẽ gặp phải (bao gồm cả vấn đề này) và cũng có thể hiệu quả hơn nhiều khi bạn chỉ truy vấn những gì bạn sẽ sử dụng.
Josh McKearin

Trong xyz.edmx của bạn, hãy mở tệp xyz.Context.vb, tệp này sẽ bị ẩn theo mặc định. Điều này sẽ có codePublic Sub New () Mybase.New ("name = EntityConName") End Sub code. Bây giờ trước khi End Sub hãy thêm codeMe.Configuration.LazyLoadingEnabled = False Me.Configuration.ProxyCreationEnabled = False code Điều đó sẽ loại bỏ lỗi 'Vòng lặp tự tham chiếu' trong đầu ra json của bạn từ webapi.
Venkat

Tôi thấy điều này không hiệu quả với tôi. Tôi đã sử dụng AsNoTracking () và nó đã sửa nó. Có thể giúp ai đó khác
scottsanpedro

@scottsanpedro, sẽ tốt hơn nếu chúng tôi có thể xem mã của bạn.
ddagsan

6

Bạn phải đặt Tham chiếu Đối tượng Bảo tồn:

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

Sau đó, gọi truy vấn của bạn var q = (from a in db.Events where a.Active select a).ToList();như

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

Xem: https://www.newtonsoft.com/json/help/html/PreserveObjectRefutions.htm


4

Thêm "[JsonIgnore]" vào lớp mô hình của bạn

{
  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; }
}

3

Tôi đang sử dụng Dot.Net Core 3.1 và đã tìm kiếm

"Newtonsoft.Json.JsonSerializationException: Đã phát hiện vòng lặp tự tham chiếu cho thuộc tính"

Tôi đang thêm điều này vào câu hỏi này, vì nó sẽ là một tài liệu tham khảo dễ dàng. Bạn nên sử dụng phần sau trong tệp Startup.cs:

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

2

đối với asp.net core 3.1.3, điều này làm việc cho tôi

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

1

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


6
Mặc dù mã này có thể trả lời câu hỏi, nhưng việc cung cấp thêm ngữ cảnh liên quan đến lý do và / hoặc cách mã này trả lời câu hỏi sẽ cải thiện giá trị lâu dài của nó.
Alex Riabov 12/1218

1

Đôi khi bạn có các vòng lặp vì lớp kiểu của bạn có tham chiếu đến các lớp khác và các lớp đó có tham chiếu đến lớp kiểu của bạn, do đó bạn phải chọn chính xác các tham số mà bạn cần trong chuỗi json, như đoạn mã này.

List<ROficina> oficinas = new List<ROficina>();
oficinas = /*list content*/;
var x = JsonConvert.SerializeObject(oficinas.Select(o => new
            {
                o.IdOficina,
                o.Nombre
            }));
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.