Обнаружена ошибка JSON.NET. Самостоятельная ссылка на тип

495

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

JsonConvert.SerializeObject 

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

Произошла ошибка Самостоятельная ссылка на тип System.data.entity.

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

NevenHuynh
источник
когда вы используете Linq и MVC: stackoverflow.com/a/38241856
aDDin
при использовании .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
  • Уровень ссылок не может контролироваться, если существует глубокая цепочка ссылок

Если вы хотите использовать это исправление в не 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, что дает больше возможностей для управления классом модели.

Бишой ханна
источник
7
Исправление 3 работает для меня. Просто удалите атрибуты DataContract и DataMember и поместите JsonObject (IsReference = true) в DTO. И это работает. Спасибо.
Маэстро
1
попробуйте это GlobalConfiguration.Configuration
Bishoy Hanna
1
Преимущество Fix 3 заключается в том, что он работает с клиентским кодом, в котором нет
GlobalConfiguration
1
@BishoyHanna, можете ли вы отредактировать свой ответ, чтобы разрешить его использование в обычных приложениях ASP.NET? Вы можете использовать мое предложенное редактирование: stackoverflow.com/review/suggested-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/

DalSoft
источник
66
Я столкнулся с ошибкой при сериализации данных. Я использовал ReferenceLoopHandling = ReferenceLoopHandling.Ignoreдля его работы
8
Если в данных есть ссылочные циклы, использование ReferenceLoopHandling.Serializeзаставит сериализатор войти в бесконечный рекурсивный цикл и переполнить стек.
Брайан Роджерс
1
Правильный. Так как вопрос о модели EF также актуален. Изменено, чтобы дать все доступные варианты.
DalSoft
1
Я столкнулся с этой же ошибкой при попытке сериализации объекта ... однако, объект не имеет никаких ссылок, кроме типа enum ..
Marin
1
для меня EF является основной причиной этой проблемы, потому что сущности, на которые ссылаются сами, повсюду.
Теоман Шипахи
58

Исправление состоит в том, чтобы игнорировать ссылки на циклы, а не сериализовать их. Это поведение указано в 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

smockle
источник
Почему вы устанавливаете формат с отступом, когда вы делаете глобальные настройки?
Murphybro2
Абсолютно то, что нам нужно было решить эту проблему (обнаружен во время развертывания)! Вы, да, человек .... спасибо, что сэкономили нам время !!
Райан Истабрук
Я решил свою проблему, добавив «JsonConvert.DefaultSettings» = () => новый JsonSerializerSettings {....} в классе «Startup.cs»
Бельди Ануар
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
Айзен
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

Чтобы сериализовать нас в 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, чтобы отключить цикл Self-ссылки, например

public TestContext()
        : base("name=TestContext")
{
    this.Configuration.LazyLoadingEnabled = false;
    this.Configuration.ProxyCreationEnabled = false;
}
Санджай Нишад
источник
Это один из самых простых и работает как шарм . Проголосовал, большое спасибо ...
Мурат Йылдыз
Как я уже писал в другом вопросе: мне не нравятся ответы такого типа, потому что вы отключаете функцию EF6, которая включена по умолчанию, и этот фрагмент кода может нарушить работу других частей программы. Вы должны объяснить, что это делает и какие последствия это имеет.
Эль Мак,
@ ElMac вы правы, но если нам не нужна эта функция, почему бы не использовать это решение?
Санджай Нишад
@SanjayNishad Я не против, если вам не нужна эта функция. Речь идет о пользователях, которые не знают, что они отключают.
Эль Мак,
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...    
}

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

Jaans
источник
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);
        });
    }
GerardBeckerleg
источник
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;

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

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

Xipooo
источник
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).

services.AddMvc().AddJsonOptions(opt => 
        { 
      opt.SerializerSettings.ReferenceLoopHandling =
      Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        });
FlyingV
источник
2

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

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

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

[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public virtual Project Project { get; set; }
Али Раза
источник
0

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

public demEntities()
    : base("name=demEntities")
{
    Configuration.ProxyCreationEnabled = false;
}
fraka
источник
0

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

services.AddMvc(
  // ...
               ).AddJsonOptions(opt =>
                 {
                opt.SerializerSettings.ReferenceLoopHandling =
                    Newtonsoft.Json.ReferenceLoopHandling.Serialize;
                opt.SerializerSettings.PreserveReferencesHandling =
                    Newtonsoft.Json.PreserveReferencesHandling.Objects;
                 });
AminGolmahalle
источник
0

Также убедитесь, что вы используете await и async в вашем методе. Вы можете получить эту ошибку, если ваш объект не сериализован должным образом.

maxspan
источник
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; }

}

Вы можете увидеть проблему в классе User, который ссылается на 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 (). User.DisplayName

на этом этапе я должен получить только этот «Company.CompanyUsers.First (). User.DisplayName», и он не должен давать мне Company.CompanyUsers.First (). User.CompanyUsers, который вызывает проблему с самоссылкой ; Технически это не должно давать мне User.CompanyUsers, так как CompanyUsers является навигационным свойством. Но EfCore очень взволнован и дает мне User.CompanyUsers .

Итак, я решил написать метод расширения для свойства, которое должно быть исключено из объекта (это на самом деле не исключает, а просто устанавливает для свойства значение null). Мало того, что он также будет работать со свойствами массива. ниже приведен код, который я также собираюсь экспортировать в пакет nuget для других пользователей (не уверен, поможет ли это кому-нибудь). Причина проста, потому что мне лень писать .Select (n => new {n.p1, n.p2});Я просто не хочу писать оператор выбора, чтобы исключить только 1 свойство!

Это не лучший код (я обновлю его на каком-то этапе), поскольку я написал на скорую руку, и хотя это может помочь тем, кто хочет исключить (установить значение NULL) в объекте также с массивами.

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

Приведенный выше класс расширений даст вам возможность установить для свойства значение null, чтобы избежать появления в цикле самоссылки даже массивов.

Построитель выражений

    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 с включениями

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

Вы заметили, что метод Explode () также является методом расширения только для нашего построителя выражений, чтобы получить свойство из свойства массива. Когда есть свойство массива, используйте .Explode (). YourPropertyToExclude или .Explode (). Property1.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» по всему (key, val) объекта.

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

rey_coder
источник