Подтвердить что ты не робот

Ошибка JSON.NET Локальный цикл привязки для типа

Я попытался сериализовать класс POCO, который был автоматически сгенерирован из Entity Data Model.edmx, и когда я использовал

JsonConvert.SerializeObject 

Я получил следующую ошибку:

Ошибка Обнаружен цикл саморегуляции, для которого зарегистрирован тип System.data.entity.

Как решить эту проблему?

4b9b3361

Ответ 1

Это было лучшее решение https://code.msdn.microsoft.com/Loop-Reference-handling-in-caaffaf7

Исправление 1: глобальное игнорирование круговой ссылки

(Я выбрал/попробовал этот, как и многие другие)

Сериализатор json.net имеет возможность игнорировать циклические ссылки. Поместите следующий код в файл WebApiConfig.cs:

 config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling 
= Newtonsoft.Json.ReferenceLoopHandling.Ignore; 

Простое исправление заставит сериализатор игнорировать ссылку, которая вызовет цикл. Однако у него есть ограничения:

  • Данные теряют циклическую справочную информацию
  • Исправление относится только к JSON.net
  • Уровень ссылок не может контролироваться, если существует глубокая цепочка ссылок

Если вы хотите использовать это исправление в не ASPI-проекте ASP.NET, вы можете добавить приведенную выше строку в Global.asax.cs, но сначала добавьте:

var config = GlobalConfiguration.Configuration;

Если вы хотите использовать это в проекте .Net Core, вы можете изменить Startup.cs следующим образом:

  var mvc = services.AddMvc(options =>
        {
           ...
        })
        .AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);

Исправление 2: глобальное сохранение круговой ссылки

Это второе исправление похоже на первое. Просто измените код на:

config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling 
     = Newtonsoft.Json.ReferenceLoopHandling.Serialize;     
config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling 
     = Newtonsoft.Json.PreserveReferencesHandling.Objects;

Форма данных будет изменена после применения этой настройки.

[
   {
      "$id":"1",
      "Category":{
         "$id":"2",
         "Products":[
            {
               "$id":"3",
               "Category":{
                  "$ref":"2"
               },
               "Id":2,
               "Name":"Yogurt"
            },
            {
               "$ref":"1"
            }
         ],
         "Id":1,
         "Name":"Diary"
      },
      "Id":1,
      "Name":"Whole Milk"
   },
   {
      "$ref":"3"
   }
]

$ Id и $ ref сохраняют все ссылки и делают уровень графа объекта плоским, но клиентскому коду необходимо знать изменение формы, чтобы использовать данные, и это также применимо только к сериализатору JSON.NET.

Исправление 3: игнорировать и сохранять ссылочные атрибуты

Это исправление - атрибуты decorate в классе модели для управления поведением сериализации на уровне модели или свойства. Чтобы игнорировать свойство:

 public class Category 
    { 
        public int Id { get; set; } 
        public string Name { get; set; } 

        [JsonIgnore] 
        [IgnoreDataMember] 
        public virtual ICollection<Product> Products { get; set; } 
    } 

JsonIgnore - для JSON.NET, а IgnoreDataMember - для XmlDCSerializer. Чтобы сохранить ссылку:

 // Fix 3 
        [JsonObject(IsReference = true)] 
        public class Category 
        { 
            public int Id { get; set; } 
            public string Name { get; set; } 

           // Fix 3 
           //[JsonIgnore] 
           //[IgnoreDataMember] 
           public virtual ICollection<Product> Products { get; set; } 
       } 

       [DataContract(IsReference = true)] 
       public class Product 
       { 
           [Key] 
           public int Id { get; set; } 

           [DataMember] 
           public string Name { get; set; } 

           [DataMember] 
           public virtual Category Category { get; set; } 
       }

JsonObject(IsReference = true)] для JSON.NET, а [DataContract(IsReference = true)] для XmlDCSerializer. Обратите внимание: после применения DataContract к классу вам необходимо добавить DataMember к свойствам, которые вы хотите сериализовать.

