JSON.NET Hatası Tür için kendi kendine başvuru döngüsü algılandı


494

Varlık Veri Modeli .edmx otomatik olarak oluşturulan POCO sınıf serileştirmeye çalıştım ve ne zaman kullandığım

JsonConvert.SerializeObject 

Aşağıdaki hatayı aldım:

Hata System.data.entity türü için otomatik başvuru döngüsü algılandı.

Bu sorunu nasıl çözerim?



Linq ve MVC kullanırken: stackoverflow.com/a/38241856
aDDin


2
Bir asyncyöntem çağrısının (a Task) sonucunu serileştirmek ve awaitifadenin ön ekini unutmak istediğimde bu hata başıma geldi .
Uwe Keim

Yanıtlar:


485

Bu en iyi çözümdü https://code.msdn.microsoft.com/Loop-Reference-handling-in-caaffaf7

Düzeltme 1: Dairesel referansı global olarak görmezden gelmek

(Ben bunu seçtim / denedim, diğerleri gibi)

Json.net serileştiricisinin döngüsel başvuruları yoksayma seçeneği vardır. Aşağıdaki kodu WebApiConfig.csdosyaya yerleştirin:

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

Basit düzeltme, serileştiricinin bir döngüye neden olacak referansı yok saymasını sağlar. Ancak, sınırlamaları vardır:

  • Veriler, döngü referans bilgilerini kaybeder
  • Düzeltme yalnızca JSON.net için geçerlidir
  • Derin bir referans zinciri varsa referans seviyesi kontrol edilemez

Bu düzeltmeyi api olmayan bir ASP.NET projesinde kullanmak istiyorsanız, yukarıdaki satırı Global.asax.csekleyebilirsiniz, ancak önce şunu ekleyin:

var config = GlobalConfiguration.Configuration;

Bunu .Net Core projesinde kullanmak istiyorsanız şu şekilde değiştirebilirsiniz Startup.cs:

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

Düzeltme 2: Dairesel referansı global olarak koruma

Bu ikinci düzeltme ilkine benzer. Kodu şu şekilde değiştirin:

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

Bu ayar uygulandıktan sonra veri şekli değişecektir.

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

$ İd ve ​​$ ref tüm referansları tutar ve nesne grafiği düz yapar, ancak istemci kodu veri tüketmek için şekil değişikliği bilmek gerekir ve sadece JSON.NET serileştirici için de geçerlidir.

Düzeltme 3: Referans niteliklerini yok sayın ve koruyun

Bu düzeltme, model veya özellik düzeyinde serileştirme davranışını denetlemek için model sınıfındaki öznitelikleri süslemektir. Mülkü yok saymak için:

 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 ve IgnoreDataMember XmlDCSerializer içindir. Referansı korumak için:

 // 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 içindir ve [DataContract(IsReference = true)]XmlDCSerializer içindir. Not: DataContractsınıfa uyguladıktan sonra DataMemberserileştirmek istediğiniz özelliklere eklemeniz gerekir .

Öznitelikler hem json hem de xml serileştiricisine uygulanabilir ve model sınıfı üzerinde daha fazla kontrol sağlar.


7
Düzeltme 3 benim için çalıştı. Sadece DataContract ve DataMember özniteliklerini kaldırın ve DTO'lara JsonObject (IsReference = true) koyun. Ve çalışıyor. Teşekkürler.
maestro

1
Bunu deneyin GlobalConfiguration.Configuration
Bishoy Hanna

1
Fix 3, GlobalConfiguration'ın olmadığı istemci kodunda
çalışabilme

1
@BishoyHanna, cevabınızı normal ASP.NET uygulamalarından kullanılmasına izin verecek şekilde düzenleyebilir misiniz? Önerilen düzenlememi kullanabilirsiniz: stackoverflow.com/review/suggested-edits/17797683
NH.

2
[JsonIgnore]Yukarıdaki özelliği kullanmak benim için çalıştı.
Nathan Beck

467

JsonSerializerSettings kullanın

  • ReferenceLoopHandling.Error(varsayılan) bir referans döngüsüyle karşılaşılırsa hata verecektir. Bu yüzden bir istisna elde edersiniz.
  • ReferenceLoopHandling.Serialize nesneler yuvalanmışsa, ancak süresiz olarak kullanışlıdır.
  • ReferenceLoopHandling.Ignore kendi başına bir alt nesne ise nesneyi serileştirmez.

