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


494

Я намагався серіалізувати клас POCO, який автоматично генерувався з Entity Data Model .edmx і коли я використовувався

JsonConvert.SerializeObject 

Я отримав таку помилку:

Помилка Виявлено цикл самовідсилки для типу System.data.entity.

Як вирішити цю проблему?



при використанні Linq і MVC: stackoverflow.com/a/38241856
надбудова

при використанні .NET Core 2: stackoverflow.com/a/48709134/4496145
Дейв Скендер

2
Ця помилка трапилася зі мною, коли я хотів серіалізувати результат asyncвиклику методу (a Task) і забув встановити префікс await.
Уве

Відповіді:


485

Це було найкращим рішенням 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
  • Рівень посилань неможливо контролювати, якщо існує глибокий контрольний ланцюг

Якщо ви хочете використати це виправлення в не-api-проекті 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: Ігнорувати та зберігати еталонні атрибути

Це виправлення - це атрибути декорування в класі моделі для контролю поведінки серіалізації на рівні моделі чи властивості. Щоб ігнорувати властивість:

 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 та надає більше керувань для модельного класу.


7
Виправлення 3 працює для мене. Просто видаліть атрибути DataContract і DataMember і поставте JsonObject (IsReference = true) на DTO. І це працює. Дякую.
маестро

1
спробуйте це GlobalConfiguration.Configuration
Bishoy Hanna

1
Виправлення 3 має перевагу в тому, що він працює на клієнтському коді, коли немає GlobalConfiguration
dumbledad

1
@BishoyHanna, чи можете ви відредагувати свою відповідь, щоб дозволити її використовувати у звичайних програмах ASP.NET? Ви можете використовувати запропоновані вами зміни: stackoverflow.com/review/sugges-edits/17797683
NH.

2
Використовуючи [JsonIgnore]вище атрибут працював на мене.
Натан Бек

467

Використовуйте параметри JsonSerializerSettings

  • ReferenceLoopHandling.Error(за замовчуванням) буде помилка, якщо зустрічається цикл посилання. Ось чому ви отримуєте виняток.
  • ReferenceLoopHandling.Serialize корисно, якщо об’єкти вкладені, але не на невизначений час.
  • ReferenceLoopHandling.Ignore не буде серіалізувати об’єкт, якщо він є дочірнім об'єктом сам по собі.

Приклад:

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

Якщо вам доведеться серіалізувати об'єкт, який вкладений на невизначений термін, ви можете використовувати PreserveObjectReferences, щоб уникнути StackOverflowException.

Приклад:

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

Виберіть те, що має сенс для об’єкта, який ви серіалізуєте.

Довідка http://james.newtonking.com/json/help/


66
Я зіткнувся з помилкою під час серіалізації даних. Я використовував ReferenceLoopHandling = ReferenceLoopHandling.Ignoreдля цього роботу

8
Якщо в даних є цикли відліку, використання ReferenceLoopHandling.Serializeзмушує серіалізатор перейти в нескінченний рекурсивний цикл і переповнювати стек.
Брайан Роджерс

1
Правильно. Оскільки питання щодо моделі EF також є вагомим питанням. Змінено, щоб надати всі доступні варіанти.
DalSoft

1
Я зіткнувся з цією ж помилкою, намагаючись серіалізувати об’єкт ... однак, на об’єкт немає жодних посилань, крім типу перерахунку ..
Марін,

1
для мене EF є основною причиною цієї проблеми, оскільки самостійні посилання на них є повсюдно.
Теоман шипахі

57

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


Чому ви встановлюєте формат на відступ під час глобальної настройки?
Мерфібро2

Абсолютно те, що нам потрібно було вирішити цю проблему (виявлену під час розгортання)! Ви, людино .... дякую за те, що ми заощадили час !!
Райан Естабрук

Я вирішив свій ісус, додавши "JsonConvert.DefaultSettings" = () => нові JsonSerializerSettings {....} у класі "Startup.cs"
Beldi Anouar

45

Найпростіший спосіб зробити це - встановити 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; }

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


3
Найкраща відповідь за допомогою Newton JSON
Aizen

21

У .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));
        });
    }

Але в цьому випадку, якщо я хочу усвідомлювати, що ця властивість ігнорується, тоді я не отримаю жодного винятку.
Майєр Шпіцер

10

Якщо ви використовуєте .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
        );

    ...
    }

Якщо ви використовуєте .NET Core 3.x без MVC, це буде:

services.AddControllers()
  .AddNewtonsoftJson(options =>
      options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
   );

Ця обробка циркуляції опорного циклу є майже обов'язковою, якщо ви використовуєте Entity Framework та шаблон дизайну, який базується на першій базі даних.


2
Що робити, якщо я не використовую services.AddMvc()?
присар

