Error de JSON.NET Se detectó un bucle de referencia automática para el tipo

495

Traté de serializar la clase POCO que se generó automáticamente a partir de Entity Data Model .edmx y cuando usé

JsonConvert.SerializeObject 

Tuve el siguiente error:

Error Se produce un bucle de auto referencia para el tipo System.data.entity.

¿Cómo resuelvo este problema?

NevenHuynh
fuente
1
posible duplicado de Serializar una a muchas relaciones en Json.net
bkaid
cuando usa Linq y MVC: stackoverflow.com/a/38241856
aDDin el
cuando se usa .NET Core 2: stackoverflow.com/a/48709134/4496145
Dave Skender el
2
Este error me ocurrió cuando quería serializar el resultado de una asyncllamada al método (a Task) y olvidé prefijar la awaitdeclaración.
Uwe Keim

Respuestas:

485

Esa fue la mejor solución https://code.msdn.microsoft.com/Loop-Reference-handling-in-caaffaf7

Solución 1: ignorar la referencia circular globalmente

(He elegido / probado este, como muchos otros)

El serializador json.net tiene una opción para ignorar las referencias circulares. Ponga el siguiente código en el WebApiConfig.csarchivo:

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

La solución simple hará que el serializador ignore la referencia, lo que causará un bucle. Sin embargo, tiene limitaciones:

  • Los datos pierden la información de referencia de bucle.
  • La solución solo se aplica a JSON.net
  • El nivel de referencias no se puede controlar si hay una cadena de referencia profunda

Si desea utilizar esta solución en un proyecto ASP.NET que no sea api, puede agregar la línea anterior Global.asax.cs, pero primero agregue:

var config = GlobalConfiguration.Configuration;

Si desea usar esto en el proyecto .Net Core , puede cambiarlo Startup.cscomo:

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

Solución 2: preservar la referencia circular a nivel mundial

Esta segunda solución es similar a la primera. Simplemente cambie el código a:

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

La forma de los datos cambiará después de aplicar esta configuración.

