タイプに対してJSON.NETエラー自己参照ループが検出されました


495

Entity Data Model .edmxから自動的に生成されたPOCOクラスをシリアル化してみました。

JsonConvert.SerializeObject 

次のエラーが発生しました:

エラータイプSystem.data.entityで自己参照ループが検出されました。

この問題を解決するにはどうすればよいですか?



LinqとMVCを使用している場合:stackoverflow.com/a/38241856
aDDin

使用している場合、.NETのコア2:stackoverflow.com/a/48709134/4496145
デイブSkender

2
このエラーは、asyncメソッド呼び出し(a Task)の結果をシリアル化し、awaitステートメントの前に付けるのを忘れたときに発生しました。
Uwe Keim

回答:


485

それが最高のソリューションでした https://code.msdn.microsoft.com/Loop-Reference-handling-in-caaffaf7

修正1:循環参照をグローバルに無視する

(私はこれを選びました/他の多くの人と同じように試しました)

json.netシリアライザーには、循環参照を無視するオプションがあります。次のコードをWebApiConfig.csファイルに入れます:

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

単純な修正により、シリアライザはループを引き起こす参照を無視します。ただし、制限があります。

  • データはループしている参照情報を失います
  • 修正はJSON.netにのみ適用されます
  • 深い参照チェーンがある場合、参照のレベルを制御できません

この修正を非API ASP.NETプロジェクトで使用する場合は、上記の行をに追加できますがGlobal.asax.cs、最初に次の行を追加します。

var config = GlobalConfiguration.Configuration;

これを.Net Coreプロジェクトで使用する場合は、次のように変更できますStartup.cs

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

修正2:循環参照をグローバルに保持する

この2番目の修正は最初の修正と似ています。コードを次のように変更するだけです。

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

この設定を適用すると、データの形状が変更されます。

[
   {
      "$id":"1",
      "Category":{
         "$id":"2",
         "Products":[
            {
               "$id":"3",
               "Category":{
                  "$ref":"2"
               },
               "Id":2,
               "Name":"Yogurt"
            },
            {
               "$ref":"1"
            }
         ],
         "Id":1,
         "Name":"Diary"
      },
      "Id":1,
      "Name":"Whole Milk"
   },
   {
      "$ref":"3"
   }
]

$ idと$ refはすべての参照を保持し、オブジェクトグラフレベルをフラットにしますが、クライアントコードはデータを使用するために形状の変更を知る必要があり、JSON.NETシリアライザーにも適用されます。

修正3:参照属性を無視して保持する

この修正は、モデルまたはプロパティレベルでのシリアル化動作を制御するためにモデルクラスの属性を装飾することです。プロパティを無視するには:

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

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

JsonIgnoreはJSON.NET用で、IgnoreDataMemberはXmlDCSerializer用です。参照を保持するには:

 // Fix 3 
        [JsonObject(IsReference = true)] 
        public class Category 
        { 
            public int Id { get; set; } 
            public string Name { get; set; } 

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

       [DataContract(IsReference = true)] 
       public class Product 
       { 
           [Key] 
           public int Id { get; set; } 

           [DataMember] 
           public string Name { get; set; } 

           [DataMember] 
           public virtual Category Category { get; set; } 
       }

JsonObject(IsReference = true)]JSON.NET用で[DataContract(IsReference = true)]あり、XmlDCSerializer用です。注意:DataContractクラスに適用した後DataMember、シリアル化するプロパティに追加する必要があります。

属性はjsonとxmlの両方のシリアライザーに適用でき、モデルクラスをより詳細に制御できます。


7
修正3は私のために働いています。単にDataContract属性とDataMember属性を削除し、JsonObject(IsReference = true)をDTOに配置するだけです。そしてそれは機能します。ありがとう。
maestro

1
これを試してくださいGlobalConfiguration.Configuration
Bishoy Hanna

1
修正3には、GlobalConfigurationがないクライアントコードで機能するという利点があります
dumbledad '28

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/


66
データテーブルをシリアル化するときにエラーが発生しました。私ReferenceLoopHandling = ReferenceLoopHandling.Ignoreはそれが機能するために使用しました