2
це погана практика?
Ренан Коельо

На перший погляд ви можете подумати, що це погана практика, оскільки це може перекрити «навмисний дизайн» уникнення старої проблеми «нескінченного циклу». Однак, якщо ви думаєте про ваші випадки використання для занять, вони можуть вам знадобитися для посилання один на одного. Наприклад, ви можете отримати доступ до дерев> фрукти, а також до фруктів> дерев.
Дейв Скендер

Крім того, якщо ви використовуєте шаблон дизайну першої бази даних з чимось на зразок Entity Framework, залежно від того, як ви налаштовуєте закордонні ключі у вашій базі даних, він автоматично створить ці циклічні посилання, тож вам досить доведеться використовувати це налаштування, якщо ви переробили інженерні курси.
Дейв Скендер

9

Щоб серіалізувати usin NEWTONSOFTJSON, коли у вас є проблема з циклом, у моєму випадку мені не потрібно було змінювати global.asax або будь-який apiconfig. Я просто використовую JsonSerializesSettings ігноруючи обробку циклу.

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

1
Якщо хтось ще прийшов сюди, щоб один лайнер зайшов у вікно годинника, щоб це було в пошуку тексту:Newtonsoft.Json.JsonConvert.SerializeObject(objToSerialize, new Newtonsoft.Json.JsonSerializerSettings() {ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore});
Грем

8

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

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

Це одна з найпростіших і працює як шарм . Проголосували, спасибі велике ...
Murat Yıldız

Як я писав в іншому запитанні: мені не подобаються подібні відповіді, оскільки ви вимикаєте функцію EF6, яка включена за замовчуванням, і цей фрагмент коду може порушити інші частини програми. Ви повинні пояснити, що це робить і які наслідки це має.
Ель Мак

@ElMac Ви праві, але якщо нам ця функція не потрібна, то чому б не вдалося скористатися цим рішенням?
Санджай Нішад

@SanjayNishad Я не заперечую, якщо ця функція вам не потрібна. Мова йде лише про користувачів, які не знають, що вони відключають.
El Mac

6

Ви також можете застосувати атрибут до властивості. [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...    
}

Сподіваюся, що це допомагає, Джайанс


4

Щоб ігнорувати посилання на цикл і не їх серіалізувати глобально в 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);
        });
    }

2

Використовуйте це в WebApiConfig.csкласі:

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

2

Для мене мені довелося піти іншим маршрутом. Замість того, щоб намагатися виправити серіалізатор JSON.Net, мені довелося піти після ледачого завантаження в моєму контексті даних.

Я щойно додав це до свого базового сховища:

context.Configuration.ProxyCreationEnabled = false;

Об'єкт "контекст" - це параметр конструктора, який я використовую в своєму базовому сховищі, оскільки використовую введення залежності. Ви можете змінити властивість ProxyCreationEnabled де завгодно, натомість замість цього інстанціюйте свій контекст даних.

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


2

У мене був цей виняток, і моє робоче рішення легко і просто,

Ігноруйте властивість Referenced, додавши до нього атрибут JsonIgnore:

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

Скиньте властивість, коли ви його десеріалізуєте:

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

використовуючи Newtonsoft.Json;


Це Магія, яка мені потрібна. Розв’яжіть це[JsonIgnore]
saviour123

2

Команда:

Це працює з ASP.NET Core; Виклик вищезгаданому полягає в тому, як ви «встановили налаштування ігнорувати». Залежно від налаштування програми, це може бути досить складно. Ось що для мене спрацювало.

Це може бути розміщено у вашому загальнодоступному розділі ConfigureServices (сервіси IServiceCollection).

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

2

Люди вже говорили про те, що [JsonIgnore] додається до віртуальної власності в класі, наприклад:

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

Я також поділюсь іншим варіантом [JsonProperty (NullValueHandling = NullValueHandling.Ignore)], який вимикає властивість після серіалізації, лише якщо він є нульовим:

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


0

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

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

0

Мою проблему вирішено за допомогою налаштування налаштувань JsonSerializer:

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

0

Будь ласка, не забудьте використовувати метод очікування та асинхронізацію у вашому методі. Ви можете отримати цю помилку, якщо ваш об’єкт неправильно серіалізований.


0

Я зіткнувся з тією самою проблемою, і я спробував за допомогою JsonSetting ігнорувати помилку самопосилання, якусь свою роботу, поки я не отримав клас, який дуже глибоко посилається на мене, і мій процес з точки дотику висить на значення запису Json.

Моя проблема

    public partial class Company : BaseModel
{
    public Company()
    {
        CompanyUsers = new HashSet<CompanyUser>();
    }

    public string Name { get; set; }

    public virtual ICollection<CompanyUser> CompanyUsers { get; set; }
}

