2012-10-08 14 views
9

Estoy usando el complemento ninject mvc3 con mi aplicación web api. Me tendrá un borde que se parece a:El enlace de Singleton Scope no funciona según lo previsto

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

Es mi interpretación de que el meollo creará exactamente una instancia de Foo y volver a utilizarlo adecuadamente. Al poner un punto de interrupción en el constructor Foo, puedo ver claramente que se llama una vez por solicitud, y no puedo explicar por qué.

Mi única suposición es que de alguna manera se está creando un kernel nuevo por solicitud, pero ese no parece ser el caso, ya que el método CreateKernel que establece el resolvedor de dependencias global solo se ejecuta una vez en la vida de la aplicación.

estoy usando un código tomado de this post hacer ninject jugar bonito con MVC 4. Debido a los cambios estructurales, que tenía que hacer una envoltura adicional que le asigno a GlobalConfiguration.Configuration.DependencyResolver:

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()); 
    } 
} 

¿Qué estoy haciendo ¿incorrecto?

+2

Tal vez no relacionado con tema de captncraig, pero relevante para el título. Tuve el mismo problema y resultó que accidentalmente estaba inyectando la implementación en uno de mis objetos en lugar de la interfaz. Entonces, en el constructor, accidentalmente puse Foo en lugar de IFoo. Espero que esto ayude a alguien por ahí ... –

Respuesta

5

que nunca podría conseguir para que funcione correctamente, y no estoy seguro de por qué. Supongo que tiene algo que ver con la integración de MVC4 siendo un poco inmaduro en este momento.

Como alternativa estoy usando:

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

Esto parece funcionar, pero no estoy muy contento con él.

+1

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

1

Nota: utilicé nuget para instalar ninject & ninject.web.mvc (que estoy seguro que hiciste también).

No puedo ver el resto de tu código, pero esto es lo que tenía en mi clase "NinjectDependencyScope". (Creo que la suya simplemente se llama NinjectScope, podría haber algunas otras inconsistencias de nombres con su código)

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 
} 

Y aquí está mi clase NinjectWebCommon (que se encuentra en la carpeta App_Start):

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

Mi controlador requiere un 'IBar' que toma un' IFoo' en el constructor. – captncraig

+0

Tenga paciencia conmigo mientras me pongo al día con mi antigua aplicación de API web MVC 4 que usó ninject ... la muestra de su código parece algo familiar para lo que había hecho ... – BlakeH

+0

Creo que tal vez esté sucediendo algo extraño. Tu código es muy similar al mío, excepto que estás usando '_resolver.TryGet' y he estado usando' _resolver.Resolve'. Los métodos 'TryGet' no existen en mi versión de' IResolutionRoot'. ¿Estás usando el plugin mvc3? – captncraig

3

Como se mencionó anteriormente, parece un error.
Una opción es simplemente poner en práctica un método de extensión Singleton mismo:

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; 
    } 
} 

Y a continuación, sólo tiene que utilizar:

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

En lugar de

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


3

llegar Ciertamente finales a este hilo pero sólo pasó a mí con un servicio de alojamiento Windows OWIN para los controladores de la API Web y resolver las dependencias con Ninject, InSingletonScope() no estaba funcionando hasta que hice lo siguiente:

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; 
    } 
... 

Esperanza esto ayuda

+0

Gracias, resuelve mi problema, También con los controladores WebAPI, Si alguien tiene una explicación clara por qué .. Estoy interesado ! – bAN

Cuestiones relacionadas