【问题标题】:How to accept a collection of a base type in WCF如何在 WCF 中接受基类型的集合
【发布时间】:2009-08-18 17:28:02
【问题描述】:

设置

我有一个 WCF 服务,它公开了一个基本类型(例如 Animal)以及一些派生类型(例如 Lion、Tiger 和 Bear)。另一种类型(例如 Zoo)包括一个作为基本类型集合的属性。基类型是具体的,不是抽象的,因此集合包含基类型和/或派生类型(以任何组合形式)的实例是完全可以接受的。例如:

[DataContract, KnownType(typeof(Lion)),
KnownType(typeof(Tiger)), KnownType(typeof(Bear))]
public class Animal
{
    [DataMember]
    public string Species { get; set; }
}

[DataContract]
public class Lion : Animal { }


[DataContract]
public class Tiger : Animal { }


[DataContract]
public class Bear : Animal { }

[DataContract]
public class Zoo 
{
    [DataMember]
    public List<Animal> Animals { get; set; }
}

我的一个服务操作接受此类型作为其参数,如下所示:

[ServiceContract]
public interface IZooService
{
    [OperationContract]
    void SetZoo(Zoo zoo);
}

所有这一切都很好,发出的 WSDL 对我来说看起来非常好。它包含所有类型并正确指示派生类型继承自基类型。因此,我应该能够使用如下所示的 SOAP 消息调用我的服务:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:z="http://zoo.org">
   <soapenv:Header/>
   <soapenv:Body>
      <z:SetZoo>
         <z:Zoo>
            <z:Animals>
               <z:Animal>
                  <z:Species>Crocodile</z:Species>
               </z:Animal>
               <z:Tiger>
                  <z:Species>Bengal</z:Species>
               </z:Tiger>
               <z:Bear>
                  <z:Species>Grizzly</z:Species>
               </z:Bear>
            </z:Animals>
         </z:Zoo>
      </z:SetZoo>
   </soapenv:Body>
</soapenv:Envelope>

在上述 SOAP 消息中,Animals 集合包含一个基本 Animal 类型的实例、一个派生 Tiger 类型的实例和一个派生 Bear 类型的实例。 WCF 应该能够成功反序列化此消息。

问题

WCF 在收到上述消息时不会抛出任何异常。相反,它只是完全忽略了派生类型(Tiger 和 Bear),当反序列化消息传递给我的代码时,Animals 集合仅包含 Crocodile 条目,因为它是基类型。

所以,我想我有两个问题...首先,为什么 WCF 不反序列化集合中的派生类型实例。其次,既然 WCF 显然不喜欢这个 SOAP 消息,为什么不抛出异常呢?这种无声无息的失败非常令人不安。

【问题讨论】:

    标签: wcf inheritance soap collections wsdl


    【解决方案1】:

    好的...我发现了问题所在。事实证明,这个场景的 SOAP 语法需要一些额外的工作才能正确。因为 Animals 集合被定义为 Animal 类型的数组,所以 SOAP 消息中的所有子元素都必须是元素,即使它们实际上是派生类型的实例。实际的实例类型由“type”属性定义,它是 XMLSchema-instance 命名空间的一部分。所以,我的 SOAP 消息应该是这样的:

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:z="http://zoo.org">
    <soapenv:Header/>
    <soapenv:Body>
      <z:SetZoo>
         <z:Zoo>
            <z:Animals>
               <z:Animal>
                  <z:Species>Crocodile</z:Species>
               </z:Animal>
               <z:Animal i:type="z:Tiger">
                  <z:Species>Bengal</z:Species>
               </z:Animal>
               <z:Animal i:type="z:Bear">
                  <z:Species>Grizzly</z:Species>
               </z:Animal>
            </z:Animals>
         </z:Zoo>
      </z:SetZoo>
    </soapenv:Body>
    </soapenv:Envelope>
    

    当然,这仍然没有解决我的另一个问题,即如果 WCF 反序列化程序不理解 SOAP 消息,它应该抛出异常。它不应该只是默默地忽略部分消息!

    【讨论】:

    • 太好了,谢谢!我几乎崩溃了,试图用 Soap UI 创建一个正确的消息......
    • 我认为 WCF 反序列化器不忽略部分消息很麻烦。这将迫使您始终保持客户端和服务器同步,这不一定是理想的特征。
    猜你喜欢
    • 1970-01-01
    • 2011-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多