2010-11-10 22 views
32

Poiché l'implementazione IoC/DI in MVC 3 è molto probabilmente nella sua forma finale nell'RC, sto cercando un'implementazione aggiornata di DependencyResolver, IControllerActivator e IViewPageActivator utilizzando Caste Windsor. Ci sono degli esempi là fuori che sono stati aggiornati per MVC 3 RC?Castle Windsor Dependency Resolver per MVC 3

EDIT # 1 implementazione di una dipendenza risolutore Windsor è davvero banale, ma c'è ancora qualcosa che manca. Contrariamente all'esempio Ninject di Jeff Putz (sotto), sembra che non sia così semplice con Windsor. Dopo aver impostato il resolver di dipendenza in questo modo,

DependencyResolver.SetResolver(new WindsorDependencyResolver(container)); 

Windsor genera ComponentNotFoundException. Devo fornire implementazioni per IControllerFactory e IControllerActivator. Poiché la DefaultControllerFactory è DependencyResolver consapevole, questo può essere risolto come segue:

Component.For<IControllerFactory >().ImplementedBy<DefaultControllerFactory>() 
Component.For<IControllerActivator >().ImplementedBy<WindsorControllerActivator>(), 

WindsorControllerActivator è banale pure. Tuttavia, questo porta a un'altra ComponentNotFoundException per IViewPageActivator.

Questo mi porta a credere che mi manchi qualcosa. Non c'è modo che questo dovrebbe essere più complicato di un'implementazione di un controller factory e chiamare ControllerBuilder.Current.SetControllerFactory MVC 2.0-style.

EDIT # 2 ho perso dettaglio sottile ma importante che il risolutore di dipendenza deve restituire null quando un servizio non può essere trovato. L'implementazione è la seguente:

public class WindsorDependencyResolver : IDependencyResolver 
{ 
    private readonly IWindsorContainer container; 

    public WindsorDependencyResolver(IWindsorContainer container) 
    { 
     this.container = container; 
    } 

    public object GetService(Type serviceType) 
    { 
     return container.Kernel.HasComponent(serviceType) ? container.Resolve(serviceType) : null; 
    } 

    public IEnumerable<object> GetServices(Type serviceType) 
    { 
     return container.Kernel.HasComponent(serviceType) ? container.ResolveAll(serviceType).Cast<object>() : new object[]{}; 
    } 
} 

EDIT # 3

Rispondendo a una domanda nei commenti. Se non trovate che è necessario il proprio IControllerActivator, ecco una semplice implementazione per Windsor:

public class WindsorControllerActivator : IControllerActivator 
{ 
    private readonly IWindsorContainer container; 

    public WindsorControllerActivator(IWindsorContainer container) 
    { 
     this.container = container; 
    } 

    public IController Create(RequestContext requestContext, Type controllerType) 
    { 
     return (IController)container.GetService(controllerType); 
    } 
} 

}

Ancora una volta, questo è NON necessario per ottenere base DI lavorando con Windsor e il resolver MVC3 dipendenze .

EDIT # 4 Sulla base di alcuni ulteriori ricerche e valutazioni, sembra che un'implementazione del controller fabbrica tradizionale è l'approccio migliore per Windsor e MVC3. La preoccupazione è che l'interfaccia IDependencyResolver manchi di un metodo di rilascio, che potrebbe causare perdite di memoria con Windsor che non dispone dei suoi componenti. Probabilmente questo non sarà un problema se tutte le tue dipendenze verranno risolte con il ciclo di vita di PerWebRequest, ma è comunque meglio non rischiare. Ecco una implementazione di base di una fabbrica di controller Windsor per MVC3.

public class WindsorControllerFactory : DefaultControllerFactory 
{ 
    private readonly IWindsorContainer container; 

    public WindsorControllerFactory(IWindsorContainer container) 
    { 
     this.container = container; 
    } 

    public override void ReleaseController(IController controller) 
    { 
     container.Kernel.ReleaseComponent(controller); 
    } 

    public override IController CreateController(RequestContext requestContext, string controllerName) 
    { 
     var controllerComponentName = controllerName + "Controller"; 
     return container.Kernel.Resolve<IController>(controllerComponentName); 
    } 
} 

EDIT # 5 Se stai usando aree MVC, quanto sopra implementazione non funziona per voi.Sarà necessario registrare ogni controller in base al suo nome completo, e sovrascrivere GetControllerInstance invece di CreateController:

protected override IController GetControllerInstance(RequestContext context, Type controllerType) 
    { 
     if (controllerType != null) 
     { 
      return (IController)container.Kernel.Resolve(controllerType); 
     } 
     return null; 
    } 
+5

MVC 3 è di 15 ore di vita già, qualcuno scrivere questo codice stat! – jfar

+0

Sì ... la parte restituita null è la chiave, che non è così ovvia nel mio esempio se non si sa che Ninject ha quel metodo TryGet e restituisce null se non riesce a trovare una corrispondenza. Probabilmente avrei potuto essere più chiaro. :) –

+0

Ogni possibilità che possiamo vedere più di questo codice. WindsorControllerActivator? dov'è, google risultati zero. – MvcCmsJon

risposta

10

L'interfaccia non è cambiata dalla versione beta, quindi tutte le implementazioni per i vari framework dovrebbero ancora funzionare. E la verità è che non è così complicato da un'interfaccia ... dovresti essere in grado di farcela da sola senza troppi problemi. Per esempio, ho fatto questo per Ninject:

public class NinjectDependencyResolver : IDependencyResolver 
{ 
    public NinjectDependencyResolver(IKernel kernel) 
    { 
     _kernel = kernel; 
    } 

    private readonly IKernel _kernel; 

    public object GetService(Type serviceType) 
    { 
     return _kernel.TryGet(serviceType); 
    } 

    public IEnumerable<object> GetServices(Type serviceType) 
    { 
     return _kernel.GetAll(serviceType); 
    } 
} 

Poi legare in su in global.asax come questo:

private static IKernel _kernel; 
    public IKernel Kernel 
    { 
     get { return _kernel; } 
    } 

    public void Application_Start() 
    { 
     _kernel = new StandardKernel(new CoreInjectionModule()); 
     DependencyResolver.SetResolver(new NinjectDependencyResolver(Kernel)); 
     ... 
    } 

Ricordate, si ottengono tutti i tipi di contenuti gratis, a quel punto, tra cui DI per controllori, fabbriche di controllori, filtri di azione e classi di base di visualizzazione.

EDIT: Per essere chiari, non sono sicuro di quali siano i tuoi "attivatori", ma probabilmente non ne hai bisogno. L'interfaccia IDependencyResolver gestisce la nuova creazione di controllori e viste in modo automatico.

+0

Hiya, perché stai memorizzando il kernal in una proprietà statica pubblica della classe dell'applicazione? Sono nuovo di Ninject, ma non ho solo bisogno di questo: 'var resolver = new StandardKernel (new MyNinjectModule()); DependencyResolver.SetResolver (new NinjectDependencyResolver (resolver)); 'Grazie! –

2

MVCContrib è attualmente la fonte autorevole per l'integrazione IOC-MVC. Attualmente, il ramo MVC3 include solo implementazioni di controller factory e IDependencyResolver (e un paio di altre cose). Raccomando di forgiare il repository e implementare i punti di estensione mancanti (non dovrebbe essere troppo difficile), quindi inviare al team una richiesta di pull.

+1

Non più! Per chi lo legge ora: http://mvccontrib.codeplex.com/workitem/7122 –

Problemi correlati