2012-08-16 15 views
13

La mia applicazione include un numero di assembly back-end (incluso un layer di repository di dati Entity Framework) condivisi da un numero di assembly front-end (incluso un servizio Windows e un'applicazione web MVC3).Dove trovare i moduli Ninject in un'applicazione multilivello

La mia comprensione del processo di associazione di Ninject è che ogni assembly che contiene tipi iniettabili dovrebbe contenere anche un modulo Ninject che definisce i collegamenti predefiniti per questi tipi. Il set di moduli definiti verrebbe quindi caricato nel kernel Ninject degli assembly consumanti.

Tuttavia, si verificano problemi, poiché l'ambito di bind richiesto non è sempre coerente. Ad esempio, il mio progetto MVC deve collegarsi al contesto dati InRequestScope, mentre il servizio Windows si lega alla stessa classe InThreadScope.

Ovviamente posso risolvere questo problema riposizionando tutti i moduli nei progetti front-end e quindi mantenendo copie separate di ogni modulo per ogni scenario di utilizzo, ma questo sembra un hacker, poiché duplica gran parte del contenuto del modulo su più progetti .

Esiste una best practice su dove i moduli devono essere collocati in un'applicazione multilivello e come posso conciliare questo con il mio bisogno di legare le differenze tra i progetti?

Molte grazie per i vostri suggerimenti,

Tim

+0

vedere anche http://stackoverflow.com/questions/1699197/how-do-you-organise-your-ninject-modules (IIRC questo Q è un dup ma questo è il migliore che ho per ora) –

+0

Grazie Ruben. Hai ragione che c'è molto in comune tra queste due domande. Mi piace in particolare il tuo suggerimento di passare i parametri di runtime in moduli che risiedono negli assembly di supporto - molto flessibile. –

+0

Hmm; è passato un po 'di tempo (non cercava di pubblicizzare la mia risposta in alcun modo). Potrei aver letteralmente voluto dire * passare i parametri * nel corso della giornata - in generale avrei cercato di farlo attraverso le interfacce il più possibile. Inoltre, questo era prima di http://manning.com/seemann, che riduce drasticamente il numero di domande che trovi sconcertante nell'architettura di DI: def run compralo senza fare domande. –

risposta

12

Per una soluzione con una singola applicazione, il consiglio generale è di registrare il contenitore nel progetto dell'applicazione (la propria app Web o progetto di servizio Web). Per un'applicazione Web, in genere questo è il Global.asax Application_Start. Questo luogo in cui si collega tutto è chiamato Composition Root nella terminologia DI.

Con una soluzione multi-applicazione, si avrebbe comunque una singola radice di composizione per progetto di applicazione. Questo deve essere, dal momento che ogni applicazione ha la sua configurazione unica. D'altra parte, il codice duplicato è sempre cattivo. Non vuoi dover cambiare tre posizioni quando introduci una nuova astrazione.

Il trucco è spostare tutte le registrazioni lungo la gerarchia del progetto. Ad esempio, è possibile definire un singolo 'assieme di bootstrap' che dipende dagli assembly del livello aziendale (e di seguito) e lasciare che abbia tutte le registrazioni per quegli assembly che non cambiano.Le radici di composizione delle applicazioni possono quindi utilizzare quell'assembly per ottenere le registrazioni predefinite ed estenderle con le dipendenze specifiche dell'applicazione.

Una cosa del genere potrebbe essere simile a questo:

// MVC Composition root 
public static void Bootstrap() 
{ 
    var container = new Container(); 

    // Default registrations 
    BusinessLayerBootstrapper.Bootstrap(container); 

    // Application specific registrations 
    container.Bind<IUserContext>().To<AspNetUserContext>(); 

    DependencyResolver.Current = 
     new ContainerDependencyResolver(container); 
} 

// Windows Service Composition root 
public static void Bootstrap() 
{ 
    var container = new Container(); 

    // Default registrations 
    BusinessLayerBootstrapper.Bootstrap(container); 

    // Application specific registrations 
    container.Bind<IUserContext>().To<SystemUserContext>() 
     .SingleScoped(); 

    // Store somewhere. 
    Bootstrapper.Container = container; 
} 

// In the BL bootstrap assembly 
public static class BusinessLayerBootstrapper 
{ 
    public static void Bootstrap(Container container) 
    { 
     container.Bind<IDepenency>().To<RealThing>(); 
     // etc 
    } 
} 

Anche se non è necessario disporre di un gruppo di bootstrapper separata (è possibile inserire questo codice nel BL stesso), questo permette di mantenere il vostro business gruppi di layer liberi da qualsiasi dipendenza dal contenitore.

Si noti inoltre che sto solo chiamando un metodo statico Bootstrap(), anziché utilizzare i moduli (Ninject). Ho cercato di mantenere la mia risposta indipendente dal framework, dal momento che la tua domanda è generale e il consiglio sarà lo stesso per tutti i framework DI. Tuttavia, se lo desideri, puoi utilizzare la funzionalità del modulo Ninject.

6

Per quanto riguarda la definizione del contenuto di un'applicazione MVC ha bisogno di avere un CompositionRoot diverso da un servizio di Windows. Ti suggerisco di cercare di organizzare il più possibile i moduli di funzionalità (per quelle parti che sono indipendenti dall'applicazione) e tutti gli altri collegamenti direttamente nel CompositionRoot del progetto MVC o WindowsService.

Un altro ottimo approccio consiste nel definire un insieme comune di convenzioni che consente di esprimere le preoccupazioni più vincolanti in poche righe. Pertanto le tue applicazioni potrebbe avere i seguenti al binding:

MVC App

Bind(c => c.FromAssemblyContaining<IRepository>() 
      .SelectAllClasses() 
      .InheritedFrom<IRepository>() 
      .Configure(b => b.InRequestScope())); 

vostro servizio di Windows App

Bind(c => c.FromAssemblyContaining<IRepository>() 
      .SelectAllClasses() 
      .InheritedFrom<IRepository>() 
      .Configure(b => b.InThreadScope())); 

Nel mio punto di vista in combinazione con una funzione orientata strutturazione l'approccio convenzione è il il più pulito

Problemi correlati