2012-10-08 4 views
9

Ich verwende das ninject mvc3-Plugin mit meiner Web-API-Anwendung. Ich habe eine Bindung, die wie folgt aussieht:Singleton Scope-Bindung funktioniert nicht wie vorgesehen

kernel.Bind<IFoo>().To<Foo>().InSingletonScope();

Es ist meine Interpretation ist, dass die kernal genau eine Instanz von Foo schaffen und sie in geeigneter Weise wiederverwenden. Indem ich einen Breakpoint in Foo 's Konstruktor einfüge, kann ich klar sehen, dass es einmal pro Anfrage aufgerufen wird, und ich kann nicht erklären, warum.

Meine einzige Vermutung ist, dass irgendwie ein neuer Kernel pro Anfrage erstellt wird, aber das scheint nicht der Fall zu sein, da die CreateKernel Methode, die den globalen Abhängigkeitsresolver setzt, nur einmal in der Anwendungslebensdauer ausgeführt wird.

ich einige Code aus this post genommen bin mit machen schön ninject zu spielen mit mvc 4. Wegen der Rahmen ändert, hatte ich eine zusätzliche Hülle zu machen, die ich GlobalConfiguration.Configuration.DependencyResolver zuweisen:

public class NinjectResolver : NinjectScope, IDependencyResolver 
{ 
    private readonly IKernel _kernel; 
    public NinjectResolver(IKernel kernel) 
     : base(kernel) 
    { 
     _kernel = kernel; 
    } 
    public IDependencyScope BeginScope() 
    { 
     return new NinjectScope(_kernel.BeginBlock()); 
    } 
} 

Was mache ich falsch?

+2

Vielleicht nicht im Zusammenhang mit captncraigs Problem, aber relevant für den Titel. Ich hatte das gleiche Problem und es stellte sich heraus, dass ich versehentlich die Implementierung in eines meiner Objekte und nicht in das Interface injizierte. Also hatte ich im Konstruktor versehentlich Foo anstelle von IFoo gesetzt. Hoffe, das hilft jemandem da draußen ... –

Antwort

5

Ich konnte nie bekommen es funktioniert richtig, und ich bin mir nicht sicher warum. Meine Vermutung ist, dass es etwas damit zu tun hat, dass die MVC4-Integration im Moment ein wenig unreif ist.

Als Alternative ich verwende:

kernel.Bind<IFoo>().ToConstant(new Foo());

Dies scheint zu funktionieren, aber ich bin nicht sehr glücklich mit ihm.

+1

http://stackoverflow.com/questions/11356864/ninject-insingletonscope-with-web-api-rc – BlakeH

1

Hinweis: Ich habe nugget verwendet, um ninject & ninject.web.mvc zu installieren (was ich sicher auch getan habe).

Ich bin nicht in der Lage, den Rest Ihres Codes zu sehen, aber hier ist, was ich in meiner "NinjectDependencyScope" -Klasse hatte. (Ich denke, Ihnen ist nur NinjectScope genannt, könnten einige andere Namensgebung Unstimmigkeiten mit Ihrem Code sein)

public class NinjectDependencyScope : IDependencyScope 
{ 
    private IResolutionRoot _resolver; 

    internal NinjectDependencyScope(IResolutionRoot resolver) 
    { 
     Contract.Assert(resolver != null); 

     _resolver = resolver; 
    } 

    #region IDependencyScope Members 

    public void Dispose() 
    { 
     var disposable = _resolver as IDisposable; 
     if (disposable != null) 
      disposable.Dispose(); 

     _resolver = null; 
    } 

    public object GetService(Type serviceType) 
    { 
     if (_resolver == null) 
      throw new ObjectDisposedException("this", "This scope has already been disposed"); 
     return _resolver.TryGet(serviceType); 
    } 

    public IEnumerable<object> GetServices(Type serviceType) 
    { 
     if (_resolver == null) 
      throw new ObjectDisposedException("this", "This scope has already been disposed"); 

     return _resolver.GetAll(serviceType); 
    } 

    #endregion 
} 

Und hier ist meine NinjectWebCommon Klasse (befindet sich in App_Start Ordner):

using System; 
using System.Web; 
using System.Web.Http; 
using Microsoft.Web.Infrastructure.DynamicModuleHelper; 
using Ninject; 
using Ninject.Modules; 
using Ninject.Web.Common; 

[assembly: WebActivator.PreApplicationStartMethod(typeof(ABCD.Project.Web.App_Start.NinjectWebCommon), "Start")] 
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(ABCD.Project.Web.App_Start.NinjectWebCommon), "Stop")] 

namespace ABCD.Project.Web.App_Start 
{ 
public static class NinjectWebCommon 
{ 
    private static readonly Bootstrapper Bootstrap = new Bootstrapper(); 

