web-dev-qa-db-ja.com

DataContractシリアル化例外(データコントラクト名は予期されていません)

私は次のコードを持っています:

[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 」の「Json_Dictionary_Test.TestContract」と入力する必要はありません。静的に不明なタイプを既知のタイプのリストに追加します。たとえば、KnownTypeAttribute属性を使用するか、DataContractSerializerに渡される既知のタイプのリストにそれらを追加します。

しかし、私はそれを理解していません!私が知っているように、KnownTypeAttributeは逆シリアル化でのみ使用され、継承がある場合はそうではありませんか?しかし、これは単なるシリアル化です。そして、データ契約メンバーがいなくても問題なく動作します。

何か案が?


私はうまくいく何かを見つけました!既知のタイプリストを持つ親クラスがあります。これにすべての子クラスを入力し、シリアル化で使用します。

[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* {
    ...
}
...
24
Aaaaaaaa

この行を追加します:

 [KnownType(typeof(TestContract))]

そのため

[Serializable]
[KnownType(typeof(TestContract))]
public class DNCJsonDictionary<K, V> : ...

これは既知の問題です。そのため、ジェネリックはWCFでは完全には機能しません。

しかし、その理由は簡単です。WCFはWSDLを作成することになっていますそしてあなたの契約を公開することができます。 Genericsを使用してコントラクトを定義することはすべて問題ありませんが、WSDLは具体的なクラスを指す必要があるため、KnownTypeが必要です。

22
Aliostad