Using NInject with WCF is the same as using any other DI container. To do this you need to use 3 WCF extensibility points: InstanceProvider
, ServiceHost
and ServiceHostFactory
.
The custom InstanceProvider
will be used to create service instances by using a constructor with parameters. The code can be seen below.
public class NInjectInstanceProvider : IInstanceProvider, IContractBehavior
{
private readonly IKernel kernel;
public NInjectInstanceProvider(IKernel kernel)
{
if (kernel == null) throw new ArgumentNullException("kernel");
this.kernel = kernel;
}
public object GetInstance(InstanceContext instanceContext, Message message)
{
//delegate to GetInstance(InstanceContext)
return GetInstance(instanceContext);
}
public object GetInstance(InstanceContext instanceContext)
{
//resolve the service instance
return kernel.Get(instanceContext.Host.Description.ServiceType);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
kernel.Release(instance);
}
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)
{
}
}
This custom instance provider is then applied to every contract in the ServiceHost
class. This is done by using a contract behavior. This is why the instance provider also implements IContractBehavior
. You can see that we apply the instance provider in the ApplyDispatchBehavior
method. The code below presents the ServiceHost
and ServiceHostFactory
implementations.
public class NInjectServiceHostFactory : ServiceHostFactory
{
private readonly IKernel kernel;
public NInjectServiceHostFactory()
{
kernel = new StandardKernel();
kernel.Bind<IDummyDependency>().To<DummyDepencency>();
//add the rest of the mappings here
}
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return new NInjectServiceHost(kernel, serviceType, baseAddresses);
}
}
public class NInjectServiceHost : ServiceHost
{
public NInjectServiceHost(IKernel kernel, Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
if (kernel == null) throw new ArgumentNullException("kernel");
foreach (var cd in ImplementedContracts.Values)
{
cd.Behaviors.Add(new NInjectInstanceProvider(kernel));
}
}
}
You can see that inside the ServiceHost
constructor we iterate over all implemented contracts and apply the behavior we need. In our case this is NInjectInstanceProvider
.
The custom ServiceHostFactory
is required in order to create the DI container and populate it with mappings. We then override the CreateServiceHost
method in order to provide our custom ServiceHost
implementation.
The setup is complete at this point. All you need to do is create a WCF service that has a dependency on IDummyDependency
. Also, don't forget to set the Factory
attribute in the svc file like below (right click on svc file, then "View Markup"):
<%@ ServiceHost Language="C#" Debug="true" Service="Service.DummyService" Factory="Service.NInjectServiceHostFactory" %>
Hope this helps. Also, I think NInject offers some implementations for this out of the box in NInject.Extensions.Wcf.dll.