[
   {
      "$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 y $ ref mantienen todas las referencias y hacen que el nivel del gráfico del objeto sea plano, pero el código del cliente necesita conocer el cambio de forma para consumir los datos y solo se aplica al serializador JSON.NET.

Solución 3: ignorar y preservar los atributos de referencia

Esta solución es decorar atributos en la clase de modelo para controlar el comportamiento de serialización a nivel de modelo o propiedad. Para ignorar la propiedad:

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

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

JsonIgnore es para JSON.NET e IgnoreDataMember es para XmlDCSerializer. Para preservar la referencia:

 // 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)]es para JSON.NET y [DataContract(IsReference = true)]es para XmlDCSerializer. Tenga en cuenta que: después de aplicar DataContracten la clase, debe agregar DataMembera las propiedades que desea serializar.

Los atributos se pueden aplicar en el serializador json y xml y ofrece más controles en la clase de modelo.

Bishoy Hanna
fuente
77
La solución 3 me funcionó. Simplemente elimine los atributos DataContract y DataMember y coloque JsonObject (IsReference = true) en los DTO. Y funciona. Gracias.
maestro
1
prueba esta GlobalConfiguration.Configuration
Bishoy Hanna
1
La corrección 3 tiene la ventaja de que funciona en el código del cliente donde no hay GlobalConfiguration
dumbledad
1
@BishoyHanna, ¿puede editar su respuesta para permitir que se use desde aplicaciones ASP.NET normales? Puede usar mi edición sugerida: stackoverflow.com/review/suggested-edits/17797683
NH.
2
Usar [JsonIgnore]el atributo anterior funcionó para mí.
Nathan Beck
467

Utilice JsonSerializerSettings

  • ReferenceLoopHandling.Error(predeterminado) producirá un error si se encuentra un bucle de referencia. Es por eso que obtienes una excepción.
  • ReferenceLoopHandling.Serialize es útil si los objetos están anidados pero no indefinidamente.
  • ReferenceLoopHandling.Ignore no serializará un objeto si es un objeto hijo de sí mismo.

Ejemplo:

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

Si tiene que serializar un objeto anidado indefinidamente, puede usar PreserveObjectReferences para evitar una excepción StackOverflowException.

Ejemplo:

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

Elija lo que tenga sentido para el objeto que está serializando.

Referencia http://james.newtonking.com/json/help/

DalSoft
fuente
66
Encontré el error al serializar una tabla de datos. Solía ReferenceLoopHandling = ReferenceLoopHandling.Ignorefuncionar
8
Si hay bucles de referencia en los datos, el uso ReferenceLoopHandling.Serializeprovocará que el serializador entre en un bucle recursivo infinito y desborde la pila.
Brian Rogers
1
Correcto. Como la pregunta es sobre un modelo EF, también es una preocupación válida. Modificado para dar todas las opciones disponibles.
DalSoft
1
He encontrado este mismo error al intentar serializar un objeto ... sin embargo, el objeto no tiene más referencias que un tipo de enumeración ...
Marin
1
para mí EF es la causa principal de este problema porque las entidades autorreferenciadas están por todas partes.
Teoman shipahi
58

La solución es ignorar las referencias de bucle y no serializarlas. Este comportamiento se especifica en JsonSerializerSettings.

IndividualJsonConvert con sobrecarga:

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

Configuración global con código Application_Start()en Global.asax.cs:

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

Referencia: https://github.com/JamesNK/Newtonsoft.Json/issues/78

smockle
fuente
¿Por qué establece el formato en sangrado cuando realiza la configuración global?
Murphybro2
¡Absolutamente lo que necesitábamos para resolver este problema (descubierto durante una implementación)! Da da man .... gracias por ahorrarnos tiempo !!
Ryan Eastabrook
Resolví mi problema agregando "JsonConvert.DefaultSettings" = () => new JsonSerializerSettings {....} en la clase "Startup.cs"
Beldi Anouar
45

La forma más sencilla de hacer esto es instalar Json.NET desde nuget y agregar el [JsonIgnore]atributo a la propiedad virtual en la clase, por ejemplo:

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

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

Aunque en estos días, creo un modelo con solo las propiedades que quiero que pasen para que sea más ligero, no incluya colecciones no deseadas y no pierdo mis cambios cuando reconstruyo los archivos generados ...

Sam Jones
fuente
3
La mejor respuesta usando Newton JSON
Aizen
21

En .NET Core 1.0, puede establecer esto como una configuración global en su archivo 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
fuente
Pero en este caso, si quiero saber que esta propiedad se ignora, no obtendré ninguna excepción.
Mayer Spitzer el
10

Si está utilizando .NET Core 2.x, actualice su sección ConfigureServices en 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
        );

    ...
    }

Si está utilizando .NET Core 3.x sin MVC, sería:

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

Este manejo del bucle de referencia es casi obligatorio si está utilizando Entity Framework y el patrón de diseño de base de datos primero.

Dave Skender
fuente
2
¿Qué pasa si no lo uso services.AddMvc()?
prisar
2
¿Es esta una mala práctica?
Renan Coelho
A primera vista, puede pensar que esta es una mala práctica, ya que podría anular el "diseño intencional" de evitar el viejo problema del "bucle infinito". Sin embargo, si piensa en sus casos de uso para las clases, es posible que necesite que se refieran entre sí. Por ejemplo, es posible que desee acceder a Árboles> Frutas y también a Frutas> Árboles.
Dave Skender
Además, si está utilizando un patrón de diseño de base de datos primero con algo como Entity Framework, dependiendo de cómo configure sus claves foráneas en su base de datos, creará automáticamente estas referencias cíclicas, por lo que tendrá que usar esta configuración si Estás haciendo ingeniería inversa en tus clases.
Dave Skender
9

Para serializar usin NEWTONSOFTJSON cuando tiene un problema de bucle, en mi caso no necesité modificar global.asax o apiconfig. Solo uso JsonSerializesSettings ignorando el manejo de 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);
Carlos Barini
fuente
1
Si alguien más vino aquí por un trazador de líneas para ir en la ventana del reloj, entonces se puede buscar texto:Newtonsoft.Json.JsonConvert.SerializeObject(objToSerialize, new Newtonsoft.Json.JsonSerializerSettings() {ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore});
Graham
8

