La forma en que estoy actualmente usando Ninject (v3) con mi WCF se basa en la extensión Ninject WCF y Pieter De Rycke's great blog post.
En pocas palabras, esto es lo que estoy haciendo:
1) A través de NuGet, he añadido una referencia a Ninject.Extensions.Wcf en mi proyecto WCF. Esto crea la carpeta App_Start con NinjectWebCommon.cs, que se encarga de inicializar Ninject.
2) Normalmente, configuraría sus asignaciones de Ninject en el método CreateKernel en NinjectWebCommon.cs. Sin embargo, ya que tengo un sitio MVC3 en la misma solución y quiero las mismas asignaciones ninject para ese sitio, mi CreateKernel se parece a esto:
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx =>() => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
InfrastructureSetup.RegisterServices(kernel);
return kernel;
}
3) En InfrastructureSetup.RegisterServices, tengo mis asignaciones ninject:
public static class InfrastructureSetup
{
public static void RegisterServices(IKernel kernel)
{
kernel.Bind<IRepositoryContext>().To<MyEntityFrameworkContext>().InRequestScope();
kernel.Bind<IFooRepository>().To<FooRepository>().InRequestScope();
kernel.Bind<IBarRepository>().To<BarRepository>().InRequestScope();
// ... and so on. I want InRequestScope() for the EF context, since
// otherwise my repositories (which take IRepositoryContext in their
// constructors) end up getting different EF contexts, messing things up
}
}
4) Quiero inyectar también cosas (IFooService etc.) a mis constructores WCF, por lo que he editado el Web.config para el proyecto WCF con el asesoramiento de Pieter de Rycke:
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
<!-- Add the Ninject behavior to the WCF service. This is needed to support dependency injection to the WCF constructors -->
<ninject />
</behavior>
</serviceBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<!-- Add the Ninject behavior extension -->
<add name="ninject"
type="MyWCFProject.Infrastructure.NinjectBehaviorExtensionElement, MyWCFProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</behaviorExtensions>
</extensions>
5) En el espacio de nombres MyWCFProject.Infrastructure, tengo tres archivos que son básicamente copiar y pegar de Pieter:
NinjectBehaviorAttribute.cs:
using System;
using System.Collections.ObjectModel;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using Ninject.Web.Common;
namespace MyWCFProject.Infrastructure
{
public class NinjectBehaviorAttribute : Attribute, IServiceBehavior
{
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase,
Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
Type serviceType = serviceDescription.ServiceType;
// Set up Ninject to support injecting to WCF constructors
var kernel = new Bootstrapper().Kernel;
IInstanceProvider instanceProvider = new NinjectInstanceProvider(kernel, serviceType);
foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher endpointDispatcher in dispatcher.Endpoints)
{
DispatchRuntime dispatchRuntime = endpointDispatcher.DispatchRuntime;
dispatchRuntime.InstanceProvider = instanceProvider;
}
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
}
}
NinjectBehaviorExtensionElement.cs:
using System;
using System.ServiceModel.Configuration;
namespace MyWCFProject.Infrastructure
{
public class NinjectBehaviorExtensionElement : BehaviorExtensionElement
{
public override Type BehaviorType
{
get { return typeof(NinjectBehaviorAttribute); }
}
protected override object CreateBehavior()
{
return new NinjectBehaviorAttribute();
}
}
}
NinjectInstanceProvider .cs:
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using Ninject;
namespace MyWCFProject.Infrastructure
{
public class NinjectInstanceProvider : IInstanceProvider
{
private Type serviceType;
private IKernel kernel;
public NinjectInstanceProvider(IKernel kernel, Type serviceType)
{
this.kernel = kernel;
this.serviceType = serviceType;
}
public object GetInstance(InstanceContext instanceContext)
{
return this.GetInstance(instanceContext, null);
}
public object GetInstance(InstanceContext instanceContext, Message message)
{
return kernel.Get(this.serviceType);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
}
}
}
En el mes Por lo tanto, esta solución parece estar funcionando bien; la inyección de dependencia funciona tanto para el sitio WCF como para el MVC3, puedo solicitar dependencias para ser inyectadas a los constructores de WCF y el contexto de EF permanece durante la duración de la solicitud.