2009-08-14 11 views
1

J'écris une application client/serveur, où le client est une application Windows Forms et le serveur est un service WCF hébergé dans un service Windows. Notez que je contrôle les deux côtés de l'application. J'essaie d'implémenter la pratique du codage par rapport à une interface: c'est-à-dire que j'ai un assemblage partagé qui est référencé par l'application cliente. Ce projet contient mes contrats de service et interfaces WCF qui seront exposés aux clients. J'essaye seulement d'exposer des interfaces aux clients, de sorte qu'ils soient seulement dépendants d'un contrat, pas d'une implémentation spécifique. Une des raisons pour cela est que je peux avoir ma mise en œuvre du service, et le changement de domaine à tout moment sans avoir à recompiler et redéployer les clients. Les interfaces/contrats ne seront pas modifiés dans ce cas. Je dois seulement recompiler et redéployer mon service WCF.Usines ou Injection de dépendances pour l'instanciation d'objet dans WCF lors du codage sur une interface?

Le problème de conception auquel je fais face est: sur le client, comment créer de nouvelles instances d'objets, par ex. ICustomer, si le client ne connaît pas l'implémentation concrète Customer? J'ai besoin de créer un nouveau client pour être enregistré dans la base de données. Est-ce que j'utilise l'injection de dépendances ou une classe Factory pour instancier de nouveaux objets ou dois-je simplement autoriser le client à créer de nouvelles instances d'implémentations concrètes?

Je ne fais pas TDD, et je n'aurai typiquement qu'une implémentation de ICustomer ou toute autre interface exposée.

Répondre

0

Eh bien, je pense que vous confondez (ou mélanger) deux choses:

  • votre contrat de service décrit uniquement les fonctions de votre service, des choses comme expose FindCustomer ou AddCustomer - pour les opérations Votre client n'a besoin que de connaître l'interface, et lorsque vous ajoutez un proxy client (en utilisant "Add Service Reference"), vous obtiendrez une classe concrète YourServiceClient dans votre proxy client qui implémente ces appels

  • le Le contrat de données décrit les données qui vont et viennent, et ce sont toujours des classes concrètes - Customer, Invoice etc. - puisque celles-ci sont basées sur un schéma XML. Ceux-ci sont définis sur le serveur et le client, lors de l'ajout d'une référence de service, déduira ces types du WSDL/XSD publié par le service et créera des classes concrètes côté client pour ces données. Ceux-ci sont et non exactement les mêmes classes que le serveur utilise - ils se ressemblent, et leur exigence principale est qu'ils sérialisent et désérialisent à partir de XML le même - mais ils sont vraiment différentes classes (espace de noms .NET différent, probablement).

Donc, pour votre fonctionnalité, vous avez le contrat de service qui vous avez vraiment besoin de partager comme une interface - qui est suffisante, et le client va créer une « classe proxy » (la classe YourServiceClient) à partir de cette interface. Le client ne dépend pas sur l'implémentation du serveur ou sa classe concrète là. D'un autre côté, les données échangées - étant sérialisées au format XML par défaut - seront toujours des classes concrètes (pas d'interfaces) qui sont déduites du WSDL/XSD - encore une fois, le client ne dépend pas du serveur du serveur. classes - seulement sur leur "empreinte de sérialisation XML", pour ainsi dire.

Maintenant, je ne suis pas sûr que cela vous aide un :-) beaucoup, mais au moins il fait, espérons-choses comme elles sont un peu plus clair - ou non?

Marc

+0

