2011-02-02 1 views
21

I次のコードを持っています。データをのDataContractシリアル化の例外(データコントラクト名が期待されていない)

タイプ 'Json_Dictionary_Test.TestContract':私は実行すると

[DataContract] 
class TestContract { 
    private String _Name; 
    private Int32 _Age; 

    [DataMember(Name = "Name")] 
    public String Name { 
     get { return _Name; } 
     set { _Name = value; } 
    } 

    [DataMember(Name = "Age")] 
    public Int32 Age { 
     get { return _Age; } 
     set { _Age = value; } 
    } 
} 

[Serializable] 
public class DNCJsonDictionary<K, V> : ISerializable { 
    Dictionary<K, V> dict = new Dictionary<K, V>(); 

    public DNCJsonDictionary() { } 

    protected DNCJsonDictionary(SerializationInfo info, StreamingContext context) { 
    } 

    public void GetObjectData(SerializationInfo info, StreamingContext context) { 
     foreach(K key in dict.Keys) { 
      info.AddValue(key.ToString(), dict[ key ]); 
     } 
    } 

    public void Add(K key, V value) { 
     dict.Add(key, value); 
    } 

    public V this[ K index ] { 
     set { dict[ index ] = value; } 
     get { return dict[ index ]; } 
    } 
} 

public class MainClass { 
    public static String Serialize(Object data) { 
     var serializer = new DataContractJsonSerializer(data.GetType()); 
     var ms = new MemoryStream(); 
     serializer.WriteObject(ms, data); 

     return Encoding.UTF8.GetString(ms.ToArray()); 
    } 

    public static void Main() { 
     DNCJsonDictionary<String, Object> address = new DNCJsonDictionary<String, Object>(); 
     address[ "Street" ] = "30 Rockefeller Plaza"; 
     address[ "City" ] = "New York City"; 
     address[ "State" ] = "NY"; 

     TestContract test = new TestContract(); 
     test.Name = "CsDJ"; 
     test.Age = 28; 

     DNCJsonDictionary<String, Object> result = new DNCJsonDictionary<String, Object>(); 
     result[ "foo" ] = "bar"; 
     result[ "Name" ] = "John Doe"; 
     result[ "Age" ] = 32; 

     result[ "Address" ] = address; 

      // ** --- THIS THROWS AN EXCEPTION!!! --- **    
     result[ "test" ] = test; 

     Console.WriteLine(Serialize(result)); 

     Console.ReadLine(); 
    } 
} 

が、私はこの例外を取得します契約名 'TestContract:http://schemas.datacontract.org/2004/07/Json_Dictionary_Test'は必要ありません。 KnownTypeAttribute属性を使用するか、DataContractSerializerに渡される既知の型のリストに追加するなど、既知の型のリストに静的に知られていない型を追加します。

しかし、私はそれを理解していません!私が知っているように、KnownTypeAttributeはデシリアライズ時にのみ使用され、継承があればそれはありませんか?しかしここにはシリアライゼーションだけがあります。そして、datacontractメンバーがうまくいなければ。


私は何かを考え出しました!私はすべての子クラスに記入し、それをシリアル化に使用されるKnownTypesリストを持つ親クラスは、あります:

[DataContract] 
[KnownType("GetKnownTypes")] // for serialization 
class ResultContract { 
    private static List<Type> KnownTypes { get; set; } 

    public static List<Type> GetKnownTypes() { 
     return KnownTypes; 
    } 

    static ResultContract() { 
     KnownTypes = new List<Type>(); 
     try { 
      foreach(Type type in Assembly.GetExecutingAssembly().GetTypes()) { 
       if(!type.IsAbstract && type.IsSubclassOf(typeof(ResultContract))) { 
        KnownTypes.Add(type); 
       } 
      } 
     } catch(Exception ex) { 
      Console.WriteLine("Fatal error!"); 
     } 
    } 
} 

[DataContract] 
class TestContract : *ResultContract* { 
    ... 
} 
... 
+0

ニースのソリューション!これは私に多くの時間を節約するだろう。すべてのシリアライズ可能なクラスをサブクラスにする代わりに、DataContract属性が適切かどうかを確認するだけです。if(!type.IsAbstract && type.IsDefined(typeof(DataContractAttribute)、true)) { knownTypes。追加(タイプ); } – rob

答えて

20

は、この行を追加します。

[KnownType(typeof(TestContract))] 

[Serializable] 
[KnownType(typeof(TestContract))] 
public class DNCJsonDictionary<K, V> : ... 
ようにするには

これは既知の問題です。そのためジェネリック医薬品はWCFではうまく機能しません。 WCFは、WSDLを作成し、契約を公開できるようになっているはずです。理由は簡単です。あなたの契約を定義するためにジェネリックスを使用するのはうまくいいですが、WSDLは具体的なクラスを指す必要がありますので、KnownTypeが必要です。

+0

Thaks、それは動作しますが、... DNCJsonDictionaryは単なるコンテナであり、 "KnownTypes"について知ることはできません。私の「辞書」の代わりに「リスト」を使うと、それは機能します。 – Aaaaaaaa

+0

契約で公開されている場合、フレームワークにシリアライズ方法を伝えるのでKnownTypesについて知っておく必要があります。私はWCFを守るのではない、私はそれを設計していない!実際に私はそれが好きではない:http://stackoverflow.com/questions/3710635/succinct-and-light-weight-api-restjson-in-net – Aliostad

+0

さて、私の質問はまだそれです:例えばリスト> T <もジェネリック型であり、私は[KnownType(typeof(TestContract))]属性を持っていません。しかし、それは正常に動作します:List ltc = new List (); ltc.Add(テスト); Console.WriteLine(Serialize(ltc));どうして?どうやって? – Aaaaaaaa

関連する問題