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

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

然而,ServiceHost只允许我传入要创建的类型的名称,而不是传递给它的控制器的参数。

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

到目前为止我发现的是:

  • WCF依赖注入行为 ,这比我正在寻找更多,似乎是我的需求过于复杂。

您将需要实现自定义的ServiceHostFactoryServiceHostIInstanceProvider的组合。

给定这个构造函数签名的服务:

 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容器已经为你做了这个(提示:温莎的WCF设施)。

您可以简单地创建和实例化您的Service并将该实例传递给ServiceHost对象。 你唯一需要做的是为你的服务添加一个[ServiceBehaviour]属性,并用[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(); 

我希望这会使一个人的生活更轻松。

Mark对IInstanceProvider的回答是正确的。

而不是使用自定义的ServiceHostFactory,你也可以使用自定义属性(比如说MyInstanceProviderBehaviorAttribute )。 从Attribute派生它,使其实现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; } } 

然后,将该属性应用于您的服务实现类

 [ServiceBehavior] [MyInstanceProviderBehavior(<params as you want>)] public class MyService : IMyContract 

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

我从马克的回答开始工作,但是(至少在我的情况下),这是不必要的复杂。 其中一个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) { } } 

拧它…我混合了依赖注入和服务定位模式(但主要是它仍然依赖注入,它甚至发生在构造函数,这意味着你可以有只读状态)。

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

服务的依赖关系在其嵌套的Dependencies类的契约中明确指定。 如果您正在使用IoC容器(您尚未修复WCF混乱的容器),则可以将其配置为创建Dependencies实例而不是服务。 这样你就可以得到你的容器给你的温暖的模糊感觉,同时也不必跳过WCF强加的太多的箍环。

这种方法我不会失眠。 其他人也不应该。 毕竟,你是IoC容器,是一个庞大的,静态的委托集合,为你创建东西。 什么是增加一个?

这是一个非常有用的解决方案 – 特别是对于新手的WCF编码人员。 我确实想给任何可能使用IIS托管的服务的用户发一个小提示。 MyServiceHost需要继承WebServiceHost ,而不仅仅是ServiceHost。

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

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

我使用我的类型的静态变量。 不知道这是否是最好的方式,但它适用于我:

 public class MyServer { public static string CustomerDisplayName; ... } 

当我实例化服务主机时,我执行以下操作:

 protected override void OnStart(string[] args) { MyServer.CustomerDisplayName = "Test customer"; ... selfHost = new ServiceHost(typeof(MyServer), baseAddress); .... } 

我们正面临同样的问题,并以如下方式解决。 这是一个简单的解决方案。

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

 public class Service1 : MyLogicNamespace.MyService { public Service1() : base(new MyDependency1(), new MyDependency2()) {} } 

MyService基类是服务的实际实现。 这个基类不应该有一个无参数的构造函数,而只能是带有接受依赖的参数的构造函数。

服务应该使用这个类而不是原来的MyService。

这是一个简单的解决方案,像一个魅力:-D