Erro JSON.NET loop auto-referenciado detectado para o tipo

495

Tentei serializar a classe POCO gerada automaticamente a partir do Entity Data Model .edmx e quando usei

JsonConvert.SerializeObject 

Eu recebi o seguinte erro:

Erro O loop de auto-referência detectado para o tipo System.data.entity ocorre.

Como eu resolvo este problema?

NevenHuynh
fonte
quando você estiver usando o Linq e o MVC: stackoverflow.com/a/38241856
aDDin
ao usar o .NET Core 2: stackoverflow.com/a/48709134/4496145
Dave Skender
2
Esse erro aconteceu comigo, quando eu queria serializar o resultado de uma asyncchamada de método (a Task) e esqueci de prefixar a awaitinstrução.
Uwe Keim

Respostas:

485

Essa foi a melhor solução https://code.msdn.microsoft.com/Loop-Reference-handling-in-caaffaf7

Correção 1: ignorando a referência circular globalmente

(Eu escolhi / tentei este, como muitos outros)

O serializador json.net tem uma opção para ignorar referências circulares. Coloque o seguinte código no WebApiConfig.csarquivo:

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

A correção simples fará com que o serializador ignore a referência que causará um loop. No entanto, possui limitações:

  • Os dados perdem as informações de referência em loop
  • A correção se aplica apenas ao JSON.net
  • O nível de referências não pode ser controlado se houver uma cadeia de referência profunda

Se você deseja usar essa correção em um projeto ASP.NET que não seja da API, você pode adicionar a linha acima a Global.asax.cs, mas primeiro adicione:

var config = GlobalConfiguration.Configuration;

Se você quiser usar isso no projeto .Net Core , poderá alterar Startup.cscomo:

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

Correção 2: preservando a referência circular globalmente

Essa segunda correção é semelhante à primeira. Apenas mude o código para:

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

A forma dos dados será alterada após a aplicação dessa configuração.

[
   {
      "$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"
   }
]

O $ id e o $ ref mantêm todas as referências e tornam o gráfico do objeto nivelado, mas o código do cliente precisa saber a mudança de forma para consumir os dados e se aplica apenas ao serializador JSON.NET.

Correção 3: ignorar e preservar atributos de referência

Essa correção é decorar atributos na classe de modelo para controlar o comportamento de serialização no nível do modelo ou da propriedade. Para ignorar a propriedade:

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

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

JsonIgnore é para JSON.NET e IgnoreDataMember é para XmlDCSerializer. Para preservar a referência:

 // 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)]é para JSON.NET e [DataContract(IsReference = true)]é para XmlDCSerializer. Observe que: após aplicar DataContractna classe, você precisa adicionar DataMemberàs propriedades que deseja serializar.

Os atributos podem ser aplicados no serializador json e xml e fornecem mais controles na classe de modelo.

Bishoy Hanna
fonte
7
Correção 3 é trabalhado para mim. Simplesmente remova os atributos DataContract e DataMember e coloque JsonObject (IsReference = true) nos DTOs. E isso funciona. Obrigado.
maestro
1
tente este GlobalConfiguration.Configuration
Bishoy Hanna 4/14
1
Fix 3 tem a vantagem de que ele funciona em código de cliente onde não há GlobalConfiguration
dumbledad
1
@BishoyHanna, você pode editar sua resposta para permitir que ela seja usada em aplicativos ASP.NET normais? Você pode usar minha edição sugerida: stackoverflow.com/review/suggested-edits/17797683
NH.
2
Usando [JsonIgnore]acima o atributo funcionou para mim.
Nathan Beck
467

Use JsonSerializerSettings

  • ReferenceLoopHandling.Error(padrão) ocorrerá erro se um loop de referência for encontrado. É por isso que você recebe uma exceção.
  • ReferenceLoopHandling.Serialize é útil se os objetos estiverem aninhados, mas não indefinidamente.
  • ReferenceLoopHandling.Ignore não serializará um objeto se ele próprio for um objeto filho.

Exemplo:

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

Se você precisar serializar um objeto aninhado indefinidamente, poderá usar PreserveObjectReferences para evitar uma StackOverflowException.

Exemplo:

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

Escolha o que faz sentido para o objeto que você está serializando.

