[WCF] DataContract et héritage

Encore une fois, j'exhume un petit peu de code pour répondre à un problème de POO qui semble simple, mais qui peut devenir cauchemardesque dès que l'on y associe WCF et les DataContract.

Le scénario est le suivant :

  • On a prévu d'utiliser une classe (Item) comme argument d'une méthode de service (Service1).
  • Côté client, l'objet réellement manipulé est une instance d'une classe qui hérite d'Item (ItemDerived).
  • Côté client, la classe de base n'est jamais manipulée directement.
  • Chaque classe ou interface est dans un namespace ou un assembly différent

Le diagramme de classe donne ceci

wcfcontract1

Pour appeler le service on utilise un code tel que celui-ci :


var result = proxy.Process(new ItemDerived()); 

Ou celui-là :

var result = proxy.Process((Item)new ItemDerived());

En l'état, les appels au service provoquent systématiquement une exception du style : le type utilisé lors de la sérialisation n'est pas du type attendu

Note : les messages d'exception semblent varier d'une version du Framework à l'autre.

 

Dans les faits, lors de la sérialisation, le DataContractSerializer est perdu :

  • Il attend une classe Item dans un namespace X avec un nom Y avec un DataContract (namespace X, name Y)
  • Il reçoit une classe ItemDerived dans un namespace U avec un nom V sans DataContract (on utilise juste l'héritage).

Il faut donc aider notre DataContractSerializer à s'en sortir. La solution est toute simple : partager une information claire et commune, le contrat.

La classe item est donc modifiée pour exposer deux constantes : le DataContractNamespace et le DataContractName.

wcfcontract2

Si on ne conserve que les déclarations de classes et des constantes, on obtient ceci :



namespace Demos.Wcf.Base
{
    // Use a data contract as illustrated in the sample below to add composite types to service operations.
    [DataContract(Name = DataContractName, Namespace = DataContractNamespace)]
    public class Item
    {
    
        protected const String DataContractName = "Item";

        protected const String DataContractNamespace = "Datas";

    }
}
namespace Demos.Wcf.Inherit
{
    [DataContract(Name = DataContractName, Namespace = DataContractNamespace)]
    public class ItemDerived : Item
    {

    }
}

En partageant ces informations, on peut maintenant utiliser des classes dérivées avec notre proxy. Il n'y a plus d'exceptions.

Simple comme WCF ;)

Jérémy Jeanson

Comments

You have to be logged in to comment this post.