Misal:

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

Süresiz olarak yuvalanmış bir nesneyi serileştirmeniz gerekiyorsa, StackOverflowException özel durumundan kaçınmak için PreserveObjectReferences kullanabilirsiniz .

Misal:

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

Serileştirdiğiniz nesne için neyin anlamlı olduğunu seçin.

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


66
Bir datatable serileştirilirken hatayla karşılaştım. ReferenceLoopHandling = ReferenceLoopHandling.IgnoreÇalışmak için kullandım

8
Verilerde referans döngüler varsa, kullanmak ReferenceLoopHandling.Serializeserileştiricinin sonsuz bir özyinelemeli döngüye girmesine ve yığını taşmasına neden olur.
Brian Rogers

1
Doğru. Soru EF modeli ile ilgili olduğu için geçerli bir endişe kaynağıdır. Mevcut tüm seçenekleri verecek şekilde değiştirildi.
DalSoft

1
Bir nesneyi serileştirmeye çalışırken aynı hatayla karşılaştım ... ancak, nesnenin bir numaralandırma türü dışında herhangi bir referansı yok ..
Marin

1
benim için EF bu sorunun ana nedenidir çünkü kendinden referanslı varlıklar her yerde vardır.
Teoman shipahi

57

Düzeltme döngü referanslarını yoksaymak ve bunları serileştirmektir. Bu davranış, içinde belirtilir JsonSerializerSettings.

JsonConvertAşırı yüklü tekli :

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

Application_Start()Global.asax.cs içindeki kod ile Genel Ayar :

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

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


Genel ayarı yaparken biçimi neden girintili olarak ayarlıyorsunuz?
Murphybro2

Kesinlikle bu sorunu çözmek için neye ihtiyacımız vardı (dağıtım sırasında keşfedildi)! Siz de .... bize zaman kazandığınız için teşekkürler !!
Ryan Eastabrook

I) (= "JsonConvert.DefaultSettings" ekleyerek benim Issus çözüldü => yeni JsonSerializerSettings {....} sınıfının "Startup.cs" in
Beldi Anouar

45

Bunu yapmanın en basit yolu Json.NET'i nuget'ten yüklemek ve [JsonIgnore]özniteliği sınıftaki sanal özelliğe eklemektir. Örneğin:

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

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

Bu günlerde, daha hafif olmasını, istenmeyen koleksiyonları içermemesi için sadece içinden geçmek istediğim özelliklere sahip bir model oluşturuyorum ve oluşturulan dosyaları yeniden oluşturduğumda değişikliklerimi kaybetmiyorum ...


3
Newton JSON
Aizen ile

21

.NET Core 1.0'da, bunu Startup.cs dosyanızda genel bir ayar olarak ayarlayabilirsiniz:

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

Ancak bu durumda, bu özelliğin Yoksayıldığının farkında olmak istiyorsam, o zaman herhangi bir istisna alamayacağım.
Mayer Spitzer

10

.NET Core 2.x kullanıyorsanız, Startup.cs içindeki ConfigureServices bölümünüzü güncelleyin

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

    ...
    }

MVC olmadan .NET Core 3.x kullanıyorsanız, şöyle olur:

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

Entity Framework ve önce veritabanında tasarım deseni kullanıyorsanız, bu referans döngü yönetimi neredeyse zorunludur.


2
kullanmazsam ne olur services.AddMvc()?
prisar

2
bu kötü bir uygulama mı?
Renan Coelho

İlk bakışta, bunun eski "sonsuz döngü" probleminden kaçınmanın "kasıtlı tasarımını" geçersiz kılabileceği için kötü bir uygulama olduğunu düşünebilirsiniz. Ancak, sınıflar için kullanım durumları hakkında düşünürseniz, birbirlerine başvurmaları gerekebilir. Örneğin, hem Ağaçlar> Meyveler'e hem de Meyveler> Ağaçlara erişmek isteyebilirsiniz.
Dave Skender

Ayrıca, Entity Framework gibi bir şeyle veritabanından önce bir tasarım deseni kullanıyorsanız, yabancı anahtarlarınızı veritabanınızda nasıl ayarladığınıza bağlı olarak, otomatik olarak bu döngüsel referansları oluşturur, bu nedenle bu ayarı hemen hemen kullanmanız gerekir. sınıflarınızı tersine mühendislik yapıyoruz.
Dave Skender

9