Атрибуты могут применяться как к сериализатору json, так и к сериализатору xml, что дает больше элементов управления классом модели.

Ответ 2

Использовать JsonSerializerSettings

  • ReferenceLoopHandling.Error (по умолчанию) выдаст ошибку, если встретится эталонная петля. Вот почему вы получаете исключение.
  • ReferenceLoopHandling.Serialize полезен, если объекты вложены, но не бесконечно.
  • ReferenceLoopHandling.Ignore не будет сериализовать объект, если он сам является дочерним объектом.

Пример:

JsonConvert.SerializeObject(YourPOCOHere, Formatting.Indented, 
new JsonSerializerSettings { 
        ReferenceLoopHandling = ReferenceLoopHandling.Serialize
});

Если вам нужно сериализовать объект, который вложен неопределенно долго, вы можете использовать PreserveObjectReferences, чтобы избежать QaruException.

Пример:

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

Выберите, что имеет смысл для объекта, который вы сериализуете.

Ссылка http://james.newtonking.com/json/help/

Ответ 3

Исправление состоит в том, чтобы игнорировать ссылки на контуры, а не сериализовывать их. Это поведение указано в JsonSerializerSettings.

Одиночный JsonConvert с перегрузкой:

JsonConvert.SerializeObject(YourObject, 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

Ответ 4

Самый простой способ сделать это - установить Json.NET из nuget и добавить [JsonIgnore] к виртуальному свойству в классе, например:

    public string Name { get; set; }
    public string Description { get; set; }
    public Nullable<int> Project_ID { get; set; }

    [JsonIgnore]
    public virtual Project Project { get; set; }

Хотя в наши дни я создаю модель только с теми свойствами, которые я хочу передать, чтобы она была легче, не включала нежелательные коллекции и не теряла свои изменения при перестройке сгенерированных файлов...

Ответ 5

В .NET Core 1.0 вы можете установить это как глобальную настройку в файле Startup.cs:

using System.Buffers;
using Microsoft.AspNetCore.Mvc.Formatters;
using Newtonsoft.Json;

// beginning of Startup class

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc(options =>
        {
            options.OutputFormatters.Clear();
            options.OutputFormatters.Add(new JsonOutputFormatter(new JsonSerializerSettings(){
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
            }, ArrayPool<char>.Shared));
        });
    }

Ответ 6

Мы можем добавить эти две строки в конструктор класса DbContext, чтобы отключить цикл саморегуляции, например

public TestContext()
        : base("name=TestContext")
{
    this.Configuration.LazyLoadingEnabled = false;
    this.Configuration.ProxyCreationEnabled = false;
}

Ответ 7

Чтобы сериализовать usin NEWTONSOFTJSON, когда у вас возникла проблема с циклом, в моем случае мне не нужно изменять global.asax или apiconfig. Я просто использую JsonSerializesSettings, игнорируя обработку Looping.

JsonSerializerSettings jss = new JsonSerializerSettings();
jss.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
var lst = db.shCards.Where(m => m.CardID == id).ToList();
string json = JsonConvert.SerializeObject(lst, jss);

Ответ 8

Если вы используете .NET Core 2.x, обновите раздел ConfigureServices в Startup.cs

https://docs.microsoft.com/en-us/ef/core/querying/related-data#related-data-and-serialization

public void ConfigureServices(IServiceCollection services)
{
...

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

...
}

Это почти обязательно, если вы используете Entity Framework и шаблон проектирования на основе базы данных.

Ответ 9

Вы также можете применить атрибут к свойству. Атрибут [JsonProperty( ReferenceLoopHandling = ... )] хорошо подходит для этого.

Например:

/// <summary>
/// Represents the exception information of an event
/// </summary>
public class ExceptionInfo
{
    // ...code omitted for brevity...

    /// <summary>
    /// An inner (nested) error.
    /// </summary>
    [JsonProperty( ReferenceLoopHandling = ReferenceLoopHandling.Ignore, IsReference = true )]
    public ExceptionInfo Inner { get; set; }