Referência http://james.newtonking.com/json/help/

DalSoft
fonte
66
Encontrei o erro ao serializar uma tabela de dados. I utilizado ReferenceLoopHandling = ReferenceLoopHandling.Ignorepara que ele funcione
8
Se houver loops de referência nos dados, o uso ReferenceLoopHandling.Serializefará com que o serializador entre em um loop recursivo infinito e transbordará a pilha.
Brian Rogers
1
Corrigir. Como a pergunta é sobre um modelo EF, também é uma preocupação válida. Alterado para fornecer todas as opções disponíveis.
DalSoft
1
Eu encontrei esse mesmo erro ao tentar serializar um objeto ... no entanto, o objeto não tem nenhuma referência além de um tipo de enum.
Marin
1
para mim, a EF é a principal causa desse problema, porque as entidades auto-referenciadas estão em todo lugar.
Teoman shipahi
58

A correção é ignorar as referências de loop e não serializá-las. Esse comportamento é especificado em JsonSerializerSettings.

SolteiroJsonConvert com sobrecarga:

JsonConvert.SerializeObject(YourObject, Formatting.Indented,
    new JsonSerializerSettings() {
        ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
    }
);

Configuração global com código Application_Start()em Global.asax.cs:

JsonConvert.DefaultSettings = () => new JsonSerializerSettings {
     Formatting = Newtonsoft.Json.Formatting.Indented,
     ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
};

Referência: https://github.com/JamesNK/Newtonsoft.Json/issues/78

smockle
fonte
Por que você define o formato como recuado quando faz a configuração global?
Murphybro2
Absolutamente o que precisávamos para resolver esse problema (descoberto durante uma implantação)! Você da man .... obrigado por nos poupar tempo !!
Ryan Eastabrook
Resolvi meu issus adicionando "JsonConvert.DefaultSettings" = () => new JsonSerializerSettings {....} na classe "Startup.cs"
Beldi Anouar
45

A maneira mais simples de fazer isso é instalar o Json.NET a partir do nuget e adicionar o [JsonIgnore]atributo à propriedade virtual na classe, por exemplo:

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

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

Embora atualmente, eu criei um modelo com apenas as propriedades pelas quais desejo passar, para que fique mais claro, não inclua coleções indesejadas e não perco minhas alterações ao reconstruir os arquivos gerados ...

Sam Jones
fonte
3
Melhor resposta usando Newton JSON
Aizen
21

No .NET Core 1.0, você pode definir isso como uma configuração global no seu arquivo 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));
        });
    }
Caleb
fonte
Mas, neste caso, se eu quiser estar ciente de que essa propriedade é Ignorada, não receberei nenhuma exceção.
Mayer Spitzer
10

Se você estiver usando o .NET Core 2.x, atualize a seção ConfigureServices em 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
        );

    ...
    }

Se você estiver usando o .NET Core 3.x sem MVC, seria:

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

Esse tratamento de loop de referência é quase obrigatório se você estiver usando o Entity Framework e o padrão de design do primeiro banco de dados.

Dave Skender
fonte
2
e se eu não usar services.AddMvc()?
prisar
2
isso é uma prática ruim?
Renan Coelho
À primeira vista, você pode pensar que essa é uma prática ruim, pois pode substituir o "design intencional" de evitar o antigo problema do "loop infinito". No entanto, se você pensar em seus casos de uso para classes, pode ser necessário que eles se refiram. Por exemplo, convém acessar Árvores> Frutas e também Frutas> Árvores.
Dave Skender
Além disso, se você estiver usando um padrão de design primeiro do banco de dados com algo como o Entity Framework, dependendo de como configurar suas chaves estrangeiras no banco de dados, ele criará automaticamente essas referências cíclicas; portanto, você precisará usar essa configuração se quiser estamos fazendo engenharia reversa em suas aulas.
Dave Skender
9

Para serializar-nos em NEWTONSOFTJSON quando houver um problema de loop, no meu caso, não precisei modificar global.asax ou apiconfig. Eu apenas uso JsonSerializesSettings ignorando o tratamento de loop.

