Виявлено цикл JSON.Net з самостійним посиланням


111

У мене є база даних 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

Відповіді:


212

У мене просто була та сама проблема з колекціями Parent / Child, і я виявив, що посада вирішила мою справу. Я хотів лише показати Список батьківських колекційних предметів і мені не потрібні були жодні дочірні дані, тому я використав наступне, і воно спрацювало чудово:

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

JSON.NET Помилка Виявлено цикл самонавідного посилання для типу

він також посилається на сторінку кодового коду Json.NET за адресою:

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

Документація: параметр ReferenceLoopHandling


2
Залежно від випадку, який ви також можете використати, PreserveReferencesHandling = PreserveReferencesHandling.Objects;як пояснено тут: вирішити-самонаправляти-петлю-питання-при використанні-newtonsoft-json
Димитрій Тронко

У WebAPI OData v4 я виявив, що для деяких типів даних потрібні і ReferenceLoopHandling.Ignore та PreserveReferencesHandling.Objects
Chris Schaller

1
Співає Allelluiah Спасибі стільки, тільки голосування під голосуванням на 1 недостатньо
JP Chapleau

42

Виправлення полягає в ігноруванні посилань на цикл, а не в їх серіалізації. Така поведінка вказана в 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/isissue/78


3
Серіалізація з цим займає дуже довго для мене
Даніель,

Це, здається, не спрацьовує, коли об'єкт із круговими петлями - це POCO з моделями NHibernate (у такому випадку серіалізація витягує тонну сміття, а іноді й просто часу).
Фернандо Гонсалес Санчес

"IsSecuritySafeCritical": false, "IsSecurityTransparent": false, "MethodHandle": {"Значення": {"значення": 140716810003120}}, "Атрибути": 150, "CallingConvention": 1, "ReturnType": "System.Void , System.Private.CoreLib, версія = 4.0.0.0, культура = нейтральна, PublicKeyToken = 7cec85d7bea7798e "," ReturnTypeCustomAttributes ": {" ParameterType ":" System.Void, System.Private.CoreLib, Version = 4.0.0.0, Culture = нейтральний, PublicKeyToken = 7cec85d7bea7798e "," Ім'я ": null," HasDefaultValue ": true," DefaultValue ": null," RawDefaultValue ": null," MetadataToken ": 134217728," Attributes ": 0," Позиція ": 1," "IsIn": false, "IsLcid": false ,. ... і т.д.

37

Якщо ви використовуєте 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
Це найкращий спосіб підійти до нього, якщо ви також використовуєте методи асинхронізації. Це може бути справжнім болем, але це вирішує багато питань, які ви мали б інакше (включаючи цю), а також може бути набагато ефективнішою, оскільки ви лише запитуєте, що будете використовувати.
Джош Маккерін

У своєму xyz.edmx відкрийте файл xyz.Context.vb, який буде приховано за замовчуванням. Це матиме codeзагальнодоступний суб-новий () Mybase.New ("ім'я = EntityConName") Кінцевий підрозділ code. Тепер перед End Sub додайте codeMe.Configuration.LazyLoadingEnabled = False Me.Configuration.ProxyCreationEnabled = Невірно, code що позбудеться помилки "Самонаправлення циклу" у вашому виході json з webapi.
Венкат

Я виявив, що це не працює для мене. Я використовував 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; }
}

3

Я використовую 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 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 });


6
Хоча цей код може відповісти на питання, надаючи додатковий контекст стосовно того, чому та / або як цей код відповідає на питання, покращує його довгострокове значення.
Олексій Рябов

1

Іноді у вас є петлі, оскільки ваш клас типу має посилання на інші класи, а класи мають посилання на ваш тип типу, тому вам потрібно вибрати параметри, які вам потрібні саме в рядку json, як цей код.

List<ROficina> oficinas = new List<ROficina>();
oficinas = /*list content*/;
var x = JsonConvert.SerializeObject(oficinas.Select(o => new
            {
                o.IdOficina,
                o.Nombre
            }));
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.