2009-08-18 12 views
2

セットアップWCFで基本型のコレクションを受け入れる方法

私は基本型(例えば動物)と同様に、いくつかの派生型を公開するWCFサービスを持っている(例えばライオン、トラ、およびくま)。別のタイプ(たとえば、動物園)には、基本タイプのコレクションであるプロパティが含まれます。基底型はコンクリートで、ではなくという抽象型であるため、コレクションに基本型および/または派生型(任意の組み合わせ)のインスタンスを含めることができます。たとえば:

[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; } 
} 

私のサービス操作の1つはそうのように、そのパラメータとして、このタイプを受け入れ:

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

このすべてがうまくで良好であり、放出されたWSDLは、私には完全に正常に見えます。これはすべての型を含み、派生型が基本型から継承することを正しく示します。だから、私は次のようなSOAPメッセージを使用して、私のサービスを呼び出すことができる必要があります:上記の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> 

、動物コレクションは基本動物の種類の1つのインスタンス、派生タイガーのインスタンスが含まれています型、および派生したBear型のインスタンスです。 WCFはこのメッセージを正常に逆シリアル化できます。それが上記のメッセージを受信したときに

問題

WCFは、例外をスローしません。代わりに、派生した型(TigerとBear)を完全に無視し、デシリアライズされたメッセージが自分のコードに渡されるまで、Animalsコレクションは基本型であるため、Crocodileエントリのみを含みます。

私は2つの質問があると思います...まず、WCFがコレクションの派生型インスタンスを逆シリアル化しないのはなぜですか。第二に、WCFは明らかにこのSOAPメッセージに関する何かを好きではないので、例外を投げないのはなぜですか?このような静かな失敗は非常に厄介です。

答えて

6

わかりました。問題を見つけました。このシナリオのSOAP構文では、少しだけ余計な作業が必要になることが判明しました。 AnimalsコレクションはAnimal型の配列として定義されているため、実際に派生型のインスタンスであっても、SOAPメッセージ内のすべての子要素は要素である必要があります。実際のインスタンス型は、XMLSchema-instance名前空間の一部である "type"属性によって定義されます。だから、私のSOAPメッセージは、次のように見ている必要があります。それはSOAPメッセージを理解していない場合は、まだWCFデシリアライザが例外をスローする必要があることである私の他の懸念に対処しない

もちろん
<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> 

、 。メッセージの部分を静かに無視してはいけません!

+0

優秀、ありがとうございます! Soap UIで適切なメッセージを作成しようとすると、私はほぼ爆発しました... – juarola

+0

メッセージの一部を無視しないWCFデシリアライザは面倒です。これにより、必ずクライアントとサーバーをロックステップにしておく必要があります。必ずしも望ましい特性ではありません。 – Jeff

関連する問題