2013-03-11 14 views
11

Questa domanda non è specificamente correlata a Ninject. È più una questione di codice generale, ma la sto postando nel caso in cui ci fosse un modo migliore di gestire il problema in Ninject, rispetto a quello che sto cercando di fare.Accesso globale al kernel di Ninject

Vorrei sapere se è possibile accedere al kernel standard di Ninject globalmente, dalla sua istanza in Global.asax.

Ecco il codice:

public class MvcApplication : NinjectHttpApplication 
{ 
    protected override void OnApplicationStarted() 
    { 
     base.OnApplicationStarted(); 

     // MVC global registration, routing and filtering code goes here... 
    } 

    protected override IKernel CreateKernel() 
    { 
     return Container; 
    } 

    private static IKernel Container 
    { 
     get 
     { 
      IKernel kernel = new StandardKernel(); 
      kernel.Load(new ServiceModule(), new RepositoryModule()); 
      return kernel; 
     } 
    } 
} 

Se ho alcune classi, per esempio, le classi di facciata che non si interfacciano con il controller, in cui vorrei iniziare una catena di dipendenza, la mia comprensione è che dovrebbero uso:

_className = kernel.Get<IClassName>(); 

Tuttavia, l'unico modo che conosco per farlo è quello di creare una nuova istanza del Ninject kernel standard, ma se ho capito bene, è non è una buona idea per creare una nuova istanza di il kernel di Ninject, perché fondamentalmente sta creando una seconda ke RNEL.

Quindi, è possibile accedere al kernel esistente che è stato istanziato in Global.asax all'avvio dell'applicazione, da qualsiasi punto della mia applicazione, oppure esiste un modo migliore per farlo?

saluti,

Fred Chateau

risposta

0

Sembra che tu stia bisogno di più di un'implementazione pattern Factory di Ninject. È possibile migrare il kernel da Global.asax a una classe Factory che potrebbe essere interagita con il resto dell'applicazione.

In alternativa, se si dispone di una situazione in cui un parametro specificato in fase di esecuzione determina i collegamenti dell'interfaccia, è possibile eseguire il wrap del servizio. Questa è una configurazione ibrida di DI e ServiceLocater, ma ServiceLocater si verifica solo all'istanziazione a livello di servizio, tutti gli altri livelli sono codificati normalmente in un modello DI/IOC.

MyService : IService1 
{ 
    public void DoSomething(MyCustomParameter parameter) 
    { 
     //Builds the Kernel using the supplied parameter 
     //We've in our resolver bound IService1 To MyActualService 
     var trueService = kernel.Get<IService1>(); 
     return trueService.DoSomething(parameter); 
    } 
} 

MyActualService : IService1 
{ 
    public void DoSomething() 
    { 
     //Do the Actual work 
    } 
} 
+1

Ti capita di sapere come la creazione di una fabbrica di interesserebbe l'attuazione MVC estensioni? –

+0

Purtroppo quella parte non lo saprei senza tentare. Ho usato il metodo di avvolgimento sopra elencato per l'applicazione su cui sto lavorando a causa di preoccupazioni e scelte di architettura uniche. – Kaiser12

1

Sono riuscito a far funzionare il localizzatore di servizio, e sembra funzionare abbastanza bene. Quando una richiesta entra nell'applicazione tramite un metodo di azione del controller MVC, le funzioni di Ninject vengono normalmente fornite da Ninject.Mvc.Extensions. Inietta le classi di istanza tramite il costruttore del controllore. Quando una richiesta inoltra l'applicazione in un altro modo, chiamo il localizzatore del servizio per fornire le classi di istanza nel costruttore di tali classi.

Ecco il codice:

In primo luogo, un riferimento alla Microsoft.Practices.ServiceLocation

E la seguente classe di adattatori Ninject.

public class NinjectServiceLocator : ServiceLocatorImplBase 
{ 
    public IKernel Kernel { get; private set; } 

    public NinjectServiceLocator(IKernel kernel) 
    { 
     Kernel = kernel; 
    } 

    protected override object DoGetInstance(Type serviceType, string key) 
    { 
     return Kernel.Get(serviceType, key); 
    } 

    protected override IEnumerable<object> DoGetAllInstances(Type serviceType) 
    { 
     return Kernel.GetAll(serviceType); 
    } 
} 

E in Global.asax

public class MvcApplication : NinjectHttpApplication 
{ 
    private static IKernel _kernel; 


    protected override IKernel CreateKernel() 
    { 
     return Container; 
    } 

    private static IKernel Container 
    { 
     get 
     { 
      if (_kernel == null) 
      { 
       _kernel = new StandardKernel(); 
       _kernel.Load(new ServiceModule(), new RepositoryModule()); 

       ServiceLocator.SetLocatorProvider(() => new NinjectServiceLocator(_kernel)); 
      } 

      return _kernel; 
     } 
    } 
} 

Nota questo codice richiede l'utilizzo di Ninject.Mvc.Extensions, che fornisce la dipendenza risolutore fallback al controller di default. In caso contrario, potrebbe essere richiesto un resolver di dipendenze personalizzato.

Questo sembra risolvere tutte le mie preoccupazioni.Crea le classi di istanze, risolve l'intero grafo degli oggetti e funziona da qualsiasi posto che mi serve per funzionare. E, per quanto posso dire, c'è solo un kernel standard di Ninject per applicazione.

So che l'uso del modello di localizzazione del servizio è disapprovato, ma immagino che l'utilizzo di più di un kernel Ninject possa essere considerato ancora peggiore.

Fred Chateau

20

Il modo più semplice (IMO):

_className = (IClassName)System.Web.Mvc.DependencyResolver.Current.GetService(typeof(IClassName)); 
2

più recente versione di Ninject ha questo metodo se utilizzato con System.Web.Mvc:

var obj = DependencyResolver.Current.GetService<IClassName>();

A meno che non sia necessario manipolare i binding DI al volo, ma l'istanziazione di uno StandardKernel è un po 'pesante.

IKernel kernel = new StandardKernel(); var obj = DependencyResolver.Current.GetService<IClassName>();