2011-09-16 2 views
7

J'ai deux classes comme ci-dessous:WCF - instanciation d'un objet dans le constructeur DataContract

[DataContract] 
public class Address 
{ 
    [DataMember] 
    public string Line1 
    [DataMember] 
    public string Line2 
    [DataMember] 
    public string City 
    [DataMember] 
    public string State 
    [DataMember] 
    public string Zip 
} 

[DataContract] 
public class Customer 
{ 
    public Customer() 
    { 
     CustomerAddress = new Address(); 
    } 

    [DataMember] 
    public string FirstName 
    [DataMember] 
    public string LastName 
    [DataMember] 
    public Address CustomerAddress 
} 

Que se passerait-il si je produis proxy de mon service qui utilise la classe client? Si je comprends bien le concept, je pense que le constructeur de la classe Customer ne sera pas appelé du côté client et cela peut donner un comportement différent.

Comment puis-je me débarrasser de ce constructeur dans la classe Customer et avoir toujours la propriété CustomerAddress de type Address afin qu'il se comporte comme un objet DTO bête? Quelles sont les lignes directrices générales ou les meilleures pratiques que les gens utilisent pour éviter cette situation?

Répondre

6

Si vous utilisez le DataContractSerializer par défaut pour sérialiser vos objets, alors, oui, votre constructeur n'est pas sérialisé, et toute logique que vous pourriez avoir ne sera pas appelée par votre client lorsque l'objet est désérialisé.

En ce qui concerne votre question sur la suppression de la logique constructeur et l'ajout de la classe Address imbriquée, cela sera pris en compte par le DataContractSerializer. Si j'ai le code comme ceci:

Customer c = new Customer() { 
    FirstName = "David", 
    LastName = "Hoerster", 
    CustomerAddress = new Address() { 
    Line1 = "1 Main Street", 
    City = "Smallville", 
    State = "AA", 
    Zip = "12345" 
    } 
}; 

puis retour que d'une méthode de service, cet objet Customer sera publié en feuilleton correctement avec les informations Address. Le proxy sur le client généré va connaître Address et pourra désérialiser le flux provenant de la méthode de service pour construire correctement votre objet Customer. Votre Customer sera un DTO factice - pas de logique, juste des propriétés.

Découvrez le MSDN article d'Aaron Skonnard sur la sérialisation WCF où il parle de DataContractSerializer.

0

Vous feriez mieux de définir toutes les classes de contrat de données dans un assembly et d'avoir à la fois le projet du serveur et la référence du projet client à l'assembly afin que le comportement d'initialisation puisse être partagé. Lors de la génération d'une référence de service, vous pouvez demander au générateur de code d'utiliser des classes de contrat de données existantes.

1

Si vous générer le client (en utilisant svcutil ou "ajouter une référence de service"), le DataContract généré ressemblera:

[DataContract] 
public class Customer 
{ 
    // empty default constructor 
    public Customer() 
    { 
    } 

    [DataMember] 
    public string FirstName 
    [DataMember] 
    public string LastName 
    [DataMember] 
    public Address CustomerAddress 
} 

Les détails de mise en œuvre ne sont pas reportées. Tout ce qui est généré est ce qui va dans le WSDL, qui est juste les propriétés [DataMember] dans ce cas.

Je mentionne cela parce que votre question initiale demande: "Que se passera-t-il si je génère un proxy".


Si cela est un objet envoyé du serveur au client, alors vous pouvez simplement initialiser toujours CustomerAddress avant de l'envoyer au client. En fait, si votre code d'origine est sur le serveur, alors ce constructeur sera exécuté, et WCF sérialisera le CustomerAddress et n'enverra fondamentalement jamais de null (à moins que vous ne le remettiez à zéro après le constructeur).

Si vous voulez faire en sorte que le client vous envoie toujours un CustomerAddress, alors vous pouvez:

  • ont le serveur chèque nul, comme if(x.CustomerAddress == null) x.CustomerAddress = new Address();
  • marquer le DataMember au besoin, alors le serveur renverra une erreur si le client n'a rien passé: [DataMember(IsRequired=true)] public Address CustomerAddress;

Sinon, je ne pense pas qu'il y ait un moyen de forcer la génération d Client WCF pour initialiser ce champ pour vous.