JsonSerializerSettings jss = new JsonSerializerSettings();
jss.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
var lst = db.shCards.Where(m => m.CardID == id).ToList();
string json = JsonConvert.SerializeObject(lst, jss);
Carlos Barini
fonte
1
Se alguém veio aqui para um um forro para ir na janela do relógio por isso é pesquisável texto:Newtonsoft.Json.JsonConvert.SerializeObject(objToSerialize, new Newtonsoft.Json.JsonSerializerSettings() {ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore});
Graham
8

Podemos adicionar essas duas linhas no construtor de classe DbContext para desativar o loop de auto-referência, como

public TestContext()
        : base("name=TestContext")
{
    this.Configuration.LazyLoadingEnabled = false;
    this.Configuration.ProxyCreationEnabled = false;
}
Sanjay Nishad
fonte
Este é um dos mais simples e funciona como um encanto . Votado, muito obrigado ...
Murat Yıldız
Como escrevi na outra pergunta: Não gosto desse tipo de resposta porque você está desativando um recurso do EF6 que está ativado por padrão e esse trecho de código pode quebrar outras partes do programa. Você deve explicar o que isso faz e que tipo de repercussão isso tem.
El Mac
@ ElMac você está certo, mas se não precisamos desse recurso, por que não podemos usar esta solução?
Sanjay Nishad
@SanjayNishad Não me importo se você não precisar do recurso. É apenas sobre os usuários que não sabem o que estão desativando.
El El
6

Você também pode aplicar um atributo à propriedade. O [JsonProperty( ReferenceLoopHandling = ... )]atributo é bem adequado para isso.

Por exemplo:

/// <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...    
}

Espero que ajude, Jaans

Jaans
fonte
4

Para ignorar as referências de loop e não serializá-las globalmente no MVC 6, use o seguinte em 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
fonte
2

Use isso na WebApiConfig.csaula:

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

Para mim, tive que seguir uma rota diferente. Em vez de tentar consertar o serializador JSON.Net, tive que ir atrás do Lazy Loading no meu datacontext.

Acabei de adicionar isso ao meu repositório base:

context.Configuration.ProxyCreationEnabled = false;

O objeto "context" é um parâmetro construtor que eu uso no meu repositório base porque eu uso injeção de dependência. Você pode alterar a propriedade ProxyCreationEnabled em qualquer lugar em que instanciar seu datacontext.

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

Xipooo
fonte
2

Eu tive essa exceção e minha solução de trabalho é fácil e simples,

Ignore a propriedade Referenciada incluindo o atributo JsonIgnore nela:

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

Redefina a propriedade quando você a desserializar:

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

using Newtonsoft.Json;

Mayer Spitzer
fonte
Esta é a mágica que eu preciso. Resolvê-lo[JsonIgnore]
saviour123
2

Equipe:

Isso funciona com o ASP.NET Core; O desafio para o acima é como você 'define a configuração para ignorar'. Dependendo de como você configura seu aplicativo, pode ser bastante desafiador. Aqui está o que funcionou para mim.

Isso pode ser colocado na sua seção pública ConfigureServices (serviços IServiceCollection).

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

As pessoas já falaram sobre [JsonIgnore] ser adicionado à propriedade virtual na classe, por exemplo:

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

Também compartilharei outra opção, [JsonProperty (NullValueHandling = NullValueHandling.Ignore)], que omite a propriedade da serialização apenas se for nula:

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

Para o .NET Core 3.0, atualize a classe Startup.cs conforme mostrado abaixo.

public void ConfigureServices(IServiceCollection services)
{
...

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

...
}

Consulte: https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-core-3-0-preview-5/

Jimmy
fonte
0

Simplesmente coloque Configuration.ProxyCreationEnabled = false;dentro do arquivo de contexto; Isto resolverá o problema.

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

Meu problema resolvido com a configuração personalizada JsonSerializerSettings:

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

Certifique-se também de usar wait e async no seu método. Você pode obter esse erro se seu objeto não for serializado corretamente.

maxspan
fonte
0

Eu estava enfrentando o mesmo problema e tentei usar o JsonSetting para ignorar o erro de auto-referência. Isso meio que funcionou até que eu recebi uma classe que se auto-referenciava muito profundamente e meu processo dot-net depende do valor de gravação do Json.

Meu problema

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

}

Você pode ver o problema na classe User, que está se referindo à classe CompanyUser, que é uma auto-referência.

