2012-08-23 17 views
5

Estoy usando el framework IoC Simple Injector, y me gustaría poder cambiar el registro de dependencia en tiempo de ejecución. Por ejemplo, tengo dos implementaciones, A y B, de la interfaz I. La implementación A se registra al inicio de la aplicación, pero dependiendo de algún indicador que pueda cambiar durante el tiempo de ejecución, me gustaría cambiar la implementación. Actualmente estamos haciendo esto el evento OnActionExecuting de nuestro BaseController, del que todos nuestros controladores heredan. Aquí está el código de muestra de lo que estoy tratando de hacer.¿Cómo cambiar el registro de dependencia en tiempo de ejecución usando un inyector simple?

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); 
} 

Gracias de antemano por su ayuda.

+1

Recomiendo combinar un patrón Factory with a Strategy, en lugar de usar un DI Container para esto. Use el contenedor para resolver su gráfico de objetos desde el principio. Ver [Composition Root] (http://blog.ploeh.dk/2011/07/28/CompositionRoot.aspx). – TrueWill

+0

¿Necesita hacer eso manualmente? ¿Qué pasa con el uso de un marco contenedor IOC? –

Respuesta

9

En caso IsRuntimeFlag es un valor de configuración (por lo tanto no puede cambiar durante el tiempo de vida de la aplicación), se puede hacer que el registro de la siguiente manera:

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

o igualmente:

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

En caso el valor puede cambiar durante la vida útil de la aplicación; un proxy o composite que se ocupa del envío a la instancia correcta es la solución correcta:

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; 
} 

Debido a que el compuesto depende directamente de A y B, sólo tiene que registrarlo como sigue:

container.Register<I, RuntimeFlagIComposite>(); 

Cuando A o B tienen una vida diferente a la transitoria (una nueva instancia para cada solicitud), se también debería registrarlos. Por ejemplo:

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

También puede dejar que su compuesto dependen de la abstracción I sí mismo en vez del hormigón A y B implementaciones:

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

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

Dependiendo del I abstracción hace que esta clase más flexible y más comprobable. Significa, sin embargo, que debe registrarlo un poco diferente:

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

Gracias por su respuesta, sin embargo, este indicador se desconoce en el momento del registro del contenedor y puede cambiar a lo largo de la vida útil de la aplicación. Supongo que puedo establecer una bandera global y cambiarla más adelante durante la aplicación, pero no creo que sea un enfoque limpio de esto. Tras una mirada más cercana, creo que el patrón compuesto podría funcionar en este caso. De nuevo, gracias por tu ayuda. – Will

+0

Hola Steven, Solo me pregunto si tienes alguna otra idea. Al tratar de implementar esto, me di cuenta de que la bandera también depende de las cosas en la capa de la aplicación web, específicamente de los valores de las cookies, a diferencia de la capa de servicio, que es donde estaría el compuesto. Por lo tanto, el compuesto no tendría acceso a la bandera. Gracias de nuevo por adelantado. – Will

+1

Creo que respondió su propia pregunta.Si el compuesto dependería de cosas específicas de la UI, debería definirse en la capa UI. Dado que la interfaz se define en una capa inferior, es absolutamente correcto definirla en la capa de la interfaz de usuario (o incluso puede hacer que forme parte de la raíz de la composición). – Steven

Cuestiones relacionadas