WCF et array parameter

Lorsqu’on utilise WCF pour exposer une méthode qui renvoie un objet de type non-standard, définie ainsi:

public CustomerResponse GetCustomers(Customer customer);

Et que la classe CustomerResponse contient une propriété de type tableau d’objet non-standard (customerBean[]), défini ainsi:

[MessageContract]
public partial class CustomerResponse
{
    [MessageBodyMember]
    public int ReturnCode { get; set; }

    [MessageBodyMember]
    public customerBean[] Customers { get; set; }
}

Alors, le WSDL se présentera sous cette forme (notez l’utilisation de la valeur « Arrayof… ») :

<xsd:element name="CUSTOMERResponse">
  <xsd:complexType>
    <xsd:sequence>
      <xsd:element minOccurs="0" name="ReturnCode" type="xsd:int" />
      <xsd:element xmlns:a="http://schemas.datacontract.org/2004/07/Common.InternalObjects" minOccurs="0" name="Customers" nillable="true" type="a:ArrayOfcustomerBean" />
    </xsd:sequence>
  </xsd:complexType>
</xsd:element>

Contenant la définition de la classe customerBean:

<xsd:complexType name="ArrayOfcustomerBean">
  <xsd:sequence>
    <xsd:element minOccurs="0" maxOccurs="unbounded" name="customerBean" nillable="true" type="tns:customerBean" />
  </xsd:sequence>
</xsd:complexType>

<xsd:element name="ArrayOfcustomerBean" nillable="true" type="tns:ArrayOfcustomerBean" />

<xsd:complexType name="customerBean">
   <xsd:sequence>
     <xsd:element minOccurs="0" name="CODE" nillable="true" type="xsd:string" />
     <xsd:element minOccurs="0" name="ID" nillable="true" type="xsd:string" />
     <xsd:element minOccurs="0" name="NAME" nillable="true" type="xsd:string" />
     <xsd:element minOccurs="0" name="SIREN" nillable="true" type="xsd:string" />
   </xsd:sequence>
</xsd:complexType>

<xsd:element name="customerBean" nillable="true" type="tns:customerBean" />

Les paramètres récupérés par l’appel à la méthode GetCustomers() vont être structurés de la sorte:

array(1) {
  [0]=> object(stdClass)#47 (1) {
    ["customerBean"]=> array(11) {
      [0]=> object(stdClass)#46 (6) {
        ["CODE"]=> string(10) "3022"
        ["ID"]=> string(4) "3400"
        ["NOM"]=> string(11) "100 LIMITES"
        ["SIREN"]=> string(14) "12345123401298"
      }
    }
  }
}

C’est à dire, un tableau imbriqué dans un autre.

Or, dans mon cas, je souhaite retrouver le contenu de mon tableau directement dans l’objet Customers, et ne pas avoir à passer par un tableau intermédiaire inutile.

La solution consiste à utiliser les attributs de sérialisation classique, pour indiquer que notre tableau doit être considéré comme un type customerBean

Il faut placer l’attribut [XmlSerializerFormat] (System.Xml.Serialization) sur l’interface de notre service:

[ServiceContract(Name = "WebService", Namespace = "http://domain.fr:81/")]
[XmlSerializerFormat]
public interface IWebServiceEspaceCourtier
{
   [OperationContract]
   public CustomerResponse GetCustomers(Customer customer);
}

Ceci nous permet d’utiliser l’attribut XmlElementAttribute sur notre propriété concernée:

[XmlElementAttribute("Customers", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
[MessageBodyMember]
public customerBean[] Customers { get; set; }

 

En marquant notre propriété avec l’attribut précédent, le WSDL généré n’est plus le même, il ne marque plus la propriété comme étant un type « ArrayOf » :

<xsd:element name="CUSTOMERResponse">
  <xsd:complexType>
    <xsd:sequence>
      <xsd:element minOccurs="1" maxOccurs="1" name="ReturnCode" type="xsd:int" />
      <xsd:element minOccurs="0" maxOccurs="unbounded" form="unqualified" name="customers" type="tns:customerBean" />
    </xsd:sequence>
  </xsd:complexType>
</xsd:element>

Avec la définition directe du bean:

<xsd:complexType name="customerBean">
   <xsd:sequence>
     <xsd:element minOccurs="0" name="CODE" nillable="true" type="xsd:string" />
     <xsd:element minOccurs="0" name="ID" nillable="true" type="xsd:string" />
     <xsd:element minOccurs="0" name="NAME" nillable="true" type="xsd:string" />
     <xsd:element minOccurs="0" name="SIREN" nillable="true" type="xsd:string" />
   </xsd:sequence>
</xsd:complexType>

Du coup, au moment de l’appel, les paramètres récupérés sont encapsulé dans un seul tableau:

array(4) {
  [0]=> object(stdClass)#47 (6) {
      ["ID"]=> string(8) "3_400036"
      ["CODE"]=> string(6) "400036"
      ["NOM"]=> string(12) "BRIGHT CLEAN"
      ["SIREN"]=> string(14) "35336322100017"
  }
}

Ce changement se vérifie également dans la structure de la requête SOAP :

Avant:

<CUSTOMERResponse xmlns="http://domain.fr:81/">
  <ReturnCode>0</ReturnCode>
  <CUSTOMER xmlns:a="http://schemas.datacontract.org/2004/07/Common.InternalObjects">
     <a:customerBean>
        <a:CODE>3022</a:CODE>
        <a:ID>3400</a:ID>
        <a:NOM>100 LIMITES</a:NOM>
        <a:SIREN>12345123401298</a:SIREN>
     </a:customerBean>
  </CUSTOMER>
</CUSTOMERResponse>

Après :

<CUSTOMERResponse xmlns="http://domain.fr:81/">
  <ReturnCode>0</ReturnCode>
  <CUSTOMER xmlns="">
    <CODE xmlns="http://domain.fr:81/">3074</CODE>
    <ID xmlns="http://domain.fr:81/">1062</ID>
    <NOM xmlns="http://domain.fr:81/">BRIGHT CLEAN</NOM>
    <SIREN xmlns="http://domain.fr:81/">35338221200017</SIREN>
  </CUSTOMER>
</CUSTOMERResponse>

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s