2012-06-02 16 views
9

Problema (abstract)Autofac - Lifetime y módulos

Dado un módulo que registra la dependencia X. La dependencia X tiene una vida útil diferente en una aplicación MVC3 (tiempo de vida por HttpRequest) a continuación, en una aplicación de consola (dependencia por lifetimescope con un nombre). ¿Dónde o cómo especificar el tiempo de vida de la dependencia X?

Caso

He puesto todo mi código de base de datos relacionada en un montaje con un módulo ahí que registra todos los repositorios. Ahora el registro ISession (Nhibernate) también está en el módulo.

ISession es la dependencia X (en el caso del problema dado). ISession tiene una vida útil diferente en una aplicación MVC3 (tiempo de vida por solicitud) luego en una aplicación de consola en la que defino un periodo de vida con nombre.

¿El registro de ISession debe estar fuera del módulo? Sería extraño ya que es un detalle de implementación.

¿Cuál es el mejor caso para hacer aquí? ¿Defecto de diseño o hay construcciones inteligentes para esto :)?

+0

¿Tiene vidas útiles específicas en mente para las conexiones? Si es así, ¿son diferentes las duraciones de cada aplicación o es siempre la misma independientemente del tipo de aplicación? ¿Qué hay de la puesta en común? ¿Se agrupa en algunas aplicaciones, pero no en otras? –

+0

Es como usted dijo "Las extensiones MVC usan un alcance designado para lograr el mecanismo de una vez por solicitud". El alcance nombrado Http no está allí cuando utiliza el módulo en la aplicación de la consola. Actualmente estoy viendo cuál será la unidad de trabajo y que estará encapsulada en un alcance. –

Respuesta

7

Dada la descripción de su caso de uso, diría que tiene algunas opciones.

Primero, puede hacer que cada aplicación registre su propio conjunto de dependencias incluyendo el alcance de por vida. Tener una o dos piezas de código "duplicadas" a este respecto no es tan importante teniendo en cuenta las diferencias entre la aplicación y el hecho de que los registros parecen bastante pequeños.

En segundo lugar, podría envolver la parte común (menos el alcance de por vida) en un método de extensión ContainerBuilder que podría utilizarse en cada aplicación. Todavía significaría que cada aplicación tiene un pequeño "código duplicado", pero la lógica común estaría envuelta en una simple extensión.

public static IRegistrationBuilder<TLimit, ScanningActivatorData, DynamicRegistrationStyle> 
    RegisterConnection<TLimit, ScanningActivatorData, DynamicRegistrationStyle>(this ContainerBuilder builder) 
{ 
    // Put the common logic here: 
    builder.Register(...).AsImplementedInterfaces(); 
} 

El consumo de una extensión tal en cada aplicación se vería así:

builder.RegisterConnection().InstancePerHttpRequest(); 
// or 
builder.RegisterConnection().InstancePerLifetimeScope(); 

Por último, si usted sabe que es ya sea web o no en la web, usted podría hacer un módulo personalizado que controla el interruptor :

public class ConnectionModule : Autofac.Module 
{ 
    bool _isWeb; 
    public ConnectionModule(bool isWeb) 
    { 
    this._isWeb = isWeb; 
    } 

    protected override void Load(ContainerBuilder builder) 
    { 
    var reg = builder.Register(...).AsImplementedInterfaces(); 
    if(this._isWeb) 
    { 
     reg.InstancePerHttpRequest(); 
    } 
    else 
    { 
     reg.InstancePerLifetimeScope(); 
    } 
    } 
} 

En cada aplicación, usted podría entonces registrar el módulo:

// Web application: 
builder.RegisterModule(new ConnectionModule(true)); 

// Non-web application: 
builder.RegisterModule(new ConnectionModule(false)); 

O bien, mencionaste que el alcance de tu vida en tus otras aplicaciones tiene un nombre.usted podría hacer su módulo de tomar el nombre:

public class ConnectionModule : Autofac.Module 
{ 
    object _scopeTag; 
    public ConnectionModule(object scopeTag) 
    { 
    this._scopeTag = scopeTag; 
    } 

    protected override void Load(ContainerBuilder builder) 
    { 
    var reg = builder.Register(...) 
        .AsImplementedInterfaces() 
        .InstancePerMatchingLifetimeScope(this._scopeTag); 
    } 
} 

El consumo es similar:

// Web application (using the standard tag normally provided): 
builder.RegisterModule(new ConnectionModule("httpRequest")); 

// Non-web application (using your custom scope name): 
builder.RegisterModule(new ConnectionModule("yourOtherScopeName")); 

recomendaría contra el simple uso de InstancePerLifetimeScope en una aplicación web a menos que en realidad es lo que se propone. Como se menciona en otras respuestas/comentarios, InstancePerHttpRequest usa un alcance específico de por vida con nombre para que sea seguro crear ámbitos de vida para niños; usar InstancePerLifetimeScope no tiene tal restricción así que realmente obtendrá una conexión por alcance de hijo en lugar de una conexión para la solicitud. Yo, personalmente, no asumo que otros desarrolladores no harán uso de los alcances de la vida del niño (which is a recommended practice), entonces en mis aplicaciones soy muy específico. Si tiene el control total de su aplicación y puede asegurar que no está creando ámbitos secundarios adicionales o que realmente desea una conexión por alcance, entonces quizás InstancePerLifetimeScope resolverá su problema.

+0

¡Gracias por la amplia respuesta! He llegado a esto: https://gist.github.com/2883596 Llamas a ConfigureUnitOfWork para configurar en la dependencia IUnitOfWork que oculta los detalles de la implementación. Además, esta solución no depende de las extensiones MVC3. El único inconveniente de esta solución es que puede configurar todo mientras solo desea permitir la duración de la vida, puede ser abstraída, pero se corta si por ahora :) –

0

Es una práctica común utilizar una conexión por solicitud HTTP. Siendo ese el caso, las conexiones se registrarían usando .InstansePerLifetimeScope(). Por ejemplo, puede hacer algo como:

builder 
    .Register(c => { 
         var conn = new SqlConnection(GetConnectionString()); 
         conn.Open(); 
         return conn; 
        }) 
    .AsImplementedInterfaces() 
    .InstancePerLifetimeScope(); 
+0

Sí, sé que puedes hacer eso. Mi problema es dónde hacer esto? Es algo de lo que el módulo 'datos' debería ser responsable. Sin embargo, parece que no hay forma de registrar la conexión dentro del módulo y establecer la vida útil fuera del módulo. –

+0

Registraría la conexión y establecería la vida útil dentro del módulo de datos. –

+0

Ese es el problema en una aplicación MVC, la duración es diferente a la de una aplicación de consola donde no existe un contexto como Http –