Podemos agregar estas dos líneas al constructor de la clase DbContext para deshabilitar el bucle de referencia automática, como

public TestContext()
        : base("name=TestContext")
{
    this.Configuration.LazyLoadingEnabled = false;
    this.Configuration.ProxyCreationEnabled = false;
}
Sanjay Nishad
fuente
Este es uno de los más simples y funciona a las mil maravillas . Votado, muchas gracias ...
Murat Yıldız
Como escribí en la otra pregunta: no me gustan este tipo de respuestas porque está desactivando una función de EF6 que está habilitada de forma predeterminada y este fragmento de código puede romper otras partes del programa. Debe explicar qué hace esto y qué tipo de repercusiones tiene.
El Mac
@ElMac tiene razón, pero si no necesitamos esa función, ¿por qué no podemos usar esta solución?
Sanjay Nishad
@SanjayNishad No me importa si no necesitas la función. Se trata solo de los usuarios que no saben lo que están desactivando.
El Mac
6

También puede aplicar un atributo a la propiedad. El [JsonProperty( ReferenceLoopHandling = ... )]atributo se adapta bien a esto.

Por ejemplo:

/// <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 ayude, Jaans

Jaans
fuente
4

Para ignorar las referencias de bucle y no serializarlas globalmente en MVC 6, use lo siguiente en 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
fuente
2

Use esto en WebApiConfig.csclase:

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

Para mí tuve que tomar una ruta diferente. En lugar de tratar de arreglar el serializador JSON.Net tuve que ir después de Lazy Loading en mi contexto de datos.

Acabo de agregar esto a mi repositorio base:

context.Configuration.ProxyCreationEnabled = false;

El objeto "contexto" es un parámetro constructor que uso en mi repositorio base porque uso la inyección de dependencia. En su lugar, puede cambiar la propiedad ProxyCreationEnabled en cualquier lugar donde cree una instancia de su contexto de datos.

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

Xipooo
fuente
2

Tuve esta excepción y mi solución de trabajo es fácil y simple,

Ignore la propiedad referenciada agregando el atributo JsonIgnore:

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

Restablezca la propiedad cuando la deserialice:

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

usando Newtonsoft.Json;

Mayer Spitzer
fuente
Esta es la magia que necesito. Resolverlo[JsonIgnore]
saviour123
2

Equipo:

Esto funciona con ASP.NET Core; El desafío a lo anterior es cómo 'configura la configuración para ignorar'. Dependiendo de cómo configure su aplicación, puede ser bastante difícil. Esto es lo que funcionó para mí.

Esto se puede colocar en su sección de vacío público ConfigureServices (servicios IServiceCollection).

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

La gente ya ha hablado de que se agregó [JsonIgnore] a la propiedad virtual en la clase, por ejemplo:

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

También compartiré otra opción, [JsonProperty (NullValueHandling = NullValueHandling.Ignore)] que omite la propiedad de la serialización solo si es nula:

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

Simplemente colóquelo Configuration.ProxyCreationEnabled = false;dentro del archivo de contexto; Esto solucionará el problema.

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

Mi problema resuelto con la configuración personalizada JsonSerializerSettings:

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

Asegúrese también de usar wait y async en su método. Puede obtener este error si su objeto no está serializado correctamente.

maxspan
fuente
0

Estaba enfrentando el mismo problema e intenté usar JsonSetting para ignorar el error de autorreferencia que funciona un poco hasta que obtuve una clase que hace una autorreferencia muy profunda y mi proceso dot-net se cuelga del valor de escritura de Json.

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

}

Puede ver el problema en la clase de usuario que hace referencia a la clase CompanyUser , que es una referencia automática.

Ahora, estoy llamando al Método GetAll que incluye todas las propiedades relacionales.

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