8
データに参照ループがある場合、を使用ReferenceLoopHandling.Serializeすると、シリアライザが無限再帰ループに入り、スタックがオーバーフローします。
ブライアンロジャース

1
正しい。問題はEFモデルに関するものであるため、これも有効な懸念事項です。利用可能なすべてのオプションを提供するように修正されました。
DalSoft 2014年

1
オブジェクトをシリアル化しようとしたとき、私は...しかし、オブジェクトがenum型以外のすべての参照を持っていない...この同じエラーが発生しました
マリン

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


グローバル設定を行うときに、フォーマットをインデントに設定するのはなぜですか?
Murphybro2

絶対にこの問題を解決するために必要なもの(展開中に発見されました)!あなたダマン....私たちの時間を節約してくれてありがとう!!
Ryan Eastabrook

クラス "Startup.cs"に "JsonConvert.DefaultSettings" =()=> new JsonSerializerSettings {....}を追加して問題を解決しました
Beldi Anouar

45

これを行う最も簡単な方法は、nuget からJson.NET をインストール[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
ニュートン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));
        });
    }

しかし、この場合、このプロパティが無視されることを認識したいのであれば、例外は発生しません。
Mayer Spitzer

10

.NET Core 2.xを使用している場合は、Startup.csのConfigureServicesセクションを更新します。

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なしで.NET Core 3.xを使用している場合は、次のようになります。

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

Entity Frameworkとデータベースファーストの設計パターンを使用している場合、この参照ループの処理はほぼ必須です。


2
使用しない場合はどうなりますservices.AddMvc()か?
プリサール2018年

2
これは悪い習慣ですか?
Renan Coelho

一見すると、古い「無限ループ」問題を回避する「意図的な設計」を無効にする可能性があるため、これは悪い習慣だと思うかもしれません。ただし、クラスのユースケースについて考える場合、それらを相互に参照する必要がある場合があります。たとえば、Trees> FruitsとFruits> Treesの両方にアクセスしたい場合があります。
Dave Skender、

また、Entity Frameworkなどでデータベースファーストのデザインパターンを使用している場合は、データベースで外部キーを設定する方法に応じて、これらの循環参照が自動的に作成されるため、この設定を使用する必要がある場合はほとんどありません。クラスをリバースエンジニアリングしています。
Dave Skender、

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
:誰がそれのテキスト検索可能なので、ウォッチウィンドウに行くために1つのライナーのためにここに来た場合Newtonsoft.Json.JsonConvert.SerializeObject(objToSerialize, new Newtonsoft.Json.JsonSerializerSettings() {ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore});
グレアム

8

次のように、これらの2行をDbContextクラスコンストラクターに追加して、自己参照ループを無効にすることができます。

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

これは最も単純なものの1つで、魅力のように機能します。投票していただき、ありがとうございました...
MuratYıldız18年

私が他の質問で書いたように:デフォルトで有効になっているEF6の機能をオフにしているため、このコードがプログラムの他の部分を壊す可能性があるため、この種の回答は好きではありません。これが何をするか、どのような影響があるかを説明する必要があります。
El Mac

@ElMacあなたは正しいですが、その機能が必要ないのであれば、なぜこのソリューションを使用できないのですか?
Sanjay Nishad

@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さんのお役に立てば幸いです


4

ループ参照を無視し、MVC 6でグローバルにシリアル化しないようにするには、startup.csで以下を使用します。

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().Configure<MvcOptions>(options =>
        {
            options.OutputFormatters.RemoveTypesOf<JsonOutputFormatter>();
            var jsonOutputFormatter = new JsonOutputFormatter();
            jsonOutputFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
            options.OutputFormatters.Insert(0, jsonOutputFormatter);
        });
    }

2

これをWebApiConfig.csクラスで使用します:

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

2

私にとっては別のルートに行かなければなりませんでした。JSON.Netシリアライザーを修正しようとする代わりに、データコンテキストで遅延読み込みを実行する必要がありました。

これをベースリポジトリに追加しました:

context.Configuration.ProxyCreationEnabled = false;

