2010-08-12 13 views
11

Ho un servizio WCF web in cui voglio usare il mio repository e servizi che desidero alla dipendenza iniettare al mio servizio WCF web, tuttavia l'esempio Ninject WCF estensione è praticamente un ctor che sta istanziando un'istanza di ogni dipendenza, che non voglio, volevo un'iniezione di dipendenza più pura.Utilizzando Ninject WCF estensione con WCF Web Service

Qualcuno ha avuto successo con l'utilizzo di Ninject con WCF, Google sembra tornare risultati poco rilevanti per gli argomenti che sto cercando.

risposta

8

Il codice dietro per TimeService ha:

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

I bastard injection ctors confondere la questione - Ninject sceglierà il costruttore più specifica. Il problema generale con l'esempio è che copre tutte le basi (IIS Hosted, EXE ospitato, Service Hosted), e WCF non rende esattamente tutte queste cose facili da gestire (@Ian Davis: potrei facilmente sbagliarmi, puoi fornire qualche altro dettaglio per favore, forse sotto forma di un riassunto di ciò che gli esempi illustrano nel README e forse più dettagli nel perché dei vari casi in cui hai usato BI?)

2

Il modo in cui sto attualmente usando Ninject (v3) con il mio WCF è basato sull'estensione per WCF Ninject e Pieter De Rycke's great blog post.

In poche parole, ecco quello che sto facendo:

1) Via NuGet, ho aggiunto un riferimento alla Ninject.Extensions.Wcf nel mio progetto WCF. Questo crea la cartella App_Start con NinjectWebCommon.cs, che si occupa dell'inizializzazione di Ninject.

2) In genere, devi impostare le mappature Ninject nel metodo CreateKernel in NinjectWebCommon.cs. Tuttavia, dal momento che ho un sito MVC3 nella stessa soluzione e vogliono la stessa mappature Ninject per quel sito, il mio CreateKernel assomiglia a questo:

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) In InfrastructureSetup.RegisterServices, ho il mio mappature 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) voglio iniettare anche roba (IFooService etc.) ai miei costruttori WCF, quindi ho modificato il web.config per il progetto WCF con la consulenza da 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) lo spazio dei nomi MyWCFProject.Infrastructure, ho tre file che sono fondamentalmente copia-incolla da 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) 
     { 
     } 
    } 
} 

Al mo questa soluzione sembra funzionare bene; l'iniezione delle dipendenze funziona sia per il WCF che per il sito MVC3, posso richiedere che le dipendenze vengano iniettate ai costruttori WCF e il contesto EF rimane in sospeso per la durata della richiesta.