如何在WCF中接受基类型的集合

时间:2009-08-18 17:28:03

标签: wcf inheritance soap collections wsdl

设置

我有一个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消息,为什么不抛出异常呢?这种无声的失败是非常令人不安的。

1 个答案:

答案 0 :(得分:6)

好的......我发现了问题。事实证明,此方案的SOAP语法需要一些额外的工作才能正确完成。因为Animals集合被定义为Animal类型的数组,所以SOAP消息中的所有子元素都需要是元素,即使它们实际上是派生类型的实例。实际的实例类型由“type”属性定义,该属性是XMLSchema实例命名空间的一部分。所以,我的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>

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