Answers:
你需要实现自定义的组合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容器已经为您完成了此操作(提示:温莎的WCF设施)。
protected
我自己,所以不能从Main()
dep
每个Contract的 InstanceProvider。您可以这样做:您的合约接口ImplementedContracts.Values.First(c => c.Name == "IMyService").ContractBehaviors.Add(new MyInstanceProvider(dep));
在哪里?因此,仅将其注入实际需要它的InstanceProvider中。IMyService
MyService(IDependency dep)
IDependency
您可以简单地创建您的实例,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();
我希望这会使某人的生活更轻松。
InstanceContextMode.Single
)。
用标记的答案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)
{
}
}
instance
。这可能会或可能不会影响性能。如果您希望能够处理并发请求,则整个对象图必须是线程安全的,否则您将获得不确定的错误行为。如果您可以保证线程安全,那么我的解决方案的确是不必要的复杂。如果您不能保证,则需要我的解决方案。
拧一下……我混合了依赖注入和服务定位器模式(但是大多数情况下它仍然是依赖注入,它甚至发生在构造函数中,这意味着您可以拥有只读状态)。
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容器,是一个庞大的,胖的,静态的委托集合,可以为您创建东西。又增加了什么?
我们正面临着同样的问题,并通过以下方式解决了它。这是一个简单的解决方案。
在Visual Studio中,只需创建一个普通的WCF服务应用程序并删除它的界面即可。将.cs文件保留在原处(只需重命名),然后打开该cs文件,并用实现服务逻辑的原始类名替换接口的名称(这样,服务类将使用继承并替换您的实际实现)。添加一个默认构造函数,该构造函数调用基类的构造函数,如下所示:
public class Service1 : MyLogicNamespace.MyService
{
public Service1() : base(new MyDependency1(), new MyDependency2()) {}
}
MyService基类是服务的实际实现。此基类不应具有无参数的构造函数,而应仅具有带有接受依赖项的参数的构造函数。
服务应使用此类而不是原始的MyService。
这是一个简单的解决方案,就像一个魅力:-D
这是一个非常有用的解决方案-尤其是对于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);
....
}