Agora, estou chamando o método GetAll, que inclui todas as propriedades relacionais.

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

Nesse estágio, meu processo DotNetCore fica travado na execução do JsonResult, escrevendo valor ... e nunca chegando. No meu Startup.cs, eu já configurei o JsonOption. Por alguma razão, o EFCore está incluindo propriedades aninhadas que não estou pedindo ao Ef para fornecer.

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

comportamento esperado deve ser este

Ei, EfCore, você pode incluir também os dados "CompanyUsers" na minha classe Company, para que eu possa acessar facilmente os dados.

então

Hey EfCore, você também pode incluir os dados "CompanyUsers.User" , para que eu possa acessar facilmente os dados como este Company.CompanyUsers.First (). User.DisplayName

nesse estágio, eu só deveria obter esse "Company.CompanyUsers.First (). User.DisplayName" e ele não deve me fornecer Company.CompanyUsers.First (). User.CompanyUsers que causam o problema de auto-referência; Tecnicamente, ele não deve me fornecer User.CompanyUsers como CompanyUsers é uma propriedade de navegação. Mas, o EfCore fica muito animado e me oferece User.CompanyUsers .

Então, decidi escrever um método de extensão para a propriedade a ser excluída do objeto (na verdade, não está excluindo, está apenas configurando a propriedade como nula). Não apenas isso também funcionará nas propriedades da matriz. Abaixo está o código. Também vou exportar o pacote nuget para outros usuários (não tenho certeza se isso ajuda alguém). A razão é simples porque tenho preguiça de escrever .Select (n => new {n.p1, n.p2}); Eu só não quero escrever a instrução select para excluir apenas uma propriedade!

Este não é o melhor código (atualizarei em algum momento), como escrevi com pressa e, embora isso possa ajudar alguém que queira excluir (definir nulo) no objeto com matrizes também.

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

A classe de extensão acima permitirá que você defina a propriedade como nula para evitar o loop de auto-referência e até as matrizes.

Construtor de Expressões

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

Usos:

Classes de modelo

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

Dados fictícios

           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" } } },

                }
            }
        };

Casos:

Caso 1: excluir apenas propriedade sem nenhuma matriz

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

Caso 2: excluir propriedade com 1 matriz

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

Caso 3: excluir propriedade com 2 matrizes aninhadas

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

Caso 4: Consulta EF GetAll com Inclui

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

Você notou que o método Explode () também é um método de extensão apenas para o nosso construtor de expressões obter a propriedade da propriedade da matriz. Sempre que houver uma propriedade de matriz, use .Explode (). YourPropertyToExclude ou .Explode (). Property1.MyArrayProperty.Explode (). MyStupidProperty . O código acima me ajuda a evitar a auto-referência tão profunda quanto eu quero. Agora eu posso usar GetAll e excluir a propriedade que eu não quero!

Obrigado por ler este grande post!

Adeel Rizvi
fonte
-1

Por não repetir isso funcionou para mim-
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,

Resolvi tudo aqui - serialização de filhos do Entity Framework com .Net Core 2 WebAPI https://gist.github.com/Kaidanov/f9ad0d79238494432f32b8407942c606

Apreciará quaisquer observações. talvez alguém possa usá-lo em algum momento.

Tzvi Gregory Kaidanov
fonte
-1

Código 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);
Lilach Rayzin
fonte
Essa é essencialmente a mesma orientação oferecida na resposta altamente avaliada pela @ DalSoft de oito anos atrás, mas com muito menos explicações.
Jeremy Caney
Espero que isso resolva o problema, mas por favor, inclua uma explicação do seu código para que o usuário tenha uma compreensão perfeita do que ele / ela realmente deseja.
Jaimil Patel
-2

Eu gostei da solução que faz isso Application_Start()como na resposta aqui

Aparentemente, não consegui acessar os objetos json no JavaScript usando a configuração dentro da minha função, como na resposta da DalSoft, pois o objeto retornado tinha "\ n \ r" em toda a (chave, val) do objeto.

De qualquer forma, tudo o que funciona é ótimo (porque abordagens diferentes funcionam em cenários diferentes, com base nos comentários e perguntas), embora uma maneira padrão de fazê-lo seja preferível com alguma boa documentação que apóie a abordagem.

rey_coder
fonte