Döngü sorununuz olduğunda NEWTONSOFTJSON'da bizi serileştirmek için, benim durumumda global.asax veya apiconfig'i değiştirmem gerekmedi. Ben sadece Döngü işlem görmezden JsonSerializesSettings kullanın.

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
Buraya metin aranabilir olması için başka bir kişinin saat penceresine gitmesi için buraya geldiyse:Newtonsoft.Json.JsonConvert.SerializeObject(objToSerialize, new Newtonsoft.Json.JsonSerializerSettings() {ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore});
Graham

8

Kendi kendine referans döngüsünü devre dışı bırakmak için bu iki satırı DbContext sınıf yapıcısına ekleyebiliriz, örneğin

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

Bu en basitlerinden biri ve bir cazibe gibi çalışıyor . Oy verildi, thanks a lot ...
Murat Yıldız

Diğer soruda yazdığım gibi: EF6'nın varsayılan olarak etkin olan bir özelliğini kapattığınız için bu tür cevapları sevmiyorum ve bu kod parçası programın diğer bölümlerini kırabilir. Bunun ne yaptığını ve ne tür yankıları olduğunu açıklamalısınız.
El Mac

@ElMac haklısınız, ancak bu özelliğe ihtiyacımız yoksa, neden bu çözümü kullanamıyorsunuz?
Sanjay Nishad

@SanjayNishad Özelliğe ihtiyacınız olup olmadığını umursamıyorum. Neyi devre dışı bıraktıklarını bilmeyen kullanıcılar hakkında.
El Mac

6

Özelliğe özellik de uygulayabilirsiniz. Bu [JsonProperty( ReferenceLoopHandling = ... )]özellik buna çok uygundur.

Örneğin:

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

Umarım yardımcı olur Jaans


4

Döngü başvurularını yok saymak ve bunları MVC 6'da global olarak serileştirmemek için startup.cs dosyasında aşağıdakileri kullanın:

    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.csSınıfta bunu kullanın :

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

2

Benim için farklı bir rotaya gitmem gerekiyordu. JSON.Net serileştiricisini düzeltmek yerine, veri bağlamımda Tembel Yükleme'den sonra gitmek zorunda kaldım.

Bunu sadece temel veri havuzuma ekledim:

context.Configuration.ProxyCreationEnabled = false;

Bağlam enjeksiyonu kullandığım için "context" nesnesi taban havuzumda kullandığım bir yapıcı parametresidir. ProxyCreationEnabled özelliğini datacontext'inizi başlattığınız her yerde değiştirebilirsiniz.

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


2

Bu istisnayı yaşadım ve çalışma çözümüm Kolay ve Basit,

Başvurulan özelliği JsonIgnore özniteliğini ekleyerek yoksay:

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

Diziselleştirmeyi kaldırdığınızda özelliği sıfırlayın:

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

Newtonsoft.Json kullanarak;


Bu ihtiyacım olan sihir. Çözmek[JsonIgnore]
saviour123

2

Takım:

Bu ASP.NET Core ile çalışır; Yukarıdakilerin zorluğu, 'ayarı yoksaymak için nasıl ayarladığınızdır'. Uygulamanızı nasıl ayarladığınıza bağlı olarak oldukça zor olabilir. İşte benim için işe yarayan.

Bu, genel geçersiz ConfigureServices (IServiceCollection hizmetleri) bölümünüze yerleştirilebilir.

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

2

İnsanlar zaten [JsonIgnore] 'un sınıftaki sanal mülke eklendiğinden bahsettiler, örneğin:

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

Ayrıca başka bir seçenek (yalnızca null ise seri hale getirme özelliği atlar [JsonProperty (NullValueHandling = NullValueHandling.Ignore)] paylaşacak:

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


0

Sadece Configuration.ProxyCreationEnabled = false;bağlam dosyasının içine yerleştirin; bu sorunu çözecektir.

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

0

Özel Yapılandırma JsonSerializer ile Sorunum Çözüldü

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

0

Lütfen yönteminizde await ve async kullandığınızdan da emin olun. Nesneniz düzgün şekilde serileştirilmemişse bu hatayı alabilirsiniz.


0

Aynı sorunla karşı karşıyaydım ve JsonSetting kullanarak kendi kendini referanslama hatasını göz ardı etmek için çalıştım, çok derinlemesine bir referans alana kadar ve nokta net sürecim Json yazma değerine dayanıyor.

Benim sorunum

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

}

