如何将值传递给wcf服务的构造函数?

如何将值传递给wcf服务的构造函数?,wcf,dependency-injection,factory-pattern,Wcf,Dependency Injection,Factory Pattern,我想将值传递到实现我的服务的类的构造函数中 但是,ServiceHost只允许我传入要创建的类型的名称,而不允许传入要传递给其contrstructor的参数 我希望能够通过创建我的服务对象的工厂 到目前为止,我发现: 这比我想要的要多,而且对于我的需求来说似乎过于复杂 您需要实现自定义ServiceHostFactory、ServiceHost和IInstanceProvider的组合 给定具有此构造函数签名的服务: public MyService(IDependency dep) 下面

我想将值传递到实现我的服务的类的构造函数中

但是,ServiceHost只允许我传入要创建的类型的名称,而不允许传入要传递给其contrstructor的参数

我希望能够通过创建我的服务对象的工厂

到目前为止,我发现:

  • 这比我想要的要多,而且对于我的需求来说似乎过于复杂

您需要实现自定义
ServiceHostFactory
ServiceHost
IInstanceProvider
的组合

给定具有此构造函数签名的服务:

public MyService(IDependency dep)
下面是一个可以提升MyService的示例:

public class MyServiceHostFactory : ServiceHostFactory
{
    private readonly IDependency dep;

    public MyServiceHostFactory()
    {
        this.dep = new MyClass();
    }

    protected override ServiceHost CreateServiceHost(Type serviceType,
        Uri[] baseAddresses)
    {
        return new MyServiceHost(this.dep, serviceType, baseAddresses);
    }
}

public class MyServiceHost : ServiceHost
{
    public MyServiceHost(IDependency dep, Type serviceType, params Uri[] baseAddresses)
        : base(serviceType, baseAddresses)
    {
        if (dep == null)
        {
            throw new ArgumentNullException("dep");
        }

        foreach (var cd in this.ImplementedContracts.Values)
        {
            cd.Behaviors.Add(new MyInstanceProvider(dep));
        }
    }
}

public class MyInstanceProvider : IInstanceProvider, IContractBehavior
{
    private readonly IDependency dep;

    public MyInstanceProvider(IDependency dep)
    {
        if (dep == null)
        {
            throw new ArgumentNullException("dep");
        }

        this.dep = dep;
    }

    #region IInstanceProvider Members

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

    public object GetInstance(InstanceContext instanceContext)
    {
        return new MyService(this.dep);
    }

    public void ReleaseInstance(InstanceContext instanceContext, object instance)
    {
        var disposable = instance as IDisposable;
        if (disposable != null)
        {
            disposable.Dispose();
        }
    }

    #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
}
在MyService.svc文件中注册MyServiceHostFactory,或者在代码中直接使用MyServiceHost进行自托管场景


您可以很容易地推广这种方法,事实上一些DI容器已经为您完成了这项工作(提示:Windsor的WCF设施)。

Mark使用
IInstanceProvider的回答是正确的

除了使用自定义ServiceHostFactory,还可以使用自定义属性(例如
MyInstanceProviderBehaviorAttribute
)。从
属性
派生它,使其实现
IServiceBehavior
,并实现
IServiceBehavior.ApplyDispatchBehavior
方法,如

// YourInstanceProvider implements IInstanceProvider
var instanceProvider = new YourInstanceProvider(<yourargs>);

foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
{
    foreach (var epDispatcher in dispatcher.Endpoints)
    {
        // this registers your custom IInstanceProvider
        epDispatcher.DispatchRuntime.InstanceProvider = instanceProvider;
    }
}
//YourInstanceProvider实现IInstanceProvider
var instanceProvider=new YourInstanceProvider();
foreach(serviceHostBase.ChannelDispatchers中的ChannelDispatcher)
{
foreach(dispatcher.Endpoints中的var epDispatcher)
{
//这将注册您的自定义IInstanceProvider
epDispatcher.DispatcheRuntime.InstanceProvider=InstanceProvider;
}
}
然后,将该属性应用于服务实现类

[ServiceBehavior]
[MyInstanceProviderBehavior(<params as you want>)]
public class MyService : IMyContract
[服务行为]
[MyInstanceProviderBehavior()]
公共类MyService:IMyContract

第三个选项:您还可以使用配置文件应用服务行为。

我根据Mark的回答进行了工作,但是(至少在我的场景中),这是不必要的复杂。其中一个
ServiceHost
构造函数接受服务实例,您可以直接从
ServiceHostFactory
实现传入该实例

以Mark的例子为例,它如下所示:

public class MyServiceHostFactory : ServiceHostFactory
{
    private readonly IDependency _dep;

    public MyServiceHostFactory()
    {
        _dep = new MyClass();
    }

    protected override ServiceHost CreateServiceHost(Type serviceType,
        Uri[] baseAddresses)
    {
        var instance = new MyService(_dep);
        return new MyServiceHost(instance, serviceType, baseAddresses);
    }
}

public class MyServiceHost : ServiceHost
{
    public MyServiceHost(MyService instance, Type serviceType, params Uri[] baseAddresses)
        : base(instance, baseAddresses)
    {
    }
}

