2016-09-08 5 views
2

私は一連のドメインオブジェクトをシリアル化し、他のアプリケーションに送信してからJson.Netを使用して逆シリアル化します。これらのオブジェクトは、ある特性を有していてもよい、複数の派生クラスと異なるタイプに$typeプロパティを追加し、私はTypeNameHandling.Autoを使用しました クラスを変更せずに動的プロパティのタイプを省略しますか?

  • 動的特性、と抽象基本クラスとして定義され

    • 宣言された型。しかし、この設定は私の動的プロパティに望ましくない副作用を与えます。つまり、それらの型も宣言されます。

      以下の例では、modelは、C#コードでpublic dynamic Model { get; set; }と定義された動的プロパティです。別のアセンブリでこの文字列をデシリアライズしようとすると

      "model":{"$type":"<>f__AnonymousType0`3[[System.String, mscorlib],[System.String, mscorlib],[System.String, mscorlib]], ExampleAssembly","link":"http://www.google.com","name":"John"} 
      

      は、Json.Netは(もちろん)ExampleAssemblyを見つけることができません。 TypeNameHandling.Noneプロパティを使用すると、正常dynamicに非直列化することができ、次のプロパティのシリアル化

      "model": {"link":"http://www.google.com","name":"John"} 
      

      を与えます。ただし、これにより、派生型の逆シリアル化が解除されます。

      IContractResolverカスタムと他のカスタムコードを実装せずにこれを動作させる方法に関するアイデアはありますか?

      私はドメインオブジェクトを所有していないので、それらを属性で飾ることはできませんし、インターフェイスなどを実装することもできません。私が探しているのは、タイプを省略したシリアライザの設定ですdynamics

      IMHOこれは何らかの設定で設定する必要があります、私はそれを見つけられませんでした。

  • +0

    [JsonIgnore]または条件付き直列化(http://www.newtonsoft.com /json/help/html/conditionalproperties.htm)は役に立つかもしれません。 – Nair

    +0

    @Nair:ありがたいですが、残念です。私はドメインオブジェクトを所有していないので、属性やメソッドで飾ることはできません。それに、私はすべてのオブジェクトのためにこれをする必要があるので、それはうまくスケールされません。 – pardahlman

    +0

    関連するプロパティに '[JsonProperty(TypeNameHandling = TypeNameHandling.None)]'を追加するのが最も簡単な方法ですが、あなたのコメントではできません。その要件を明確にするために質問を編集したいかもしれません。 – dbc

    答えて

    2

    Json.Netには、ダイナミックタイプのみのタイプ名処理をオフにするための特定の設定はありません。関連する動的プロパティを[JsonProperty(TypeNameHandling = TypeNameHandling.None)]とすることができない(またはしたくない)場合は、カスタム契約レゾルバを実装してプログラム的に動作を適用する唯一のオプション(Json.Netソースコード自体を変更すること) 。しかし、DefaultContractResolverまたはCamelCasePropertyNamesContractResolverのようなJson.Net提供のリゾルバの1つからリゾルバを引き出すなら、これは難しくありません。ここで

    はあなたが必要となるすべてのコードです:

    using System; 
    using System.Reflection; 
    using Newtonsoft.Json; 
    using Newtonsoft.Json.Serialization; 
    
    public class OmitTypeNamesOnDynamicsResolver : DefaultContractResolver 
    { 
        public static readonly OmitTypeNamesOnDynamicsResolver Instance = new OmitTypeNamesOnDynamicsResolver(); 
    
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) 
        { 
         JsonProperty prop = base.CreateProperty(member, memberSerialization); 
         if (member.GetCustomAttribute<System.Runtime.CompilerServices.DynamicAttribute>() != null) 
         { 
          prop.TypeNameHandling = TypeNameHandling.None; 
         } 
         return prop; 
        } 
    } 
    

    すると、ちょうどJsonSerializerSettingsにリゾルバを追加し、すべて設定する必要があります。ここで

    JsonSerializerSettings settings = new JsonSerializerSettings 
    { 
        TypeNameHandling = TypeNameHandling.Auto, 
        ContractResolver = OmitTypeNamesOnDynamicsResolver.Instance 
    }; 
    
    string json = JsonConvert.SerializeObject(foo, settings); 
    

    は、コンセプトを証明するために、往復のデモです:

    public class Program 
    { 
        public static void Main(string[] args) 
        { 
         Foo foo = new Foo 
         { 
          Model = new { link = "http://www.google.com", name = "John" }, 
          Widget1 = new Doodad { Name = "Sprocket", Size = 10 }, 
          Widget2 = new Thingy { Name = "Coil", Strength = 5 } 
         }; 
    
         JsonSerializerSettings settings = new JsonSerializerSettings 
         { 
          TypeNameHandling = TypeNameHandling.Auto, 
          ContractResolver = OmitTypeNamesOnDynamicsResolver.Instance, 
          Formatting = Formatting.Indented 
         }; 
    
         string json = JsonConvert.SerializeObject(foo, settings); 
         Console.WriteLine(json); 
         Console.WriteLine(); 
    
         Foo foo2 = JsonConvert.DeserializeObject<Foo>(json, settings); 
         Console.WriteLine(foo2.Model.link); 
         Console.WriteLine(foo2.Model.name); 
         Console.WriteLine(foo2.Widget1.Name + " (" + foo2.Widget1.GetType().Name + ")"); 
         Console.WriteLine(foo2.Widget2.Name + " (" + foo2.Widget2.GetType().Name + ")"); 
        } 
    } 
    
    public class Foo 
    { 
        public dynamic Model { get; set; } 
        public AbstractWidget Widget1 { get; set; } 
        public AbstractWidget Widget2 { get; set; } 
    } 
    
    public class AbstractWidget 
    { 
        public string Name { get; set; } 
    } 
    
    public class Thingy : AbstractWidget 
    { 
        public int Strength { get; set; } 
    } 
    
    public class Doodad : AbstractWidget 
    { 
        public int Size { get; set; } 
    } 
    

    出力:

    { 
        "Model": { 
        "link": "http://www.google.com", 
        "name": "John" 
        }, 
        "Widget1": { 
        "$type": "Doodad, JsonTest", 
        "Size": 10, 
        "Name": "Sprocket" 
        }, 
        "Widget2": { 
        "$type": "Thingy, JsonTest", 
        "Strength": 5, 
        "Name": "Coil" 
        } 
    } 
    
    http://www.google.com 
    John 
    Sprocket (Doodad) 
    Coil (Thingy) 
    
    +0

    美しい!私が言ったように、私はむしろカスタムクラスなしでボックス機能を使い果たしてしまいます。しかし、あなたのコンタクトリゾルバの実装は非常に小さく、それは評価されています。よく書かれた応答をありがとう! – pardahlman

    +0

    問題ありません。お役に立てて嬉しいです。 –

    関連する問題