2010-01-12 10 views
11

Actualmente estoy creando un proyecto ASP.NET MVC, con NHibernate como capa de persistencia.¿Cómo puedo implementar un sólido patrón de sesión por solicitud en mi proyecto, mientras me enfoco en ocultar información?

Por ahora, algunas funcionalidades han sido implementadas, pero solo usan sesiones locales de NHibernate: cada método que accedió a la base de datos (de lectura o escritura) necesita crear una instancia de su propia sesión de NHibernate, con la cláusula "using()".

El problema es que quiero aprovechar las capacidades de carga diferida de NHibernate para mejorar el rendimiento de mi proyecto.

Esto implica una sesión abierta de NHibernate por solicitud hasta que se visualice la vista. Además, las solicitudes simultáneas deben ser compatibles (varias sesiones al mismo tiempo).

¿Cómo puedo lograr eso tan limpiamente como sea posible?

He buscado un poco en la web y he aprendido sobre el patrón de sesión por solicitud. La mayoría de las implementaciones que vi utilizaban algún tipo de objeto Http * (HttpContext, etc.) para almacenar la sesión. Además, el uso de las funciones Application_BeginRequest/Application_EndRequest es complicado, ya que se activan para cada solicitud HTTP (archivos aspx, archivos css, archivos js, etc.), cuando solo deseo instanciar una sesión una vez por solicitud.

La preocupación que tengo es que no quiero que mis vistas o controladores tengan acceso a las sesiones de NHibernate (o, más en general, a los espacios de nombres y el código de NHibernate). Eso significa que no quiero manejar sesiones en el nivel de controlador ni en el de vista.

Tengo algunas opciones en mente. ¿Cuál parece el mejor?

  • Use interceptores (como en GRAILS) que se disparan antes y después de la acción del controlador. Estos abrirían y cerrarían sesiones/transacciones. ¿Es esto posible en el mundo ASP.NET MVC?
  • Utilice el Singleton CurrentSessionContext proporcionado por NHibernate en un contexto web. Usando this page como ejemplo, creo que esto es bastante prometedor, pero que aún requiere filtros en el nivel del controlador.
  • Utilice HttpContext.Current.Items para almacenar la sesión de solicitud. Esto, junto con unas pocas líneas de código en Global.asax.cs, puede proporcionarme fácilmente una sesión en el nivel de solicitud. Sin embargo, significa que las dependencias se inyectarán entre NHibernate y mis vistas (HttpContext).

Muchas gracias!

+0

"serán inyectados dependencias entre NHibernate y mis puntos de vista" -> No es muy claro lo que quiere decir con esto, ¿Puedes explicar más? –

+0

Si uso HttpContext para almacenar una sesión de NHibernate, el aspecto Vista de mi aplicación MVC se combinará con el aspecto de acceso a datos (sesión NHibernate). –

+0

@ggervais: eso solo ocurre si utiliza la carga diferida en sus vistas, lo que no debería hacer. –

Respuesta

13

Bueno, chicos, después de unos días de trabajo, finalmente decidí usar HttpContext.Current.Items para cargar la sesión.

Funciona muy bien!

Así es como lo hice

import System.Web 
class SessionManager { 
    public static ISession GetSession() 
     var session = HttpContext.Current.Items["NHibernateSession"]; 
     if (session == null) { 
      session = ...; // Create session, like SessionFactory.createSession()... 
      HttpContext.Current.Items.Add("NHibernateSession", session); 
     } 
     return session; 
    } 

    public static void CloseSession() 
    { 
     var session = HttpContext.Current.Items["NHibernateSession"]; 
     if (session != null) { 
      if (session.IsOpen) { 
       session.close(); 
      } 
      HttpContext.Current.Items.Remove("NHibernateSession"); 
     } 
    } 
} 

Mediante el uso de los métodos estáticos que ofrece esta clase, se puede obtener una sesión (por ejemplo, en un controlador) que está ligado a la HttpContext actual (el solicitud web actual). Necesitamos otro fragmento de código para llamar al método CloseSession() cuando se complete la solicitud.

En Global.asax.cs:

protected void Application_EndRequest(object sender, EventArgs args) 
{ 
    NHibernateSessionManager.CloseSession(); 
} 

El evento Application_EndRequest es llamado automáticamente cuando se haya completado la sesión, por lo que la sesión puede ser adecuadamente cerrado un desecharse. Esto es útil, porque de lo contrario tendríamos que hacer esto en cada controlador.

+1

¿Puede dar más detalles, por favor, para aquellos de nosotros que intentamos descubrir cómo configurar esto? –

+0

@ joe-phillips: ver mi edición, ¡lo expliqué! –

+0

Creo que esto podría crear problemas mientras haces las pruebas unitarias, debes ocuparte de lo mismo. Encontré este enlace http://www.prideparrot.com/blog/archive/2012/7/how_to_create_a_custom_session_value_provider, que podría ser una buena opción. Cualquier entrada sería bueno? –

1

Eche un vistazo a S#arp Architecture. Es una arquitectura muy agradable para ASP.NET MVC y NHibernate.

2

Uso DI junto con un COI. La mayoría de los IoC vienen con un comportamiento de instanciación por solicitud.

Cuestiones relacionadas