2011-05-02 10 views
5

Para una aplicación web, parece que una buena forma de manejar la sesión es usar la configuración <property name="current_session_context_class">managed_web</property>, llame al CurrentSessionContext.Bind/Unbind en Begin/EndRequest. Entonces solo puedo usar sessionFactory.GetCurrentSession() en la clase de repositorio.Estrategia de gestión de sesiones de Nhibernate para aplicaciones web con trabajadores en segundo plano?

Esto funciona bien para todas las solicitudes de página. Pero tengo trabajadores de fondo haciendo cosas y utilizando las mismas clases de repositorio para hacer cosas. Estos no se ejecutan dentro de una solicitud web, por lo que el manejo de la sesión no funcionará.

¿Alguna sugerencia de cómo se puede resolver esto?

Respuesta

14

Lo resuelto mediante la creación de mi propia clase de contexto de sesión:

public class HybridWebSessionContext : CurrentSessionContext 
{ 
    private const string _itemsKey = "HybridWebSessionContext"; 
    [ThreadStatic] private static ISession _threadSession; 

    // This constructor should be kept, otherwise NHibernate will fail to create an instance of this class. 
    public HybridWebSessionContext(ISessionFactoryImplementor factory) 
    { 
    } 

    protected override ISession Session 
    { 
     get 
     { 
      var currentContext = ReflectiveHttpContext.HttpContextCurrentGetter(); 
      if (currentContext != null) 
      { 
       var items = ReflectiveHttpContext.HttpContextItemsGetter(currentContext); 
       var session = items[_itemsKey] as ISession; 
       if (session != null) 
       { 
        return session; 
       } 
      } 

      return _threadSession; 
     } 
     set 
     { 
      var currentContext = ReflectiveHttpContext.HttpContextCurrentGetter(); 
      if (currentContext != null) 
      { 
       var items = ReflectiveHttpContext.HttpContextItemsGetter(currentContext); 
       items[_itemsKey] = value; 
       return; 
      } 

      _threadSession = value; 
     } 
    } 
} 
+6

Si no quiere hacer referencia a 'HttpContext.Current', puede usar' NHibernate.Context.ReflectiveHttpContext' para determinar si un contexto está disponible. Esto es útil en situaciones donde no desea hacer referencia 'System.Web' en un proyecto de acceso a datos, por ejemplo. – Siewers

+1

Gracias, buen consejo! ¡He editado el código para usarlo en su lugar! :) – Allrameest

+1

¡Muchas gracias! Estuve desconcertado por esto durante medio día. Tengo un proyecto de WebForms con un servicio WCF, y 'CurrentSessionContext.Bind' arrojaba una' NullReferenceException'. Tu código funcionó perfectamente para mí: D –

0

En mi proyecto, escribí una pequeña clase contenedora alrededor del CurrentSessionContext.
Quizás pueda ampliarlo según sus necesidades.
creo que sólo tiene que ajustar la ejecución de BindSessionToRequest y GetCurrentSession:

public static class SessionManager 
    { 
     private static ISessionFactory _sessionFactory = null; 
     private static ISessionFactory SessionFactory 
     { 
      get 
      { 
       if (_sessionFactory == null) 
       { 
        //check whether we're in web context or win context, and create the session factory accordingly. 
        if (System.Web.HttpContext.Current != null) 
        { 
         if (_sessionFactory == null) 
         { 
          _sessionFactory = DAOBase.GetSessionFactory(); 
         } 
        } 
        else 
        { 
         _sessionFactory = DAOBase.GetSessionFactoryForWin(); 
        } 
       } 
       return _sessionFactory; 
      } 
     } 

     public static void BindSessionToRequest() 
     { 
      ISession session = SessionManager.SessionFactory.OpenSession(); 
      NHibernate.Context.CurrentSessionContext.Bind(session); 
     } 

     public static bool CurrentSessionExists() 
     { 
      return NHibernate.Context.CurrentSessionContext.HasBind(SessionFactory); 
     } 

     public static void UnbindSession() 
     { 
      ISession session = NHibernate.Context.CurrentSessionContext.Unbind(SessionManager.SessionFactory); 
      if (session != null && session.IsOpen) 
      { 
       session.Close(); 
      } 
     } 

     public static ISession GetCurrentSession() 
     { 
      return SessionFactory.GetCurrentSession(); 
     } 
    } 
2

he encontrado que es más simple en este escenario para manejar creación de la sesión a mí mismo usando una biblioteca DI y el alcance 'híbrido' (en StructureMap, esto se define como InstanceScope.Hybrid). Esto abarcará las instancias de HttpContext en un dominio de aplicación ASP.net y ThreadStatic en un dominio de aplicación normal, lo que le permite usar el mismo enfoque en ambos.

Estoy seguro de que otras bibliotecas DI ofrecen una función similar.

+0

Esto probablemente funcionaría. Pero utilizo Castle, que no tiene ese tipo de estilo de vida híbrido fuera de la caja. Entonces tendría que construirlo yo mismo. Entonces fue simplemente más simple construir una clase de contexto de sesión NHibernate (ver mi respuesta). Pero gracias por darme indirectamente esa idea. :) – Allrameest

Cuestiones relacionadas