2011-09-08 12 views
12

Tengo el siguiente después de hacer algunas investigaciones sobre otras cuestiones:usar la inyección de la Unidad de Dependencia con servicios WCF

MyServiceHost:

public class MyServiceHost : ServiceHost 
{ 
    public MyServiceHost(IUnityContainer 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 DependencyInjectionInstanceProvider(container)); 
     } 
    } 
} 

DependencyInjectionInstanceProvider:

public class DependencyInjectionInstanceProvider : IInstanceProvider, IContractBehavior 
{  
    private readonly IUnityContainer container;  
    public DependencyInjectionInstanceProvider(IUnityContainer 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.Teardown(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 

} 

MyServiceHostFactory :

public class MyServiceHostFactory : ServiceHostFactory 
{ 
    private readonly IUnityContainer container;  
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses) 
    { 
     return new MyServiceHost(this.container, serviceType, baseAddresses); 
    } 
} 

servicio de correo electrónico con una inyección de constructor intentado: anfitrión

public class EmailValidator : IEmailValidator 
{ 
    private IFakeDAL fakeDAL; 

    public EmailValidator(IFakeDAL fakeDAL) 
    { 
     this.fakeDAL = fakeDAL; 
    } 

    public bool ValidateAddress(string emailAddress) 
    { 
     Console.WriteLine("Validating: {0}", emailAddress); 

     string pattern = @"^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@(([0-9a-zA-Z])+([-\w]*[0-9a-zA-Z])*\.)+[a-zA-Z]{2,9})$"; 
     return Regex.IsMatch(emailAddress, pattern); 
    } 
} 

mi consola para iniciar el servicio:

static void Main(string[] args) 
    { 
     Type serviceType = typeof(EmailValidator); 
     Uri serviceUri = new Uri("http://localhost:8080/"); 

     MyServiceHostFactory shf = new MyServiceHostFactory(); 
     ServiceHost host = shf.CreateServiceHost(serviceType, serviceUri); 
     //ServiceHost host = new ServiceHost(serviceType, serviceUri); 
     host.Open(); 

Mi problema reside en la lógica de acogida de la consola . La llamada CreateServiceHost tiene un error de sintaxis debido al primer argumento que espera una cadena de Constructor y no un Tipo. Lo cual no entiendo porque acepta un parámetro Tipo. Además de eso, no entiendo dónde debería estar mapeando IFakeDAL a una clase concreta. ¿Puedo hacer eso en un archivo app.config o debería registrarlo en otro lugar?

Respuesta

7

ServiceHostFactory es para alojar en IIS. En autohosting debe usar su derivado ServiceHost directamente. Here tienes todo el ejemplo, incluida la configuración de Unity.

+0

Gracias. Parece un muy buen ejemplo. De hecho, podría resolver esto. :) – Elim99

1

El CreateServiceHost method espera una gran variedad de Uri casos, por lo prueba este lugar:

ServiceHost host = shf.CreateServiceHost(serviceType, new[] { serviceUri }); 

Puede asignar las interfaces de tipos en XML o código, pero me gustaría recomendar código, ya XML tiene demasiado alto gastos generales de mantenimiento.

El método Main es una excelente Composition Root, pero si desea configurar el contenedor en ese nivel, tendrás que pasarlo a partir del método Main a MyServiceHostFactory - que es perfectamente bien cuando aloja el servicio en una consola aplicación, pero no funcionará si desea alojarlo en IIS, donde MyServiceHostFactoryshould be the Composition Root, since IIS requires a default constructor.

+0

+1 para comentar sobre dónde debe estar la raíz de composición. Por cierto, amando el libro Mark. –

3

Estoy usando las siguientes clases en mi servicio de Windows para crear servicios WCF e inyectarle dependencias usando la unidad.

UnityInstanceProvider:

internal class UnityInstanceProvider : IInstanceProvider { 

    private readonly IUnityContainer container; 
    private readonly Type contractType; 

    public UnityInstanceProvider(IUnityContainer container, Type contractType) { 
     this.container = container; 
     this.contractType = contractType; 
    } 

    public object GetInstance(InstanceContext instanceContext) { 
     return GetInstance(instanceContext, null); 
    } 

    public object GetInstance(InstanceContext instanceContext, Message message) { 
     return container.Resolve(contractType); 
    } 

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

UnityServiceBehavior:

public class UnityServiceBehavior : IServiceBehavior { 

    private readonly IUnityContainer container; 

    public UnityServiceBehavior(IUnityContainer container) { 
     this.container = container; 
    } 

    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { 
    } 

    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { 
    } 

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { 
     foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers) { 
      foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints) { 
       if (endpointDispatcher.ContractName != "IMetadataExchange") { 
        string contractName = endpointDispatcher.ContractName; 
        ServiceEndpoint serviceEndpoint = serviceDescription.Endpoints.FirstOrDefault(e => e.Contract.Name == contractName); 
        endpointDispatcher.DispatchRuntime.InstanceProvider = new UnityInstanceProvider(this.container, serviceEndpoint.Contract.ContractType); 
       } 
      } 
     } 
    } 
} 

UnityServiceHost:

public class UnityServiceHost : ServiceHost { 

    private IUnityContainer unityContainer; 

    public UnityServiceHost(IUnityContainer unityContainer, Type serviceType) 
     : base(serviceType) { 
     this.unityContainer = unityContainer; 
    } 

    protected override void OnOpening() { 
     base.OnOpening(); 

     if (this.Description.Behaviors.Find<UnityServiceBehavior>() == null) { 
      this.Description.Behaviors.Add(new UnityServiceBehavior(this.unityContainer)); 
     } 
    } 
} 

Con estas clases puede hacer lo siguiente (La configuración de los servicios se realiza en .config):

UnityContainer container = new UnityContainer(); 
UnityServiceHost serviceHost = new UnityServiceHost(container, typeof("Type of Service to host")); 
serviceHost.Open(); 
+0

¿Entonces está mapeando a las clases concretas en su archivo de configuración? – Elim99

+0

¿Te importa mostrar tu configuración de un servicio en el archivo de configuración? – Elim99

Cuestiones relacionadas