@marc_s: Je pense que vous avez mal compris tout à fait ma question. Je pense que je devrais le modifier pour le rendre plus clair. Je comprends parfaitement la WCF et tout ce que vous avez expliqué. Mais je n'utilise pas WCF comme ça. Le client et le serveur partagent l'assembly MyProject.Shared, qui contient mes types et interfaces (ou les contrats comme je l'appelle, mais pas [DataContract]). Ils partagent donc exactement les mêmes types du même assemblage. J'utilise le NetDataContractSerializer, et en utilisant WCF pour émuler quelque chose de plus proche de .Net remoting –

1

Nous avons discuté de le faire en interne pour les applications d'entreprise où nous contrôlons les deux côtés d'application, comme un gain de productivité pour les clients .NET. Le jury est toujours sur celui-ci.

Cependant, lors de la discussion ayant des contrats dans une bibliothèque partagée (entre le client et le service) Ceci comprend généralement les lesservices contrats ([ServiceContract]), ainsi que les entités ([DataContract]) pour tous les paramètres aux opérations de service. Ces types sont traditionnellement les béton types que vous attendez pour ces opérations de service.

Dans votre cas, votre DTO implémente une interface, comme Iaide, les propriétés qui représentent la mise en œuvre client, et est un [DataContract]. En supposant que le type sérialise passe correctement au service (en utilisant NetDataContractSerializer), alors je suppose que le client peut à peu près tout shove mise en œuvre concrète qu'ils veulent - le service est seulement intéressé par ce qui est conforme à Iaide. Un client peut créer n'importe quelle instance concrète d'ICustomer qu'il souhaite: OrderingCustomer, FinanceCustomer, etc. Tant que le type implémente l'interface ICustomer de service, il pourrait être transmis comme valeur à une opération de service s'il sérialise correctement. par exemple.

public class OrderingCustomer : ICustomer 
{ 
} 

Je ne suis pas sûr que vous n'obtiendrez aucun impact client. Si vous changez un type d'interface (ajoutez la propriété à ICustomer), vos clients devront recompiler. Si vous ajoutez un paramètre, même un type de noyau .NET (par exemple int), vos clients devront recompiler. C'est effectivement le même impact que le client met à jour sa référence de service et la recompilation.

Cependant, si votre ne changer votre mise en œuvre de services ou de comportement (par exemple bug fix), puis dans les deux cas (types partagés ou référence de service), les clients auront besoin ne rien faire tant que ce contrat entre vous et votre client ne change pas. Bien sûr, j'aimerais aussi entendre toutes les expériences que vous avez eues avec ceci qui prouvent que c'est faux!

Cette pratique tuerait aussi complètement votre histoire interopérable avec les systèmes non-.NET. Aussi sûr que je balaie celui-ci sous le tapis, un département quelque part entendra parler de votre service super spiffy et voudra l'utiliser .... et ils seront en cours d'exécution de la pile Java, ou COBOL, ou FORTRAN .. etc. :)

+0

Vous avez décrit ce que j'essaie d'atteindre avec précision, mais vous n'avez pas répondu à ma question - comment créer de nouvelles instances d'objets sur le client côté. Vous ne pouvez évidemment pas faire ceci: 'ICustomer cus = new ICustomer', et vous ne pouvez pas faire ceci non plus:' ICustomer cus = new Customer() 'puisque le client n'a pas accès à l'assembly contenant le' Client: Implémentation d'ICustomer. –

+0

ah, je pense que j'ai raté un point dans ma réponse! C'est ce que je reçois pour lire trop vite! :) Le client doit avoir accès à ICustomer, si ICustomer est un paramètre de l'opération de service. Sinon, comment vont-ils invoquer le service? Ils ne sauront pas à quoi ressemble un client IC - ils ne peuvent pas le faire à la volée, c'est un contrat binaire entre le client et le service. Le client ne peut pas créer sa propre implémentation ICustomer et l'utiliser, vous devez le fournir. :) –

+0

Vous avez encore manqué un point critique. Le client a accès à 'ICustomer', il est dans l'assembly partagé, référencé par le client et le serveur. C'est un impératif! Mais 'ICustomer' est une interface - et vous ne pouvez pas instancier un type d'interface, comme expliqué ci-dessus. –

1

Je suis venu sur la même question dans mon développement WCF. Le fait est il doit y avoir une implémentation concrète de vos contrats de données des deux côtés de la communication. Alors d'où viennent ces implémentations? Du côté du serveur, les implémentations sont généralement vos objets métier, avec toute leur logique métier et ainsi de suite. Et vous ne voulez pas utiliser ces implémentations sur le client - cela signifierait les placer dans l'assembly partagé, et vous ne le souhaitez pas pour plusieurs raisons. Le client a donc besoin de son propre ensemble de classes concrètes. Soit vous allez les écrire vous-même, soit vous les générerez automatiquement.

L'écriture des implémentations vous est fastidieux.Parce que les objets client sont généralement simples - tout ce qu'ils font vraiment est stocker des données - la génération de code est probablement la voie à suivre. À ce stade, vous avez quelques choix: Vous pouvez générer du code basé sur le WSDL via Add Service Reference, ou vous pouvez générer des classes à l'exécution en fonction des interfaces en utilisant un framework quelconque. Les deux approches vous donnent les avantages du codage sur une interface: Tant que l'interface ne change pas, le serveur et le client peuvent être modifiés et reconstruits indépendamment. Dans un cas, l'interface est le WSDL et dans l'autre, c'est une interface CLR, mais comme WCF génère le WSDL basé sur l'interface CLR, ils sont vraiment identiques. Personnellement j'aime bien ajouter une référence de service parce que c'est déjà là et n'ajoute aucune dépendance à mon projet, mais choisis celui que tu préfères.

0

Vous avez probablement déjà reçu votre réponse mais j'essaye de faire quelque chose de similaire pour le moment - injecter mes dépôts dans mes services WCF, donc ces services n'ont aucune dépendance sur le code qui accède à la base de données. J'ai trouvé les articles suivants qui je pense peut aider à répondre à votre question:

http://geekswithblogs.net/ballhaus/archive/2009/12/12/unit-testing-your-wcf-service.aspx http://www.silverlightshow.net/items/Deep-dive-into-WCF-part-1-TDD.aspx

HTH

Ciaran