「コンテキスト」オブジェクトは、依存関係の注入を使用するため、ベースリポジトリで使用するコンストラクタパラメータです。代わりに、データコンテキストをインスタンス化する任意の場所でProxyCreationEnabledプロパティを変更できます。

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


2

私にはこの例外があり、私の解決策は簡単でシンプルです。

JsonIgnore属性を追加してReferencedプロパティを無視します。

[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で動作します。上記の課題は、「設定を無視するように設定する」方法です。アプリケーションの設定方法によっては、非常に困難な場合があります。ここに私のために働いたものがあります。

これは、public void ConfigureServices(IServiceCollection services)セクションに配置できます。

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

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

0

カスタム構成JsonSerializerSettingsで解決した私の問題:

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

0

また、必ずメソッドでawaitおよびasyncを使用してください。このエラーは、オブジェクトが正しくシリアル化されていない場合に発生する可能性があります。


0

私は同じ問題に直面していて、JsonSettingを使用して自己参照エラーを無視しようとしましたが、自己参照が非常に深く、ドットネットプロセスがJsonの書き込み値でハングアップするクラスが見つかるまでは、この作業はうまくいきました。

私の問題

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

    public string Name { get; set; }

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

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

    public virtual Company Company { get; set; }

    public virtual User User { get; set; }
}

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

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

}

CompanyUserを参照しているUserクラスで問題を確認できます自己クラスを。

ここで、すべてのリレーショナルプロパティを含むGetAllメソッドを呼び出します。

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

この段階では私のDotNetCoreプロセスのハング、するJsonResultを実行する値を書き込む...とは来ません。私のStartup.csでは、JsonOptionをすでに設定しています。なんらかの理由でEFCoreにネストされたプロパティが含まれているため、Efに指定するように求めていません。

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

予想される動作はこれでなければなりません

EfCoreさん、「CompanyUsers」データもCompanyクラスに含めて、データに簡単にアクセスできるようにしてください。

その後

EfCoreさん、「CompanyUsers.User」データも含めて、このCompany.CompanyUsers.First()。User.DisplayNameのようなデータに簡単にアクセスできるようにしてください

この段階では、この"Company.CompanyUsers.First()。User.DisplayName"のみを取得し、自己参照の問題の原因となるCompany.CompanyUsers.First()。User.CompanyUsers取得しないようにする必要があります。厳密には、CompanyUsersはナビゲーションプロパティであるため、User.CompanyUsersを取得するべきではありません。しかし、EfCoreはとても興奮し、User.CompanyUsersをくれます

そのため、オブジェクトから除外されるプロパティの拡張メソッドを作成することにしました(実際には、プロパティをnullに設定するだけで除外されるわけではありません)。それだけでなく、配列のプロパティでも機能します。以下は、他のユーザーのためにnugetパッケージもエクスポートするコードです(これが誰かに役立つかどうかはわかりません)。理由は単純です。私は.Select(n => new {n.p1、n.p2});を書くのが面倒だからです1つのプロパティのみを除外するselectステートメントを記述したくないだけです。

私は急いで書いたので、これは最良のコードではありません(ある段階で更新します)。これは、配列を持つオブジェクトから除外(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:Includeを含む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

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

これは、8年前の@DalSoftの高評価の回答で提供されているガイダンスと基本的に同じですが、説明がはるかに少なくなっています。
Jeremy Caney

問題が解決することを願っていますが、ユーザーが本当に望んでいることをユーザーが完全に理解できるように、コードの説明を追加してください。
Jaimil Patel

-2

私はここApplication_Start()の答えのようにそれを行うソリューションが好きでした

返されたオブジェクトにはオブジェクトの(key、val)全体に「\ n \ r」があったため、DalSoftの回答のように関数内の設定を使用してJavaScriptでjsonオブジェクトにアクセスできなかったようです。

とにかく、何でもうまくいくのは素晴らしいことです(さまざまなアプローチが、コメントや質問に基づいてさまざまなシナリオで機能するため)。ただし、アプローチをサポートする優れたドキュメントがあれば、標準的な方法で行うのが望ましいでしょう。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.