public partial class CompanyUser
{
    public int Id { get; set; }
    public int CompanyId { get; set; }
    public int UserId { get; set; }

    public virtual Company Company { get; set; }

    public virtual User User { get; set; }
}

public partial class User : BaseModel
{
    public User()
    {
        CompanyUsers = new HashSet<CompanyUser>();
    }

    public string DisplayName { get; set; }
    public virtual ICollection<CompanyUser> CompanyUsers { get; set; }

}

Проблему ви можете бачити в класі користувача, посилаючись на CompanyUser клас який є самопосиланням.

Тепер я закликаю метод GetAll, який включає всі реляційні властивості.

cs.GetAll("CompanyUsers", "CompanyUsers.User");

На цьому етапі мій процес DotNetCore висить на Виконання JsonResult, значення написання ... і ніколи не прийде. У своєму Startup.cs я вже встановив JsonOption. Чомусь EFCore включає вкладене майно, яке я не прошу надавати Ef.

    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

очікувана поведінка повинна бути такою

Ей, EfCore, будь ласка, будь ласка, включіть дані "CompanyUsers" також у мій клас компанії, щоб я міг легко отримати доступ до даних.

тоді

Ей, EfCore, чи можете ви також включити дані "CompanyUsers.User" , щоб я міг легко отримати доступ до таких даних, як ця Company.CompanyUsers.First ().

на цьому етапі я повинен отримати лише це "Company.CompanyUsers.First (). User.DisplayName", і він не повинен давати мені Company.CompanyUsers.First (). User.CompanyUsers, що викликає проблему самопосилання; Технічно це не повинно давати мені User.CompanyUsers як CompanyUsers - навігаційне властивість. Але EfCore дуже схвильований і дарує мені User.CompanyUsers .

Отже, я вирішив написати метод розширення для того, щоб властивість було виключено з об'єкта (це фактично не виключає, що просто встановити властивість на нуль). Мало того, що він також буде працювати і над властивостями масиву. нижче - код, який я також хочу експортувати пакунок nuget для інших користувачів (не впевнений, чи це комусь навіть допомагає). Причина проста, тому що я лінивий писати .Select (n => new {n.p1, n.p2}); Я просто не хочу писати заяву select, щоб виключити лише 1 властивість!

Це не найкращий код (я його оновлюю на деякому етапі), як я писав поспіхом, і хоча це може допомогти тому, хто хоче виключити (встановити нуль) в об'єкті також з масивами.

    public static class PropertyExtensions
{
    public static void Exclude<T>(this T obj, Expression<Func<T, object>> expression)
    {
        var visitor = new PropertyVisitor<T>();
        visitor.Visit(expression.Body);
        visitor.Path.Reverse();
        List<MemberInfo> paths = visitor.Path;
        Action<List<MemberInfo>, object> act = null;

        int recursiveLevel = 0;
        act = (List<MemberInfo> vPath, object vObj) =>
        {

            // set last propert to null thats what we want to avoid the self-referencing error.
            if (recursiveLevel == vPath.Count - 1)
            {
                if (vObj == null) throw new ArgumentNullException("Object cannot be null");

                vObj.GetType().GetMethod($"set_{vPath.ElementAt(recursiveLevel).Name}").Invoke(vObj, new object[] { null });
                return;
            }

            var pi = vObj.GetType().GetProperty(vPath.ElementAt(recursiveLevel).Name);
            if (pi == null) return;
            var pv = pi.GetValue(vObj, null);
            if (pi.PropertyType.IsArray || pi.PropertyType.Name.Contains("HashSet`1") || pi.PropertyType.Name.Contains("ICollection`1"))
            {
                var ele = (IEnumerator)pv.GetType().GetMethod("GetEnumerator").Invoke(pv, null);

                while (ele.MoveNext())
                {
                    recursiveLevel++;
                    var arrItem = ele.Current;

                    act(vPath, arrItem);

                    recursiveLevel--;
                }

                if (recursiveLevel != 0) recursiveLevel--;
                return;
            }
            else
            {
                recursiveLevel++;
                act(vPath, pv);
            }

            if (recursiveLevel != 0) recursiveLevel--;

        };

        // check if the root level propert is array
        if (obj.GetType().IsArray)
        {
            var ele = (IEnumerator)obj.GetType().GetMethod("GetEnumerator").Invoke(obj, null);
            while (ele.MoveNext())
            {
                recursiveLevel = 0;
                var arrItem = ele.Current;

                act(paths, arrItem);
            }
        }
        else
        {
            recursiveLevel = 0;
            act(paths, obj);
        }

    }

    public static T Explode<T>(this T[] obj)
    {
        return obj.FirstOrDefault();
    }

