2012-08-23 13 views
5

Sto utilizzando il framework IoC Simple Injector e vorrei poter modificare la registrazione delle dipendenze in fase di esecuzione. Ad esempio, ho due implementazioni, A e B, dell'interfaccia I. L'implementazione A è registrata all'avvio dell'app, ma a seconda di alcuni flag che possono cambiare durante il runtime, vorrei passare all'implementazione. Attualmente stiamo facendo questo l'evento OnActionExecuting del nostro BaseController, da cui tutti i nostri controllori ereditano. Ecco il codice di esempio di ciò che sto cercando di fare.Come modificare la registrazione delle dipendenze in fase di esecuzione utilizzando l'iniettore semplice?

protected override void OnActionExecuting(
    ActionExecutingContext filterContext) 
{ 
    if (IsRuntimeFlag) 
    { 
     // check current implementation type and 
     // change implementation to A 
    } 
    else 
    { 
     // check current implementation type and 
     // change implementation to B 
    } 

    base.OnActionExecuting(filterContext); 
} 

Grazie in anticipo per il vostro aiuto.

+1

Si consiglia di combinare una Fabbrica con un modello di strategia, piuttosto che utilizzare un contenitore DI per questo. Usa il contenitore per risolvere il tuo grafico degli oggetti nelle prime fasi. Vedi [Composizione radice] (http://blog.ploeh.dk/2011/07/28/CompositionRoot.aspx). – TrueWill

+0

Hai bisogno di farlo manualmente? Che ne pensi di utilizzare un framework di contenitori IOC? –

risposta

9

In caso IsRuntimeFlag è un valore di configurazione (quindi non può cambiare durante la vita dell'applicazione), è possibile effettuare la registrazione come segue:

if (IsRuntimeFlag) 
{ 
    container.Register<I, A>(); 
} 
else 
{ 
    container.Register<I, B>(); 
} 

o ugualmente:

container.Register(typeof(I), IsRuntimeFlag ? typeof(A) : typeof(B)); 

Nel caso in cui il valore può cambiare durante la vita dell'applicazione un proxy o composite che si occupa dell'erogazione all'istanza giusta è la soluzione giusta:

public sealed class RuntimeFlagIComposite : I 
{ 
    private readonly A a; 
    private readonly B b; 

    public RuntimeFlagIComposite(A a, B b) { 
     this.a = a; 
     this.b = b; 
    } 

    void I.Method() => this.Instance.Method(); 

    private I Instance => IsRuntimeFlag ? this.a : this.b; 
} 

Perché il composito dipende direttamente A e B, si può semplicemente registrarsi come segue:

container.Register<I, RuntimeFlagIComposite>(); 

Quando A o B hanno una vita diversa da quella transitoria (una nuova istanza per ogni richiesta), è dovrebbe anche registrarli. Per esempio:

container.Register<A>(Lifestyle.Singleton); 
container.Register<B>(Lifestyle.Scoped); 

Si può anche lasciare il vostro composito dipendono dalla I astrazione stesso anziché calcestruzzo A e B implementazioni:

public class RuntimeFlagIComposite : I 
{ 
    private I a; 
    private I b; 

    public RuntimeFlagIComposite(I a, I b) 
    { 
     this.a = a; 
     this.b = b; 
    } 
} 

A seconda del I astrazione rende questa classe più flessibile e più verificabile. Significa tuttavia che è necessario registrarlo un po 'diverso:

container.Register<I, RuntimeFlagIComposite>(); 

container.RegisterConditional<I, A>(c => c.Consumer.Target.Name == "a"); 
container.RegisterConditional<I, B>(c => c.Consumer.Target.Name == "b"); 
+0

Grazie per la risposta, tuttavia, questo flag è sconosciuto al momento della registrazione del contenitore e può variare durante l'intero ciclo di vita dell'applicazione. Credo di poter impostare una bandiera globale e cambiarla più tardi durante l'applicazione, ma non penso che sia un approccio pulito a questo. A ben guardare, penso che il modello composito potrebbe funzionare in questo caso. Grazie ancora per il vostro aiuto. – Will

+0

Ciao Steven, Basta chiedersi se avete altre idee. Nel tentativo di implementare ciò, mi sono reso conto che il flag dipende anche dalle cose nel livello della web app, i valori dei cookie in modo specifico, al contrario del livello del servizio, che è il luogo in cui si trova il composito. Pertanto, il composito non avrebbe accesso al flag. Grazie ancora in anticipo. – Will

+1

Penso che tu abbia risposto alla tua stessa domanda.Se il composito dipenderebbe da elementi specifici dell'interfaccia utente, dovrebbe essere definito nel livello dell'interfaccia utente. Poiché l'interfaccia è definita in un livello inferiore, è assolutamente corretto definirla nel tuo livello di interfaccia utente (o potresti addirittura farne parte della tua radice di composizione). – Steven

Problemi correlati