Sorunu CompanyUser'a başvurduğu Kullanıcı sınıfında görebilirsiniz. kendi kendine sınıfına .

Şimdi, tüm ilişkisel özellikleri içeren GetAll yöntemini çağırıyorum.

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

Bu aşamada DotNetCore işlemim JsonResult'u yürütmek , değer yazmak ... ve asla gelmek istemiyor . Startup.cs dosyalarında JsonOption'u zaten ayarladım. Nedense EFCore Ef vermek istemiyorum iç içe özellik dahil.

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

beklenen davranış bu olmalı

Hey EfCore, lütfen "CompanyUsers" verilerini Şirket sınıfıma da dahil edebilir, böylece verilere kolayca erişebilirim.

sonra

Hey EfCore ayrıca "CompanyUsers.User" verilerini de dahil edebilir, böylece böyle verilere kolayca erişebilirim Company.CompanyUsers.First () .

bu aşamada ben sadece bu "Company.CompanyUsers.First (). User.DisplayName" almalı ve bana Company.CompanyUsers.First (). User.CompanyUsers kendi kendine başvuru sorunu neden olmamalıdır ; CompanyUsers bir navigasyon özelliği olduğu için teknik olarak bana User.CompanyUsers vermemelidir. Ancak, EfCore çok heyecanlanıyor ve bana User.CompanyUsers veriyor .

Bu nedenle, nesnenin dışında bırakılacak özellik için bir uzantı yöntemi yazmaya karar verdim (aslında sadece özelliği null olarak ayarlaması hariç değil). Sadece dizi özellikleri üzerinde de çalışacak. aşağıda da diğer kullanıcılar için nuget paketini ihraç edeceğim kod (bu bile birine yardımcı olup olmadığından emin değilim). Nedeni basit çünkü yazamayacak kadar tembelim .Select (n => new {n.p1, n.p2});Sadece 1 özelliği hariç tutmak için select deyimi yazmak istemiyorum!

Acele yazdım ve bu da dizilerle nesnede dışlamak (null) ayarlamak isteyen birine yardımcı olabilir, ancak bu en iyi kod (bazı aşamada güncelleyeceğim) değil.

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

Yukarıdaki eklenti sınıfı, kendiliğinden başvuru yapan döngü dizilerinden bile kaçınmak için özelliği null değerine ayarlayabilmenizi sağlar.

İfade Oluşturucu

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

Usages:

Model Sınıfları

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

Kukla Veriler

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

                }
            }
        };

Durumlar:

Durum 1: Yalnızca dizisi olmayan mülkü hariç tutma

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

Durum 2: 1 dizili özelliği hariç tutma

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

Durum 3: İç içe 2 dizili özelliği hariç tutma

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

Durum 4: İçerdiği EF GetAll Sorgusu

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

Explode () yönteminin, yalnızca ifade oluşturucumuzun özelliği dizi özelliğinden alması için bir uzantı yöntemi olduğunu fark ettiniz . Bir dizi özelliği olduğunda .Explode () .ProProtytyToExclude veya .Explode (). Property1.MyArrayProperty.Explode () kullanın . Yukarıdaki kod ben kadar derin istediği kadar kendini referans önlemek için bana yardımcı olur. Şimdi GetAll kullanabilirim ve istemediğim özelliği hariç tutabilirim!

Bu büyük gönderiyi okuduğunuz için teşekkürler!



-1

C # kodu:

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

Bu, esas olarak @ DalSoft'un sekiz yıl önceki yüksek puanlı cevabında sunulanla aynı rehberdir, ancak çok daha az açıklama ile.
Jeremy Caney

Umarım sorunu çözer, ancak kullanıcı ile kodunun açıklamasını ekleyin, böylece kullanıcı gerçekten istediği mükemmel anlayışı elde edecektir.
Jaimil Patel

-2

Ben karşı yapıyor çözümü sevdim Application_Start()cevap olarakBuradaki

Görünüşe göre ben js nesneler benim işlevi içinde yapılandırmayı DalSoft yanıt olarak olduğu gibi kullanarak nesneye erişemedi çünkü nesnenin tüm (anahtar, val) "\ n \ r" vardı.

Her neyse işe yarayan her şey harika (çünkü farklı yaklaşımlar, sorulan yorumlara ve sorulara dayanarak farklı senaryoda çalışmaktadır), ancak bunu yapmanın standart bir yolu, yaklaşımı destekleyen bazı iyi belgelerle tercih edilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.