【问题标题】:WCF - serializing inherited typesWCF - 序列化继承的类型
【发布时间】:2010-02-24 20:58:43
【问题描述】:

我有这些课程:

[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) 对象。

我有一大堆错误类型,列表将包含它们的组合,那么我该怎么做才能让它工作呢?

【问题讨论】:

    标签: wcf serialization datacontractserializer


    【解决方案1】:

    你应该在你的基类中添加 KnownType 属性

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

    blog 中阅读有关 KnownType 属性的更多信息

    【讨论】:

    • 谢谢,博客条目有所有可能的方式来声明已知类型。
    • 就我而言,使用 KnownType 并没有多大帮助,因为该类型来自我没有引用的单独程序集。其他开发人员正在扩展我的 DataContract 类以添加一些属性。如果我只是想丢弃任何派生类并使用基类怎么办?
    • 这是我必须使用的解决方案:stackoverflow.com/a/8414390/2460073 注意:我必须将客户 DataContractSerializer 应用到 ClientBase
    【解决方案2】:

    试试这个:

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

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

    【讨论】:

    • 那么这意味着我需要在这里指定所有子错误类吗?有没有其他方法可以做到这一点?我不喜欢父类以附加属性和类文件中的“使用”子句的方式知道子类的事实。异常表示“将任何静态未知的类型添加到已知类型列表中 - 例如,通过使用 KnownTypeAttribute 属性或将它们添加到传递给 DataContractSerializer 的已知类型列表中。”那么有什么方法可以将它们添加到已知类型列表中?我该怎么做?
    • 只有在您自己手动序列化合约时,才能将已知类型列表传递给序列化。由于您似乎允许 WCF 为您处理序列化,因此您唯一能做的就是将 KnownTypeAttribute 添加到基类,为它需要了解的每个子类添加一个。
    【解决方案3】:

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

    如果您不想将每个子类的属性添加到父类,您可以在父类静态构造函数中使用

    构造已知类型的列表
     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 构造函数。我不知道这个解决方案有多强大,但这就是我正在做的事情,到目前为止它有效。速度有点慢,所以一定要缓存结果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多