En esta etapa, mi proceso DotNetCore se cuelga en Ejecutar JsonResult, escribiendo valor ... y nunca llega. En mi Startup.cs, ya configuré JsonOption. Por alguna razón, EFCore incluye propiedades anidadas que no le estoy pidiendo a Ef.

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

el comportamiento esperado debería ser este

Hola, EfCore, ¿podría incluir los datos de "CompanyUsers" también en mi clase de empresa para que pueda acceder fácilmente a los datos?

entonces

Hola, EfCore, ¿puedes incluir también los datos de "CompanyUsers.User" para que pueda acceder fácilmente a los datos como esta Company.CompanyUsers.First (). User.DisplayName

en esta etapa solo debería obtener este "Company.CompanyUsers.First (). User.DisplayName" y no debería darme Company.CompanyUsers.First (). User.CompanyUsers que causa el problema de autorreferencia; Técnicamente no debería darme User.CompanyUsers como CompanyUsers es una propiedad de navegación. Pero, EfCore se emociona mucho y me da User.CompanyUsers .

Entonces, decidí escribir un método de extensión para que la propiedad se excluya del objeto (en realidad no es excluyente, solo establece la propiedad en nulo). No solo eso también funcionará en las propiedades de la matriz. a continuación se muestra el código que también voy a exportar el paquete nuget para otros usuarios (no estoy seguro si esto incluso ayuda a alguien). La razón es simple porque soy demasiado vago para escribir .Seleccione (n => new {n.p1, n.p2}); ¡No quiero escribir una declaración select para excluir solo 1 propiedad!

Este no es el mejor código (lo actualizaré en algún momento) como lo he escrito rápidamente y aunque esto podría ayudar a alguien que quiera excluir (establecer nulo) en el objeto con matrices también.

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

la clase de extensión anterior le dará la capacidad de establecer la propiedad en nulo para evitar el bucle de autorreferencia incluso en matrices.

Generador de expresiones

    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:

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

Datos ficticios

           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 solo propiedades sin ninguna matriz

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

Caso 2: excluir propiedad con 1 matriz

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

Caso 3: excluir propiedad con 2 matrices anidadas

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

Caso 4: EF GetAll Query con incluye

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

Ha notado que el método Explode () también es un método de extensión solo para que nuestro generador de expresiones obtenga la propiedad de la propiedad de matriz. Siempre que haya una propiedad de matriz, use .Explode (). YourPropertyToExclude o .Explode (). Property1.MyArrayProperty.Explode (). MyStupidProperty . El código anterior me ayuda a evitar la autorreferencia tan profunda como quiero. ¡Ahora puedo usar GetAll y excluir la propiedad que no deseo!

¡Gracias por leer esta gran publicación!

Adeel Rizvi
fuente
-1

Por no repetir esto funcionó para mí
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,

Lo he resuelto todo aquí: serialización de niños de Entity Framework con .Net Core 2 WebAPI https://gist.github.com/Kaidanov/f9ad0d79238494432f32b8407942c606

Agradeceré cualquier comentario. Tal vez alguien pueda usarlo alguna vez.

Tzvi Gregory Kaidanov
fuente
-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
fuente
Esta es esencialmente la misma orientación que se ofrece en la respuesta altamente calificada de @ DalSoft de hace ocho años, pero con mucha menos explicación.
Jeremy Caney
Espero que resuelva el problema, pero agregue una explicación de su código con él para que el usuario obtenga una comprensión perfecta de lo que realmente quiere.
Jaimil Patel
-2

Me gustó la solución que lo hace Application_Start()como en la respuesta aquí

Aparentemente no pude acceder a los objetos json en JavaScript usando la configuración dentro de mi función como en la respuesta de DalSoft ya que el objeto devuelto tenía "\ n \ r" en toda la (clave, val) del objeto.

De todos modos, lo que sea que funcione es genial (porque los diferentes enfoques funcionan en diferentes escenarios basados ​​en los comentarios y las preguntas formuladas), aunque sería preferible una forma estándar de hacerlo con una buena documentación que respalde el enfoque.

rey_coder
fuente