    /// <summary> 
    /// Starts the application 
    /// </summary> 
    public static void Start() 
    { 
     DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule)); 
     DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule)); 
     Bootstrap.Initialize(CreateKernel); 
    } 

    /// <summary> 
    /// Stops the application. 
    /// </summary> 
    public static void Stop() 
    { 
     Bootstrap.ShutDown(); 
    } 

    /// <summary> 
    /// Creates the kernel that will manage your application. 
    /// </summary> 
    /// <returns>The created kernel.</returns> 
    private static IKernel CreateKernel() 
    { 
     var kernel = new StandardKernel(); 
     kernel.Bind<Func<IKernel>>().ToMethod(ctx =>() => new Bootstrapper().Kernel); 
     kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>(); 

     RegisterServices(kernel); 

     // Set Web API Resolver 
     GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel); 
     return kernel; 
    } 

    /// <summary> 
    /// Load your modules or register your services here! 
    /// </summary> 
    /// <param name="kernel">The kernel.</param> 
    private static void RegisterServices(IKernel kernel) 
    { 
     //var modules = new INinjectModule[] { new NinjectBindingModule(), }; 
     //kernel.Load(modules); 
     Here's where you would load your modules or define your bindings manually... 
    }   
} 
} 
+0

Mein Controller benötigt einen 'IBar', der im Konstruktor ein' IFoo' akzeptiert. – captncraig

+0

Erinnere dich an mich, während ich auf meiner alten MVC 4 Web-API-App, die Ninject verwendet, wieder Geschwindigkeit erlange ... dein Code-Beispiel sieht irgendwie vertraut aus, was ich getan habe ... – BlakeH

+0

Ich denke, vielleicht passiert etwas Seltsames. Ihr Code sieht mir sehr ähnlich, außer dass Sie '_resolver.TryGet' verwenden und ich' _resolver.Resolve' verwendet habe. Die 'TryGet' Methoden existieren nicht in meiner Version von' IResolutionRoot'. Verwenden Sie das mvc3-Plugin? – captncraig

3

Wie bereits erwähnt, sieht es wie ein Fehler aus.
Eine Möglichkeit ist, einfach eine Singleton-Extension-Methode selbst zu implementieren:

public static class NinjectSingletonExtension 
{ 
    public static CustomSingletonKernelModel<T> SingletonBind<T>(this IKernel i_KernelInstance) 
    { 
     return new CustomSingletonKernelModel<T>(i_KernelInstance); 
    } 
} 

public class CustomSingletonKernelModel<T> 
{ 
    private const string k_ConstantInjectionName = "Implementation"; 
    private readonly IKernel _kernel; 
private static object padlock = new Object(); 

    private T _concreteInstance; 


    public CustomSingletonKernelModel(IKernel i_KernelInstance) 
    { 
     this._kernel = i_KernelInstance; 
    } 

    public IBindingInNamedWithOrOnSyntax<T> To<TImplement>(TImplement i_Constant = null) where TImplement : class, T 
    { 
     _kernel.Bind<T>().To<TImplement>().Named(k_ConstantInjectionName); 
     var toReturn = 
      _kernel.Bind<T>().ToMethod(x => 
             { 
              if (i_Constant != null) 
              { 
               return i_Constant; 
              } 

              if (_concreteInstance == null) 
         { 
         lock (padlock) 
         { 
         if (_concreteInstance == null) 
         { 
          _concreteInstance = _kernel.Get<T>(k_ConstantInjectionName); 
         } 
          } 
         } 


              return _concreteInstance; 
             }).When(x => true); 

     return toReturn; 
    } 
} 

Und dann verwenden Sie einfach:

i_Kernel.SingletonBind<T>().To<TImplement>(); 

Eher dann

i_Kernel.Bind<T>().To<TImplement>().InSingletonScope(); 


3

Sicher spät ankommen zu diesem Thread aber es gerade passiert mir mit einem Windows-Dienst OWIN für Web-API-Controller-Hosting und Lösung von Abhängigkeiten mit Ninject, InSingletonScope() nicht funktioniert, bis ich habe folgendes:

var kernel = new StandardKernel(); 
... 
kernel.Bind<Foo>().ToSelf().InSingletonScope(); 
kernel.Bind<IFoo>().ToMethod(context => context.Kernel.Get<Foo>()); 
... 

// Controllers ask for the dependency as usual... 
public class SomeController : ApiController 
{ 
    readonly IFoo _foo; 

    public SomeController(IFoo foo) 
    { 
     _foo = foo; 
    } 
... 

hoffe, das hilft

+0

danke es mein Problem zu lösen, auch mit WebAPI-Controllern, wenn jemand eine klare Erklärung warum .. Ich bin interessiert ! – bAN