    // ...code omitted for brevity...    
}

Надеюсь, что это поможет, Jaans

Ответ 10

Чтобы игнорировать ссылки на контуры и не сериализовать их глобально в MVC 6, используйте в startup.cs следующее:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().Configure<MvcOptions>(options =>
        {
            options.OutputFormatters.RemoveTypesOf<JsonOutputFormatter>();
            var jsonOutputFormatter = new JsonOutputFormatter();
            jsonOutputFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
            options.OutputFormatters.Insert(0, jsonOutputFormatter);
        });
    }

Ответ 11

Используйте это в классе WebApiConfig.cs:

var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);

Ответ 12

Для меня мне пришлось идти другим путем. Вместо того, чтобы пытаться исправить сериализатор JSON.Net, мне пришлось идти после Lazy Loading на моем datacontext.

Я просто добавил это в мой базовый репозиторий:

context.Configuration.ProxyCreationEnabled = false;

Объект "context" - это параметр конструктора, который я использую в базовом репозитории, потому что я использую инъекцию зависимостей. Вы можете изменить свойство ProxyCreationEnabled везде, где вы создаете свой файл datacontext.

http://techie-tid-bits.blogspot.com/2015/09/jsonnet-serializer-and-error-self.html

Ответ 13

У меня было это исключение, и мое рабочее решение было простым и простым,

Игнорировать свойство Referenced, добавив к нему атрибут JsonIgnore:

[JsonIgnore]
public MyClass currentClass { get; set; }

Reset свойство, когда вы Deserialize его:

Source = JsonConvert.DeserializeObject<MyObject>(JsonTxt);
foreach (var item in Source)
        {
            Source.MyClass = item;
        }

с использованием Newtonsoft.Json;

Ответ 14

Люди уже говорили о добавлении [JsonIgnore] к виртуальному свойству в классе, например:

[JsonIgnore]
public virtual Project Project { get; set; }

Я также поделюсь другим вариантом, [JsonProperty (NullValueHandling = NullValueHandling.Ignore)], который пропускает свойство из сериализации, только если оно имеет значение null:

[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public virtual Project Project { get; set; }

Ответ 15

Команда:

Это работает с ASP.NET Core; Сложность заключается в том, как установить "игнорирование". В зависимости от того, как вы настраиваете ваше приложение, оно может быть довольно сложным. Вот что сработало для меня.

Это может быть размещено в вашем общедоступном разделе ConfigureServices (IServiceCollection services).

services.AddMvc().AddJsonOptions(opt => 
        { 
      opt.SerializerSettings.ReferenceLoopHandling =
      Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        });

Ответ 16

Просто разместите Configuration.ProxyCreationEnabled = false; внутри контекстного файла; это решит проблему.

public demEntities()
    : base("name=demEntities")
{
    Configuration.ProxyCreationEnabled = false;
}

Ответ 17

Моя проблема решена с помощью пользовательской конфигурации JsonSerializerSettings:

services.AddMvc(
  // ...
               ).AddJsonOptions(opt =>
                 {
                opt.SerializerSettings.ReferenceLoopHandling =
                    Newtonsoft.Json.ReferenceLoopHandling.Serialize;
                opt.SerializerSettings.PreserveReferencesHandling =
                    Newtonsoft.Json.PreserveReferencesHandling.Objects;
                 });

Ответ 18

Для нециклирования это работало для me-
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,

Я решил все это здесь - сериализация дочерних элементов Entity Framework с.Net Core 2 WebAPI https://gist.github.com/Kaidanov/f9ad0d79238494432f32b8407942c606

Получу любые замечания. возможно, кто-то может когда-нибудь использовать его.

Ответ 19

Мне понравилось решение, которое делает это от Application_Start(), как в ответе здесь

По-видимому, я не мог получить доступ к json-объектам в JavaScript, используя конфигурацию в моей функции, как в ответе DalSoft, поскольку возвращаемый объект имел "\n\r" по всему (ключ, val) объекта.

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