WCF - 序列化继承的类型

时间:2010-02-24 20:58:44

标签: wcf serialization datacontractserializer

我有这些课程:

[DataContract]
public class ErrorBase {}

[DataContract]
public class FileMissingError: ErrorBase {}

[DataContract]
public class ResponseFileInquiry
{
  [DataMember]
  public List<ErrorBase> errors {get;set;};
}

类ResponseFileInquiry的一个实例是我的服务方法返回给客户端的。现在,如果我用ErrorBase实例填充ResponseFileInquiry.errors,一切正常,但如果我添加一个继承类型FileMissingError的实例,我在序列化期间得到服务端异常:

Type 'MyNamespace.FileMissingError' with data contract name 'FileMissingError' 
is not expected. Add any types not known statically to the list of known types - 
for example, by using the KnownTypeAttribute attribute or by adding them to the 
list of known types passed to DataContractSerializer.'

因此序列化程序变得混乱,因为它期望List包含声明的类型对象(ErrorBase),但它正在获取继承类型(FileMissingError)对象。

我有一大堆错误类型,List会包含它们的组合,那么我该怎么做才能使它工作?

3 个答案:

答案 0 :(得分:17)

您应该将KnownType属性添加到基类

[DataContract]
[KnownType(typeof(FileMissingError))]
public class ErrorBase {}

详细了解此blog

中的KnownType属性

答案 1 :(得分:7)

试试这个:

[DataContract]
[KnownType(typeof(FileMissingError))]
public class ErrorBase {}

正如错误消息所述,任何无法静态知道的信息(如此处表达的多态关系)必须通过属性提供。在这种情况下,您需要指定您的FileMissingError数据协定是其基类的已知类型ErrorBase

答案 2 :(得分:2)

有点晚了,但也许是后代。 =)

如果您不想将每个子类的属性添加到父类,可以使用

在父类静态构造函数中构造已知类型的列表。
 IEnumerable<Assembly> assemblies = AppDomain.CurrentDomain
                                             .GetAssemblies()
                                             .Where(a => !a.GlobalAssemblyCache);

 IEnumerable<Type> serializableTypes = assemblies.SelectMany(a => a.GetTypes())
                                                 .Where(t => IsSerializable(t));

// ...

private static bool IsSerializable(Type type)
{
    return type.GetCustomAttributes(true).Any(a => a is DataContractAttribute);
}

并将此列表传递给de / serializers构造函数。我不知道这个解决方案有多强大,但这就是我正在做的事情,到目前为止它的工作原理。它有点慢,所以一定要缓存结果。