Utilizzo di contenitori IoC; in particolare Windsor

Penso che la risposta a questa domanda sia così ovvia che nessuno si è preoccupato di scrivere su questo, ma è tardi e non riesco davvero a capirlo.

Ho letto i contenitori IoC (Windsor in questo caso) e mi manca il modo in cui parli al contenitore dalle varie parti del tuo codice.

Ricevo la DI, ho fatto i poveri mans di DI (costruttori vuoti che chiamano i costruttori di overload sovraccaricati con implementazioni di parametri predefinite) per un po ‘di tempo e posso vedere completamente il vantaggio del container. Tuttavia, mi manca un pezzo fondamentale di informazioni; come dovresti fare riferimento al contenitore ogni volta che ti serve un servizio?

Creo una singola insistenza globale che trasmetto? Sicuramente no!

So che dovrei chiamare questo:

WindsorContainer container = new WindsorContainer(new XmlInterpreter()); 

(per esempio) quando voglio caricare la mia configurazione XML, ma cosa devo fare con il contenitore? La creazione di un nuovo contenitore ogni volta dopo persiste la configurazione caricata attraverso alcune majick statiche interne o in altro modo, o devo ricaricare la configurazione ogni volta (non credo, o il ciclo di vita non potrebbe funzionare).

Non riuscire a capire questo mi impedisce di capire come funzionano i cicli di vita, e di andare avanti con l’utilizzo di alcuni problemi di IoC

Grazie,

Andrea

Il 99% dei casi è un’istanza contenitore per app. Normalmente lo si inizializza in Application_Start (per un’app Web), come questo .

Dopodiché, è davvero all’altezza del consumatore del contenitore. Ad esempio, alcuni framework, come Monorail e ASP.NET MVC consentono di intercettare la creazione delle istanze (i controller in questo caso), quindi basta registrare i controller e le loro dipendenze nel contenitore e il gioco è fatto, ogni volta che si ottiene un richiedere al contenitore di iniettare ogni controller con le sue dipendenze. Vedi ad esempio questo controller ASP.NET MVC . In questi framework, non è quasi mai necessario chiamare o persino fare riferimento al contenitore nelle classi, che è l’utilizzo consigliato.

Altri framework non ti permettono di entrare facilmente nel processo di creazione (come Webforms), quindi devi ricorrere a hack come questo , o tirare le dipendenze richieste (cioè chiamando esplicitamente il contenitore). Per tirare le dipendenze, usa un gateway statico per il contenitore come questo o quello descritto da maxnk . Nota che, facendo ciò, stai effettivamente utilizzando il contenitore come Localizzatore di servizio, che non disaccoppia le cose e inversione di controllo. (vedi la differenza qui e qui )

Spero che questo chiarisca i tuoi dubbi.

In genere si desidera mantenere solo un’istanza per la durata dell’intera applicazione. Ciò che faccio la maggior parte del tempo è che inizializzo il contenitore all’avvio dell’app, quindi utilizzo le fabbriche digitate per estrarre oggetti in modo inconsapevole dal contenitore.

Un altro approccio popolare è quello di avvolgere l’istanza del contenitore con una class statica e utilizzare quella class statica per accedere al contenitore (singleton). Puoi trovare un esempio di ciò nella libreria Rhino.Commons di Ayende qui . Questo approccio presenta tuttavia gravi inconvenienti e dovrebbe essere evitato.

Uso questo esempio del blog di Michael Puleio sull’uso di un HttpModule per gestire l’accumulo delle mie dipendenze usando Unity. http://blogs.msdn.com/mpuleio/archive/2008/07/17/proof-of-concept-a-simple-di-solution-for-asp-net-webforms.aspx

Come le altre risposte qui affermano ci sono molte scelte, e ancora una volta siamo lasciati a noi stessi per capire cosa è meglio nel nostro caso.

Detto questo, l’IMO con un contenitore globale a cui si accede nell’intera applicazione alquanto rompe l’isolamento in quanto un sacco di codice ora dipende dall’unica class globale. Inoltre, per le applicazioni suddivise in più assiemi, il contenitore globale deve essere reso accessibile a tutti questi assembly.

Con Unity puoi effettivamente avere un parametro IUnityContainer nel tuo costruttore e il contenitore si inietterà automaticamente nell’istanza quando risolvi la class. In questo modo, per i servizi che devono risolvere altri servizi che si passano nel contenitore anziché forzare la class a fare riferimento alla class esterna.

Non sono sicuro di come altri framework supportino questo scenario (Windsor inietterà IKernel ).

Sto usando un’implementazione di questa interfaccia:

 public interface IResolver { object Resolve(Type type); object Resolve(string name); T Resolve() where T : class; T Resolve(string name) where T : class; } 

Che in realtà è racchiuso nella class statica globale, ad esempio:

 public static class Resolver // : IResolver { private static IResolver _current; public static object Resolve(Type type) { return Current.Resolve(type); } public static object Resolve(string name) { return Current.Resolve(name); } public static T Resolve() where T : class { return Current.Resolve(); } public static T Resolve(string name) where T : class { return Current.Resolve(name); } private static IResolver Current { get { if (_current == null) { _current = new SpringResolver(); } return _current; } } } 

Sto anche cercando di seguire la semplice regola: utilizzare la class Resolver il meno ansible, invece di iniettare servizi in oggetti che richiedono tali servizi.