2010-08-12 15 views
11

Tengo un servicio web WCF en el que quiero usar mis Repositorios y Servicios que deseo incorporar en mi servicio web de WCF, sin embargo, el ejemplo de Ninzzle WCF Extension tiene bastante que es instanciar una instancia de cada dependencia, que no quiero, quería una inyección de dependencia más pura.Uso de Ninject WCF Extension con WCF Web Service

Alguien ha tenido éxito con el uso de Ninject con WCF, Google parece devolver resultados poco relevantes para los temas que estoy buscando.

Respuesta

8

El código detrás de TimeService tiene:

<%@ ServiceHost Language="C#" Debug="true" Service="WcfTimeService.TimeService" CodeBehind="TimeService.svc.cs" **Factory="Ninject.Extensions.Wcf.NinjectServiceHostFactory"** %> 

Los bastard injection ctors confunden el asunto - Ninject elegirá el constructor más específica. El problema general con la muestra es que está cubriendo todas las bases (alojado en IIS, alojado en EXE, servicio hospedado), y WCF no hace exactamente que todo esto sea fácil de administrar (@Ian Davis: podría equivocarme fácilmente, puede proporcionar algunos detalles más por favor, quizás en la forma de un resumen de lo que las muestras ilustran en el archivo README, y quizás más detalles en el porqué de los varios casos donde ha usado BI?)

2

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.