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]'.

Страстный разработчик
источник
2
возможный дубликат ошибки JSON.NET. Обнаружен цикл самореференции для типа
Крис Москини
Не могли бы вы отметить мой ответ как правильный, если это так? @Kovu
Мухаммад Омар ЭльШурбаджи
Обнаружен
Майкл

Ответы:

212

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

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;как описано здесь: resolve-self-referencing-loop-issue-when-using-newtonsoft-json
Dimitri Troncquo
В WebAPI OData v4 я обнаружил, что для некоторых типов данных требуются как ReferenceLoopHandling.Ignore, так и PreserveReferencesHandling.Objects
Крис Шаллер,
1
Поет Allelluiah Большое спасибо, только одного голоса недостаточно
JP Chapleau 09
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/issues/78

смоклин
источник
3
Сериализация с этим занимает у меня очень много времени
Дэниел
Это не работает, когда объект с круговыми циклами является POCO модели NHibernate (в этом случае при сериализации извлекается тонна мусора, а иногда просто истекает время ожидания).
Фернандо Гонсалес Санчес
"IsSecuritySafeCritical": false, "IsSecurityTransparent": false, "MethodHandle": {"Value": {"value": 140716810003120}}, "Attributes": 150, "CallingConvention": 1, "ReturnType": "System.Void , System.Private.CoreLib, Version = 4.0.0.0, Culture = нейтральный, PublicKeyToken = 7cec85d7bea7798e "," ReturnTypeCustomAttributes ": {" ParameterType ":" System.Void, System.Private.CoreLib, Version = 4.0.0.0, Culture = нейтральный, PublicKeyToken = 7cec85d7bea7798e "," Name ": null," HasDefaultValue ": true," DefaultValue ": null," RawDefaultValue ": null," MetadataToken ": 134217728," Attributes ": 0," Position ": - 1, «IsIn»: ложь, «IsLcid»: ложь ,. ... и т.д.
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, который по умолчанию будет скрыт. Это будет иметь codePublic Sub New () Mybase.New ("name = EntityConName") End Sub code. Теперь перед End Sub добавьте codeMe.Configuration.LazyLoadingEnabled = False Me.Configuration.ProxyCreationEnabled = False. code Это избавит от ошибки «Самостоятельная ссылка цикла» в вашем 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; }
}
Самет Санман
источник
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;
                });
Кришнан2784
источник
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 });

user3824027
источник
6
Хотя этот код может ответить на вопрос, предоставление дополнительного контекста относительно того, почему и / или как этот код отвечает на вопрос, улучшает его долгосрочную ценность.
Alex Riabov
1

Иногда у вас есть циклы, потому что ваш класс типа имеет ссылки на другие классы и эти классы имеют ссылки на ваш класс типа, поэтому вам нужно выбрать параметры, которые вам нужны, именно в строке json, как этот код.

List<ROficina> oficinas = new List<ROficina>();
oficinas = /*list content*/;
var x = JsonConvert.SerializeObject(oficinas.Select(o => new
            {
                o.IdOficina,
                o.Nombre
            }));
Анжелика Товар
источник