将 Unity 依赖注入与 WCF 服务结合使用

发布于 2024-12-04 05:18:52 字数 4000 浏览 0 评论 0 原文

对其他问题进行一些研究后,我得到以下结果:

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 调用存在语法错误,因为第一个参数需要构造函数字符串而不是类型。我不明白,因为它确实接受类型参数。除此之外,我不明白应该在哪里将 IFakeDAL 映射到具体的类。我可以在 app.config 文件中执行此操作还是应该在其他地方注册?

I have the following after doing some research on other questions:

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

Email Service with an attempted Constructor Injection:

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

My Console Host to start the Service:

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

My problem resides in the console host logic. The CreateServiceHost call has a syntax error due to the first argument expecting a Constructor string and not a Type. Which I don't understand since it does accept a Type parameter. In addition to that I don't understand where I should be mapping IFakeDAL to a concrete class. Can I do that in an app.config file or should I register that somewhere else?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

何以畏孤独 2024-12-11 05:18:52

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

ServiceHostFactory is for hosting in IIS. In self hosting you should use your derived ServiceHost directly. Here you have whole example including Unity configuration.

萤火眠眠 2024-12-11 05:18:52

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

I´m using the following classes in my windows service to create WCF services and inject dependencies to it using 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));
        }
    }
}

With this classes you can do the following (The configuration of services is done in .config):

UnityContainer container = new UnityContainer();
UnityServiceHost serviceHost = new UnityServiceHost(container, typeof("Type of Service to host"));
serviceHost.Open();
赏烟花じ飞满天 2024-12-11 05:18:52

CreateServiceHost 方法需要一个 Uri 数组实例,所以尝试这样做:

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

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

Main 方法是一个优秀的组合根 ,但如果您想在该级别配置容器,则需要将其从 Main 方法传递到 MyServiceHostFactory - 当您托管服务时,这完全没问题在控制台应用程序,但如果您想将其托管在 IIS 中,则无法工作,其中 MyServiceHostFactory 应该是组合根,因为 IIS 需要默认构造函数

The CreateServiceHost method expects an array of Uri instances, so try this instead:

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

You can map interfaces to types in either XML or code, but I'd recommend code, since XML has too high a maintenance overhead.

The Main method is an excellent Composition Root, but if you want to configure the container at that level, you'll need to pass it from the Main method to MyServiceHostFactory - which is perfectly fine when you host the service in a console application, but will not work if you want to host it in IIS, where MyServiceHostFactory should be the Composition Root, since IIS requires a default constructor.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文