2010-10-15 5 views
7

Sto cercando di introdurre DI (con Autofac) in un'applicazione Windows Form esistente.DI (Autofac) in un'architettura plug-in: è un contenitore DI separato per plug-in OK?

Questa applicazione ha un'architettura plug-in di base in cui ogni plug-in visualizza il proprio modulo. All'avvio, le scansioni delle applicazioni assemblee registrati per i tipi che implementano IPlugin, e quindi attiva queste usando Activator.CreateInstance:

public interface IPlugin 
{ 
    Form MainForm { get; } 
} 

io non posso cambiamento questo dato quadro. Ciò significa che ogni classe di plug-in viene istanziata tramite mezzi non-DI, e mi sembra quindi che dovrò riavviare un contenitore DI separato per ciascun plugin.

La mia domanda è, sta creando un separato ContainerBuilder e contenitore per plug-in OK e comunque ragionevolmente efficiente? (Ci saranno circa 10 diversi plugin.) O dovrebbe esserci solo un contenitore DI per l'intera applicazione?

Ho fornito un codice di esempio della mia soluzione corrente di seguito.


using Autofac; 
using System.Windows.Forms; 

public class Plugin : IPlugin // instantiated by Activator 
{ 
    public Form MainForm { get; private set; } 

    public Plugin() // parameter-less constructor required by plugin framework 
    { 
     var builder = new ContainerBuilder(); 
     builder.RegisterModule(new Configuration()); 
     var container = builder.Build(); 

     MainForm = container.Resolve<MainForm>(); 
     //^preferred to new MainForm(...) because this way, I can take 
     // advantage of having dependencies auto-wired by the container. 
    } 
} 

internal class Configuration : Module 
{ 
    protected override void Load(ContainerBuilder builder) 
    { 
     builder.RegisterType<MainForm>().SingleInstance(); 
     // ... more plugin-specific registrations go here... 
    } 
} 

internal class MainForm : Form { /* ... */ } 

Io non sono sicuro se anche la creazione di un contenitore nel costruttore plug-in e poi semplicemente dimenticare a questo proposito, ma lasciando a fare auto-cablaggio in background, è OK?

risposta

7

L'utilizzo del contenitore dovrebbe idealmente seguire lo Register Resolve Release pattern (RRR). So che hai detto che non puoi modificare l'attuale utilizzo di Activator.CreateInstance, ma può comunque essere utile capire come dovrebbe essere davvero.

Se non si dispone di tale vincolo, deve essere presente una sola istanza contenitore, ospitata dall'applicazione padre stessa. Questo potrebbe quindi essere usato per comporre tutti i plugin. Ciò consentirebbe ai plugin di condividere dipendenze. Questo è il percorso preso da MEF, che affronta anche gli scenari di estensibilità.

Ora, dato che non puoi farlo, la cosa migliore che puoi fare è avere un contenitore per plugin come suggerisci. Diventa per lo più un dettaglio di implementazione a quel punto. In ogni plugin, dovresti comunque seguire il modello RRR.

Sarebbe inefficiente? A meno che tu non abbia molti plugin e li crei e li distrugga tutto il tempo, un paio di contenitori diversi non dovrebbero avere molta importanza. Tuttavia, è meglio misurare che creare ottimizzazioni premature.

In questo scenario, è possibile condividere un contenitore solo rendendolo statico. Tuttavia, questo rende le cose più complicate di quanto debbano essere, quindi non seguire questa strada se non assolutamente necessario.

+0

Grazie per la risposta, @ Mark. Se ti capisco bene, il mio codice di esempio segue già il modello RRR ... giusto? (Con l'eccezione che non rilascio il contenitore, poiché deve rimanere attivo almeno fino a quando il componente root 'MainForm'. Suppongo che il modo ideale per farlo sia rendere i plugin' IDisposable' e rilasciare il contenitore nel metodo 'Dispose'.) – stakx

+2

Non c'è nulla nel codice che suggerisce di non seguire RRR, ma è difficile da dire. In ogni caso, tieni presente che lo stile di vita SingleInstance definisce solo Singleton con ambito contenitore. Non è un vero Singleton, quindi non puoi condividere la MainForm in questo modo. –

0

Io non sono sicuro se anche la creazione di un contenitore nel costruttore plug-in e poi semplicemente dimenticare a questo proposito, ma lasciando a fare auto-cablaggio in background, è OK?

Guardando alla mia domanda molti mesi dopo, oserei dire che solo dimenticare il container non è OK, dal momento che (a) è IDisposable e deve essere trattato come tale, e (b) durata alcuni componenti sono legati al contenitore, quindi la vita del contenitore dovrebbe essere terminata esplicitamente; sia nel metodo Dispose del modulo sia quando viene attivato l'evento FormClosed.