DataContract 序列化异常(不需要数据合约名称)

Posted

技术标签:

【中文标题】DataContract 序列化异常(不需要数据合约名称)【英文标题】:DataContract serialization exception (data contract name is not expected) 【发布时间】:2011-06-19 23:57:42 【问题描述】:

我有以下代码:

[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 成员也可以正常工作。

有什么想法吗?


我想出了一些可行的方法!有一个带有 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* 
    ...

...

【问题讨论】:

不错的解决方案!这将节省我很多时间。我没有将所有可序列化的类设为子类,而是检查它们是否具有对我更有效的 DataContract 属性: if (!type.IsAbstract && type.IsDefined(typeof(DataContractAttribute), true)) knownTypes.Add(类型); 【参考方案1】:

添加这一行:

 [KnownType(typeof(TestContract))]

这样

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

这是一个已知问题。这就是泛型不能与 WCF 完全兼容的原因。

但原因很简单,WCF 应该创建 WSDL 并能够发布您的合同。使用泛型来定义合同很好,但是 WSDL 需要指向一些具体的类,因此您需要 KnownType

【讨论】:

Thaks,它可以工作,但是...... DNCJsonDictionary 只是一个容器,它可能不知道“KnownTypes”,这不是他的工作。如果我使用 List 而不是我的“字典”,它就可以工作。 如果它已经在合约中公开,那么它应该知道 KnownTypes,因为它会告诉框架如何序列化。我不是为WCF辩护,我没有设计它!其实我不喜欢:***.com/questions/3710635/… 好的,但我的问题仍然是:例如 List>T<也是一个泛型类型,而且它没有 [KnownType(typeof(TestContract))] 属性。但它工作正常: List ltc = new List(); ltc.Add(测试); Console.WriteLine(序列化(ltc));为什么?怎么样? List() 工作正常,因为您在 List() 本身上声明 TestContract,因此不涉及未知的泛型。即,如果您尝试序列化 List 而不是 List().,则会出现问题

以上是关于DataContract 序列化异常(不需要数据合约名称)的主要内容,如果未能解决你的问题,请参考以下文章

数据契约[DataContract]

WCF 数据契约(DataContract)

DataContract 无法序列化集合成员

DataContract XML 序列化和 XML 属性

如何找出类是不是具有 DataContract 属性?

DataContract,默认 DataMember 值