2010-01-11 48 views
18

Tengo servicios de WCF estructurados como sugerido por Miguel Castro. Esto significa que configuré todo de forma manual y tengo una aplicación de consola que hospeda mis servicios utilizando los objetos ServiceHost.Inyectando datos a un servicio de WCF

Quiero mantener mis clases de servicio delgadas, y actualmente solo están transmitiendo llamadas a clases de comportamiento. Mi problema ahora es probar las unidades de las clases de servicio. Quiero inyectar algo a las clases como un parámetro constructor de modo que pueda simular esto y escribir las pruebas unitarias propias. La clase ServiceHost no parece aceptar argumentos, por lo que mi pregunta es cómo puedo inyectar datos a las clases de servicio, ¿o no?

+0

¿está utilizando un contenedor IoC? y si es así, ¿cuál? – Fabiano

+0

Todavía no estoy usando un contenedor de IoC en el servidor. Planeando presentar uno ahora. Estoy usando Unity en el lado del cliente (como venía con Prism), pero considere usar StructureMap en el servidor. Abierto para cualquiera realmente. – stiank81

Respuesta

29

WCF admite Constructor Injection, pero debe pasar unos aros para llegar allí. La clave está en escribir un ServiceHostFactory personalizado. Si bien eso también debe tener un constructor predeterminado, puede usarlo para cablear todos los comportamientos correctos.

Como ejemplo, recientemente escribí uno que usa Castle Windsor para conectar dependencias para la implementación del servicio. La implementación de CreateServiceHost simplemente hace esto:

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

donde this.container es una IWindsorContainer configurado.

WindsorServiceHost se ve así:

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)); 
     } 
    } 
} 

y WindsorInstanceProvider se ve así:

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 
} 

Esto puede parecer mucho, pero darse cuenta de que es reutilizable, el código de uso general que tiene un lugar baja complejidad ciclomática.

Puede seguir el mismo idioma de codificación para implementar Dependency Injection con otro contenedor DI o utilizando la DI de Poor Man.

Aquí hay un older writeup de este idioma que usa la DI de Poor Man.

+0

Thx por su respuesta. Se ve prometedor! ¡Excavaremos en él mañana! – stiank81

+0

Muy útil respuesta. –

+0

¿Cuál fue la ventaja de este enfoque en lugar de utilizar la instalación de Wcf? – CrazyDart

1

¿configuró su servicio como Singleton? descubrí que las implementaciones de IInstanceProvider pueden ser problemáticas cuando se usa un contenedor DI para crear instancias de servicio.

5

Si usaba Castle Windsor, tiene una excelente instalación de integración WCF que le permite hacer esto, y mucho más fácilmente.

Cuestiones relacionadas