Gestión de la sesión de NHibernate con Autofac
(2)
¿Alguien tiene alguna sugerencia o buenas prácticas sobre cómo Autofac puede ayudar a administrar la instancia de sesión de NHibernate (en el caso de una aplicación MVC de ASP.NET)?
Edición: Suena como Autofac y, probablemente, otros contenedores pueden cubrir el tiempo de vida correctamente. Si ese es el caso, ve por ello.
No es una buena idea usar su contenedor de IoC para administrar las sesiones directamente. La duración de su sesión debe corresponder a su unidad de trabajo (límite de transacción). En el caso de una aplicación web, es casi seguro que debe ser la vida útil de una solicitud web.
La forma más común de lograr esto es con un HttpModule que crea su sesión y comienza su transacción cuando comienza una solicitud, y luego se compromete cuando la solicitud ha finalizado. Me gustaría que HttpModule registre la sesión en la colección HttpContext.Items.
En su contenedor de IoC, puede registrar algo como HttpContextSessionLocator contra ISessionLocator.
Debería mencionar que su manejo genérico de errores debería ubicar la sesión actual y revertir la transacción automáticamente, o podría terminar cometiendo la mitad de una unidad de trabajo.
No estoy demasiado familiarizado con la forma en que deben manejarse las sesiones de NHibernate. Dicho esto, Autofac tiene un excelente manejo de por vida (instancias y eliminación determinística ). Algunos recursos relacionados son este artículo y esta pregunta . Ya que estás en el sitio de ASP.Net MVC, asegúrate de que también analices las cosas de integración de MVC .
Para ilustrar el punto, aquí hay una muestra rápida de cómo puede usar los delegados de fábrica de Autofac y el genérico de Owned
para obtener un control total sobre la vida útil de la instancia:
public class SomeController
{
private readonly Func<Owned<ISession>> _sessionFactory;
public SomeController(Func<Owned<ISession>> sessionFactory)
{
_sessionFactory = sessionFactory;
}
public void DoSomeWork()
{
using (var session = _sessionFactory())
{
var transaction = session.Value.BeginTransaction();
....
}
}
}
La configuración del contenedor para que esto funcione es bastante simple. Tenga en cuenta que no tenemos que hacer nada para obtener los tipos Func<>
y Owned<>
, estos están disponibles automáticamente mediante Autofac:
builder.Register(c => cfg.BuildSessionFactory())
.As<ISessionFactory>()
.SingleInstance();
builder.Register(c => c.Resolve<ISessionFactory>().OpenSession());
Actualización: mi razonamiento aquí es que, de acuerdo con este tutorial de NHibernate , la duración de la sesión debe ser la de la "unidad de trabajo". Por lo tanto, necesitamos alguna forma de controlar tanto cuando se crea la instancia de sesión como cuando se elimina la sesión.
Con Autofac obtenemos este control solicitando un Func<>
lugar del tipo directamente. No utilizar Func<>
requeriría que la instancia de sesión se cree por adelantado antes de que se cree la instancia del controlador.
A continuación, el valor predeterminado en Autofac es que las instancias tienen la vida útil de su contenedor. Como sabemos que necesitamos el poder para disponer esta instancia tan pronto como la unidad de trabajo esté terminada, solicitamos una instancia Owned
. La eliminación de la instancia de propiedad en este caso dispondrá inmediatamente de la sesión subyacente.