    public static T Explode<T>(this ICollection<T> obj)
    {
        return obj.FirstOrDefault();
    }
}

вище клас розширення дасть вам можливість встановити властивість на нуль, щоб уникнути навіть масивів циклу самопосилань.

Expression Builder

    internal class PropertyVisitor<T> : ExpressionVisitor
{
    public readonly List<MemberInfo> Path = new List<MemberInfo>();

    public Expression Modify(Expression expression)
    {
        return Visit(expression);
    }


    protected override Expression VisitMember(MemberExpression node)
    {
        if (!(node.Member is PropertyInfo))
        {
            throw new ArgumentException("The path can only contain properties", nameof(node));
        }

        Path.Add(node.Member);
        return  base.VisitMember(node);
    }
}

Використання:

Класи моделей

    public class Person
{
    public string Name { get; set; }
    public Address AddressDetail { get; set; }
}

public class Address
{
    public string Street { get; set; }
    public Country CountryDetail { get; set; }
    public Country[] CountryDetail2 { get; set; }
}

public class Country
{
    public string CountryName { get; set; }
    public Person[] CountryDetail { get; set; }
}

Дамські дані

           var p = new Person
        {
            Name = "Adeel Rizvi",
            AddressDetail = new Address
            {
                Street = "Sydney",
                CountryDetail = new Country
                {
                    CountryName = "AU"
                }
            }
        };

        var p1 = new Person
        {
            Name = "Adeel Rizvi",
            AddressDetail = new Address
            {
                Street = "Sydney",
                CountryDetail2 = new Country[]
                {
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A1" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A2" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A3" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A4" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A5" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A6" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A7" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A8" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A9" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A1" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A2" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A3" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A4" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A5" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A6" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A7" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A8" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },
                    new Country{ CountryName = "AU", CountryDetail = new Person[]{ new Person { Name = "A9" }, new Person { Name = "A1" }, new Person { Name = "A1" } } },

                }
            }
        };

Випадки:

Випадок 1: Виключіть лише властивість без жодного масиву

p.Exclude(n => n.AddressDetail.CountryDetail.CountryName);

Випадок 2: Виключіть властивість за допомогою 1 масиву

p1.Exclude(n => n.AddressDetail.CountryDetail2.Explode().CountryName);

Випадок 3: Виключіть властивість за допомогою 2 вкладених масивів

p1.Exclude(n => n.AddressDetail.CountryDetail2.Explode().CountryDetail.Explode().Name);

Випадок 4: Запит EF GetAll With Includes

var query = cs.GetAll("CompanyUsers", "CompanyUsers.User").ToArray();
query.Exclude(n => n.Explode().CompanyUsers.Explode().User.CompanyUsers);
return query;

Ви помітили, що метод Explode () - це також метод розширення лише для того, щоб наш конструктор виразів міг отримати властивість з властивості масиву. Щоразу, коли є властивість масиву, використовуйте .Explode (). YourPropertyToExclude або .Explode (). Properties1.MyArrayProperty.Explode (). MyStupidProperty . Наведений вище код допомагає мені уникнути самовідсилення настільки глибоко, наскільки я хочу. Тепер я можу використовувати GetAll та виключити властивість, яку я не хочу; не хочу!

Дякую, що прочитали цей великий пост!


-1

Бо не циклічно це працювало для мене-
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,

Я все вирішив тут - серіалізація дітей Entity Framework за допомогою .Net Core 2 WebAPI https://gist.github.com/Kaidanov/f9ad0d79238494432f32b8407942c606

Будемо вдячні за будь-які зауваження. можливо, хтось може ним скористатися колись.


-1

C # код:

            var jsonSerializerSettings = new JsonSerializerSettings
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
                PreserveReferencesHandling = PreserveReferencesHandling.Objects,
            };

            var jsonString = JsonConvert.SerializeObject(object2Serialize, jsonSerializerSettings);

            var filePath = @"E:\json.json";

            File.WriteAllText(filePath, jsonString);

Це по суті те саме керівництво, яке пропонується у високо оціненій відповіді @ DalSoft від восьми років тому, але з набагато меншими поясненнями.
Джеремі Кейні

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

-2

Мені сподобалося рішення, яке воно робить Application_Start() як у відповіді тут

Мабуть, я не зміг отримати доступ до об’єктів json в JavaScript, використовуючи конфігурацію в межах своєї функції, як у відповіді DalSoft, оскільки повернутий об’єкт мав "\ n \ r" по всьому (ключ, val) об'єкта.

У будь-якому випадку все, що працює, є чудовим (адже різні підходи працюють за різним сценарієм, грунтуючись на коментарях та запитаних запитаннях), хоча стандартний спосіб зробити це було б кращим, якщо має бути хороша документація, яка підтримує цей підхід.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.