2010-01-11 5 views
18

J'ai les services WCF structurés comme suggéré par Miguel Castro. Cela signifie que j'ai tout configuré manuellement et que j'ai une application console hébergeant mes services en utilisant les objets ServiceHost.Injecter des données à un service WCF

Je souhaite limiter la taille de mes classes de service et ne fait que passer des appels à des classes de comportement. Mon problème maintenant est le test unitaire des classes de service. Je veux injecter quelque chose dans les classes en tant que paramètre constructeur, de sorte que je puisse me moquer de cela et écrire des tests unitaires isolés appropriés. La classe ServiceHost ne semble pas accepter les arguments, alors ma question est de savoir comment injecter des données dans les classes de service - ou pas moi?

+0

utilisez-vous un conteneur IoC? et si oui lequel? – Fabiano

+0

Je n'utilise pas encore de conteneur IoC côté serveur. Je prévois d'en présenter un maintenant. J'utilise Unity côté client (comme avec Prism), mais envisage d'utiliser StructureMap sur le serveur. Ouvert à tous. – stiank81

Répondre

29

WCF prend en charge Injection Constructeur, mais vous devez passer quelques cerceaux pour y arriver. La clé réside dans l'écriture d'un ServiceHostFactory personnalisé. Bien que cela aussi, doit avoir un constructeur par défaut, vous pouvez l'utiliser pour câbler tous les comportements corrects. Par exemple, j'ai récemment écrit un qui utilise Castle Windsor pour câbler les dépendances pour l'implémentation du service. La mise en œuvre de CreateServiceHost fait simplement ceci:

return new WindsorServiceHost(this.container, serviceType, baseAddresses); 

this.container est un IWindsorContainer configuré.

WindsorServiceHost ressemble à ceci:

public class WindsorServiceHost : ServiceHost 
{ 
    public WindsorServiceHost(IWindsorContainer container, Type serviceType, params Uri[] baseAddresses) 
     : base(serviceType, baseAddresses) 
    { 
     if (container == null) 
     { 
      throw new ArgumentNullException("container"); 
     } 

     foreach (var cd in this.ImplementedContracts.Values) 
     { 
      cd.Behaviors.Add(new WindsorInstanceProvider(container)); 
     } 
    } 
} 

et WindsorInstanceProvider ressemble à ceci:

public class WindsorInstanceProvider : IInstanceProvider, IContractBehavior 
{ 
    private readonly IWindsorContainer container; 

    public WindsorInstanceProvider(IWindsorContainer container) 
    { 
     if (container == null) 
     { 
      throw new ArgumentNullException("container"); 
     } 

     this.container = container; 
    } 

    #region IInstanceProvider Members 

    public object GetInstance(InstanceContext instanceContext, Message message) 
    { 
     return this.GetInstance(instanceContext); 
    } 

    public object GetInstance(InstanceContext instanceContext) 
    { 
     var serviceType = instanceContext.Host.Description.ServiceType; 
     return this.container.Resolve(serviceType); 
    } 

    public void ReleaseInstance(InstanceContext instanceContext, object instance) 
    { 
     this.container.Release(instance); 
    } 

    #endregion 

    #region IContractBehavior Members 

    public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) 
    { 
    } 

    public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime) 
    { 
    } 

    public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime) 
    { 
     dispatchRuntime.InstanceProvider = this; 
    } 

    public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint) 
    { 
    } 

    #endregion 
} 

Cela peut ressembler à beaucoup, mais notez qu'il est réutilisable, le code d'usage général qui a plutôt faible complexité cyclomatique.

Vous pouvez suivre le même idiome de codage pour implémenter l'injection de dépendances avec un autre conteneur DI ou en utilisant DI de Poor Man.

Voici un older writeup de cet idiome qui utilise DI de Poor Man.

+0

Thx pour votre réponse. On dirait prometteur! Je vais y aller demain! – stiank81

+0

Réponse très utile. –

+0

Quel était l'avantage de cette approche plutôt que d'utiliser le service Wcf ??? – CrazyDart

1

avez-vous configuré votre service en tant que singleton? J'ai découvert que les implémentations IInstanceProvider peuvent être problématiques lors de l'utilisation d'un conteneur DI pour créer les instances de service.

5

Si vous utilisiez Castle Windsor, il dispose d'un excellent système d'intégration WCF qui vous permet de le faire, et beaucoup plus facilement.

Questions connexes