在WCF服务中使用Unity依赖注入

时间:2011-09-08 22:58:39

标签: wcf dependency-injection unity-container

在对其他问题进行一些研究后,我有以下几点:

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

使用构造函数注入尝试的电子邮件服务:

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

我的控制台主机启动服务:

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

我的问题在于控制台主机逻辑。由于第一个参数需要构造函数字符串而不是类型,因此CreateServiceHost调用具有语法错误。我不明白,因为它接受一个Type参数。除此之外,我不明白我应该将IFakeDAL映射到具体类。我可以在app.config文件中执行此操作,还是应该在其他位置注册?

3 个答案:

答案 0 :(得分:7)

ServiceHostFactory用于在IIS中托管。在自托管中,您应该直接使用派生的ServiceHostHere你有完整的例子,包括Unity配置。

答案 1 :(得分:3)

我在Windows服务中使用以下类来创建WCF服务并使用unity注入依赖项。

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

使用这些类,您可以执行以下操作(服务配置在.config中完成):

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

答案 2 :(得分:1)

CreateServiceHost method需要一组Uri个实例,所以请尝试这样做:

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

您可以将接口映射到XML或代码中的类型,但我建议使用代码,因为XML的维护开销太高。

Main方法非常出色Composition Root,但如果您想在该级别配置容器,则需要将其从Main方法传递给{{1 - 在控制台应用程序中托管服务时完全没问题,但如果要在IIS MyServiceHostFactory should be the Composition Root, since IIS requires a default constructor中托管服务,则无法正常工作。