如何在WCF服务中注入依赖项

3
我正在尝试在WCF服务中注入一些业务服务。我读了这篇非常有趣的文章:如何在我的wcf服务中传递构造函数的值? 接下来我做了以下操作: 自定义ServiceHost
    public class UnityServiceHost : ServiceHost
    {
        public UnityServiceHost(IUnityContainer container, Type serviceType, params Uri[] baseAddresses)
            : base(serviceType, baseAddresses)
        {
            if (container == null)
            {
                throw new ArgumentNullException(nameof(container));
            }

            foreach (ContractDescription contractDescription in ImplementedContracts.Values)
            {
                contractDescription.Behaviors.Add(new UnityInstanceProvider(serviceType, container));
            }
        }
    }

自定义实例提供程序
public class UnityInstanceProvider : IInstanceProvider, IContractBehavior
{
    private readonly Type m_serviceType;
    private readonly IUnityContainer m_container;

    public UnityInstanceProvider(Type serviceType, IUnityContainer container)
    {
        m_serviceType = serviceType;
        m_container = container;
    }
    public object GetInstance(InstanceContext instanceContext, Message message)
    {
        return GetInstance(instanceContext);
    }
    public object GetInstance(InstanceContext instanceContext)
    {
        return m_container.Resolve(m_serviceType);
    }
    public void ReleaseInstance(InstanceContext instanceContext, object instance)
    {
        (instance as IDisposable)?.Dispose();
    }
    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)     {       }
}

我所理解的服务行为如下所示:

[ServiceBehavior] 
public class MyService : IMyService 
{
    public ServerInformationService(ISomeDependency coreManager)
    {
        //...
    }
}

但是我无法进入GetInstance,当我运行代码时,会得到以下错误信息:

提供的服务类型无法作为服务加载,因为它没有默认(无参数)构造函数。要解决问题,请向该类型添加默认构造函数,或将该类型的实例传递给主机。

我做错了什么?看起来我的实例提供程序甚至都没有被使用。

这意味着你尝试注入的依赖项应该有一个无参数的构造函数。 - ArunGeorge
@ArunGeorge 我不这么认为,它甚至没有停在 return m_container.Resolve(m_serviceType); 断点上,我能够在 WPF 之外的依赖项中请求完全相同的服务。 - J4N
你的服务是否托管在IIS中?你是否使用了UnityServiceHost类? - Yacoub Massad
@YacoubMassad 不是的,它是自托管的。我终于找到了问题所在。我使用了ContractBehavior,但应该使用ServiceBehavior。我正在确认一切是否正常工作,并将发布一个答案。 - J4N
1个回答

1
我终于找到了解决方案。我将我的InstanceProvider应用于联系人而不是服务。
以下是我的最终(可工作)解决方案:
public class UnityServiceHost : ServiceHost
{
    public UnityServiceHost(IUnityContainer container, Type serviceType, params Uri[] baseAddresses)
        : base(serviceType, baseAddresses)
    {
        if (container == null)
        {
            throw new ArgumentNullException(nameof(container));
        }
        Description.Behaviors.Add(new UnityInstanceProvider(serviceType, container));
    }
}

而行为和实例提供者:

public class UnityInstanceProvider : IInstanceProvider, IServiceBehavior
{
    private readonly Type m_serviceType;
    private readonly IUnityContainer m_container;

    public UnityInstanceProvider(Type serviceType, IUnityContainer container)
    {
        m_serviceType = serviceType;
        m_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 (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
        {
            ChannelDispatcher cd = (ChannelDispatcher)channelDispatcherBase;
            foreach (EndpointDispatcher ed in cd.Endpoints)
            {
                if (!ed.IsSystemEndpoint)
                {
                    ed.DispatchRuntime.InstanceProvider = this;
                }
            }
        }
    }

    public object GetInstance(InstanceContext instanceContext)
    {
        return m_container.Resolve(m_serviceType);
    }

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

    public void ReleaseInstance(InstanceContext instanceContext, object instance)
    {
        (instance as IDisposable)?.Dispose();
    }
}

它之所以能够正常工作,是因为我自己托管了服务(new UnityServiceHost(...) ....),如果在IIS上,我就无法以这种方式创建行为。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接