2010-08-12 8 views
11

Ich habe einen WCF-Webdienst, in dem ich meine Repositorys und Dienste verwenden möchte, die ich in meinen WCF-Webdienst einspeisen möchte, jedoch hat das Ninject WCF Extension-Beispiel ziemlich viel Bedeutung welches eine Instanz jeder Abhängigkeit instanziiert, die ich nicht will, wollte ich eine reinere Abhängigkeitsinjektion.Verwenden von Ninject WCF-Erweiterung mit WCF-Webdienst

Hat jemand Erfolg mit Ninject mit WCF gehabt, scheint Google wenig relevante Ergebnisse für die gesuchten Themen zurückzugeben.

Antwort

8

Der Code hinter für TimeService hat:

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

Die bastard injection ctors verwirren die Angelegenheit - Ninject wird die spezifischste Konstruktor wählen. Das allgemeine Problem mit dem Beispiel ist, dass es alle Grundlagen abdeckt (gehostete IIS, gehostete EXE-Dienste, gehostete Dienste), und WCF macht auch nicht all diese Dinge einfach zu verwalten (@Ian Davis: Ich könnte leicht falsch liegen, können Sie liefern etwas mehr Details bitte, vielleicht in Form einer Zusammenfassung dessen, was die Proben in der README illustrieren, und vielleicht mehr Details im Warum der verschiedenen Fälle, in denen Sie BI verwendet haben?)

2

Die Art, wie ich gerade benutze Ninject (v3) mit meiner WCF basiert auf der Ninject WCF-Erweiterung und Pieter De Rycke's great blog post.

Auf den Punkt gebracht, ist hier, was ich tue:

1) Via NuGet, ich habe einen Verweis auf Ninject.Extensions.Wcf in meine WCF-Projekt hinzugefügt. Dadurch wird der Ordner App_Start mit NinjectWebCommon.cs erstellt, der für die Initialisierung von Ninject zuständig ist.

2) Normalerweise würden Sie Ihre Ninject-Zuordnungen in der CreateKernel-Methode in NinjectWebCommon.cs einrichten. Da ich aber eine MVC3 Standort in der gleichen Lösung und wollen die gleichen Ninject Zuordnungen für diese Website, sieht mein CreateKernel wie folgt aus:

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, ich habe meine Ninject Mappings:

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) ich möchte auch Sachen (IFooService etc.) auf meine WCF Konstrukteuren injizieren, also habe ich die Web.config für die WCF-Projekt mit den Ratschlägen von Pieter De Rycke bearbeitet:

<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) Im MyWCFProject.Infrastructure Namespace, ich habe drei Dateien, die sind im Grunde copy-paste von 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) 
     { 
     } 
    } 
} 

Am mo Diese Lösung scheint gut zu funktionieren. Die Abhängigkeitsinjektion funktioniert sowohl für die WCF- als auch für die MVC3-Site. Ich kann verlangen, dass Abhängigkeiten in die WCF-Konstruktoren eingefügt werden, und der EF-Kontext bleibt für die Dauer der Anforderung erhalten.

Verwandte Themen