2009-08-18 10 views
2

Das SetupWie eine Sammlung von einem Basistyp in WCF akzeptieren

Ich habe einen WCF-Dienst, der einen Basis-Typen macht (zB Tier) sowie einige abgeleitete Typen (zB Löwen, Tiger, und Bär). Ein anderer Typ (z. B. Zoo) enthält eine Eigenschaft, die eine Sammlung des Basistyps ist. Der Basistyp ist Beton, nicht abstrakt, so dass es vollkommen akzeptabel ist, dass die Sammlung Instanzen des Basistyps und/oder der abgeleiteten Typen (in beliebiger Kombination) enthält. Zum Beispiel:

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

Einer meiner Service-Operationen übernimmt diese Art als Parameter, etwa so:

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

All dies ist schön und gut, und das emittierte WSDL sieht für mich völlig in Ordnung. Sie enthält alle Typen und gibt korrekt an, dass die abgeleiteten Typen vom Basistyp erben. So soll ich in der Lage sein, meinen Dienst rufen eine SOAP-Nachricht mit, wie die folgenden:

<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> 

In der obigen SOAP-Nachricht, die Tiere Sammlung enthält eine Instanz des Basistiertypen, eine Instanz der abgeleiteten Tiger type und eine Instanz des abgeleiteten Bear-Typs. WCF sollte diese Nachricht erfolgreich deserialisieren können.

Das Problem

WCF werfen keine Ausnahmen, wenn es die obige Meldung empfängt. Stattdessen werden die abgeleiteten Typen (Tiger und Bär) einfach ignoriert, und zu dem Zeitpunkt, an dem die deserialisierte Nachricht an meinen Code übergeben wird, enthält die Animals-Auflistung nur den Eintrag "Crocodile", da dieser vom Basistyp ist.

Also, ich denke, ich habe zwei Fragen ... Erstens, warum WCF die abgeleiteten Typ Instanzen in der Sammlung nicht deserialisiert. Und zweitens, weil WCF offensichtlich etwas an dieser SOAP-Nachricht nicht mag, warum gibt es keine Ausnahme? Diese Art des stillen Versagens ist sehr beunruhigend.

Antwort

6

Okay ... Ich habe das Problem herausgefunden. Es stellt sich heraus, dass die SOAP-Syntax für dieses Szenario ein wenig mehr Arbeit erfordert, um richtig zu arbeiten. Da die Animals-Auflistung als Array von Animal-Typen definiert ist, müssen alle untergeordneten Elemente in der SOAP-Nachricht Elemente sein, selbst wenn es sich tatsächlich um Instanzen eines abgeleiteten Typs handelt. Der tatsächliche Instanztyp wird durch das Attribut "type" definiert, das Teil des Namespace XMLSchema-instance ist. So sollte meine SOAP-Nachricht wie folgt ausgesehen hat:

<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> 

Natürlich, die noch nicht meine andere Sorge adressiert, das ist, dass der WCF Deserializer eine Ausnahme auslösen soll, wenn es nicht die SOAP-Nachricht nicht versteht . Es sollte nicht einfach Teile der Nachricht ignorieren!

+0

Ausgezeichnet, danke! Ich habe fast implodiert, eine richtige Nachricht mit Soap UI zu erstellen ... – juarola

+0

Ich denke, der WCF-Deserializer ignoriert Teile der Nachricht ist mühsam. Dies würde Sie zwingen, immer den Client und den Server im Lockstep zu halten, nicht unbedingt ein wünschenswertes Merkmal. – Jeff

Verwandte Themen