设置
我有一个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消息,为什么不抛出异常呢?这种无声的失败是非常令人不安的。
答案 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反序列化器应抛出异常。它不应该只是默默地忽略部分消息!