【问题标题】:WCF call fails when serialize base class which is a generic List<>序列化作为通用 List<> 的基类时,WCF 调用失败
【发布时间】:2012-11-17 00:59:52
【问题描述】:

我有以下结构:

public class DerivedClass : List<BaseClass>
{
   //Some helper methods used against the List of BaseClass properties

   //Methods
   public  List<BaseClass> GetListOfBaseClasses()
   {
       return (List<BaseClass>)this;
   }
}

我的 WCF 服务知道 BaseClass 对象,但客户端将其作为通用列表派生,现在当我尝试调用该服务时,如下所示:

DerivedClass classD;
FillData(classD)
List<BaseClass> baseClassList = classD.GetListOfBaseClasses();

using (IService myService = ObjectFactory.GetMyService())
{
      myService.DoSomething(baseClassList); //Method is expecting "List<BaseClass>"
}

我得到以下异常:

数据协定名称为“[某些 URI 文本]”的类型“DerivedClass”不是 预期的。考虑使用 DataContractResolver 或添加任何类型 静态已知的已知类型列表 - 例如,通过使用 KnownTypeAttribute 属性或将它们添加到 传递给 DataContractSerializer 的已知类型。

我尝试以各种组合将这些属性添加到我的课程中,但仍然没有成功:

[Serializable]
[KnownType(typeof(List<BaseClass>))]
[XmlInclude(typeof(List<BaseClass>))]
[KnownType(typeof(BaseClass))]
[XmlInclude(typeof(BaseClass))]
public class DerivedClass : List<BaseClass>
{
  /// ...
}

PS- Sheehs,我是唯一一个认为这个网站上的输入字段很时髦的人吗?当我尝试格式化时,事情一直在变化......:|很棒的网站,尽管我无法根据需要输入文本。

【问题讨论】:

    标签: c# xml wcf serialization inherited


    【解决方案1】:

    您必须为您的服务接口添加一个 ServiceKnownTypeAttribute:

    [ServiceKnownType(typeof(DerivedClass))]
    public interface IService
    {
        // Service declaration
    }
    

    【讨论】:

    • 不确定这是否是最好的方法,因为这会将客户端代码紧密耦合到服务接口。该服务只知道 List 并且认为它不应该关心客户端如何发送它。假设另一个客户端想要继承 DerivedClass,那么服务器需要添加另一个属性。不要认为这对软件维护很有好处。所有派生类都作为 List 的包装器发挥作用,因此它可以使用内置的通用 List 操作符/方法来操作列表元素。
    • 当您无法控制服务代码时,这是一个有效的担忧。
    【解决方案2】:

    register known types 有几种方法。但首先请研究有关 DataContracts 的 articlestypes supported by the DataContractSerializer

    请注意,您没有在DerivedClass BaseClass 上添加DataContract 属性。尽管标有Serializable 属性的类是有效的并且可以在 WSDL 中公开,但DataContractAttibute 具有为互操作性而设计的序列化规则,它是 WCF 的首选序列化机制。

    如果您决定在数据合约上注册已知类型,那么这就足够了:

    [DataContract]    
    public class DerivedClass : List<BaseClass>
    {
      /// ...
    }
    
    [DataContract]
    [KnownType(typeof(DerivedClass))]
    public clas BaseClass
    {
        //Add the DataMemberAttribute to the properties you want serialized.
    }
    

    如果您想在服务合同级别注册已知类型,请在ServiceContract 上添加ServiceKnownType 属性。

    【讨论】:

    • BaseClass 如您所述定义。客户端只是从该类派生以利用通用 List 运算符/方法;如果客户简单地采用 has-a 方法而不是 is-a 方法,则该实现将起作用;也就是说,如果客户端不是从 List 派生而是将其设为属性。但这看起来很笨拙。服务是否有必要了解 List 的派生实现?似乎没有,客户端需要将 List 发送过来;客户端派生的 cls 应该对服务隐藏
    • 您不必在服务合同和数据合同级别添加它。一个就够了。另一种选择是配置文件或使用 KnownTypeAttbibute .ctor,它将返回已知类型的 IEnumerable 的辅助方法的名称作为参数。无论如何,我看不到您的派生类的意义。如果没有任何好处(从您的示例和 cmets 可见),它会使您的设计更难理解。删除派生类并在服务操作中使用 IList 或 IEnumerable。这样您就可以封装集合类型并拥有简单的可维护代码。
    • 派生类纯粹是对List进行操作,仅此而已。只是辅助功能。类似于对 List 进行操作的函数;例如,将列表的所有项目属性设置为给定某些条件的值,并根据 List 计算某些值。基本上,所有数据和操作都包含在 DerivedClass 中,而不是在每次需要执行常见任务时都需要创建单独的“Helper”类。现在如果你说拥有两个类(Derived 和 Helper)是一个好的设计,我不同意。
    猜你喜欢
    • 1970-01-01
    • 2013-08-05
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多