我们也面临着同样的问题,并通过以下方式解决了它。这是一个简单的解决方案

在VisualStudio中,只需创建一个普通的WCF服务应用程序并删除它的接口。保留.cs文件(只需重命名它)并打开该cs文件,然后用实现服务逻辑的原始类名替换接口的名称(这样,服务类使用继承并替换实际实现)。添加一个调用基类构造函数的默认构造函数,如下所示:

public class Service1 : MyLogicNamespace.MyService
{
    public Service1() : base(new MyDependency1(), new MyDependency2()) {}
}
MyService基类是服务的实际实现。该基类不应具有无参数构造函数,而应仅具有接受依赖项的参数的构造函数

服务应该使用这个类,而不是原始的MyService


这是一个简单的解决方案,工作起来很有魅力:-D

我使用我类型的静态变量。不确定这是否是最好的方法,但对我来说很有效:

public class MyServer
{   
    public static string CustomerDisplayName;
    ...
}
在实例化服务主机时,我会执行以下操作:

protected override void OnStart(string[] args)
{
    MyServer.CustomerDisplayName = "Test customer";

    ...

    selfHost = new ServiceHost(typeof(MyServer), baseAddress);

    ....
}

您只需创建
服务的实例,并将该实例传递给
服务主机
对象。您只需为您的服务添加一个
[ServiceBehavior]
属性,并用
[DataContract]
属性标记所有返回的对象

这是一个模型:

namespace Service
{
    [ServiceContract]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class MyService
    {
        private readonly IDependency _dep;

        public MyService(IDependency dep)
        {
            _dep = dep;
        }

        public MyDataObject GetData()
        {
            return _dep.GetData();
        }
    }

    [DataContract]
    public class MyDataObject
    {
        public MyDataObject(string name)
        {
            Name = name;
        }

        public string Name { get; private set; }
    }

    public interface IDependency
    {
        MyDataObject GetData();
    }
}
以及用法:

var dep = new Dependecy();
var myService = new MyService(dep);
var host = new ServiceHost(myService);

host.Open();

我希望这将使某些人的生活变得更轻松。

这是一个非常有用的解决方案-尤其是对于WCF新手来说。我确实想为任何可能将其用于IIS托管服务的用户发布一些提示。MyServiceHost需要继承WebServiceHost,而不仅仅是ServiceHost

public class MyServiceHost : WebServiceHost
{
    public MyServiceHost(MyService instance, Type serviceType, params Uri[] baseAddresses)
        : base(instance, baseAddresses)
    {
    }
}

这将为IIS中的端点创建所有必要的绑定等。

该死……我混合了依赖项注入和服务定位器模式(但主要还是依赖项注入,它甚至发生在构造函数中,这意味着您可以具有只读状态)

公共类MyService:IMyService
{
私有只读依赖项_依赖项;
//在创建服务主机之前设置此项。这可以使用您的IOC容器或任何东西。
//如果您不喜欢此处显示的可变性(IoC容器在配置后通常是不可变的)
//您可以使用某种一次写入对象
//或更高级的方法,如身份验证访问
公共静态函数GetDependencies{get;set;}
公共类依赖项
{
//无论你的服务需要什么。
公共内容1内容1{get;}
公共事物2事物2{get;}
公共依赖项(Thing1 Thing1,Thing2 Thing2)
{
Thing1=Thing1;
Thing2=Thing2;
}
}
公共MyService()
{
_dependencies=GetDependencies();//这将在运行时以与IoC容器完全相同的方式运行,前提是它没有正确配置。没有区别
}
}
服务的依赖项在其嵌套的
依赖项
类的契约中明确指定。如果您使用的是IoC容器(尚未为您修复WCF混乱的容器),则可以将其配置为创建
依赖项
实例,而不是服务。通过这种方式,您可以获得容器给您的温暖模糊感觉,同时也不必跳过WCF施加的太多限制

我不会因为这个方法而失眠的。其他人也不应该这样。毕竟,你知道IoC容器是bi
public class MyService : IMyService
{
    private readonly Dependencies _dependencies;

    // set this before creating service host. this can use your IOC container or whatever.
    // if you don't like the mutability shown here (IoC containers are usually immutable after being configured)
    // you can use some sort of write-once object
    // or more advanced approach like authenticated access
    public static Func<Dependencies> GetDependencies { get; set; }     
    public class Dependencies
    {
        // whatever your service needs here.
        public Thing1 Thing1 {get;}
        public Thing2 Thing2 {get;}

        public Dependencies(Thing1 thing1, Thing2 thing2)
        {
            Thing1 = thing1;
            Thing2 = thing2;
        }
    }

    public MyService ()
    {
        _dependencies = GetDependencies(); // this will blow up at run time in the exact same way your IoC container will if it hasn't been properly configured up front. NO DIFFERENCE
    }
}
var myService = new Service(argumentOne, argumentTwo, . . . etc.);
var host = new WebServiceHost(myService, new Uri("http://localhost:80"));
var behavior = host.Description.Behaviors.Find<ServiceBehaviorAttribute>();
behavior.InstanceContextMode = InstanceContextMode.Single;
host.Open();