He estado usando NHibernate desde hace un tiempo y he encontrado de vez en cuando que si trato de solicitar dos páginas simultáneamente (o lo más cerca que pueda) ocasionalmente se produce un error. Así que asumí que era porque mi gestión de sesión no era segura para subprocesos.NHibernate thread safety con la sesión
Pensé que era mi clase, así que traté de usar un método diferente de esta publicación de blog http://pwigle.wordpress.com/2008/11/21/nhibernate-session-handling-in-aspnet-the-easy-way/, sin embargo, sigo teniendo los mismos problemas. El error real que estoy recibiendo es:
Server Error in '/AvvioCMS' Application.
failed to lazily initialize a collection, no session or session was closed
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: NHibernate.LazyInitializationException: failed to lazily initialize a collection, no session or session was closed
O eso, o ninguna datareader está abierto, pero este es el principal culpable.
He colocado mi clase de gestión de sesión a continuación, ¿alguien puede detectar por qué puedo tener estos problemas?
public interface IUnitOfWorkDataStore
{
object this[string key] { get; set; }
}
public static Configuration Init(IUnitOfWorkDataStore storage, Assembly[] assemblies)
{
if (storage == null)
throw new Exception("storage mechanism was null but must be provided");
Configuration cfg = ConfigureNHibernate(string.Empty);
foreach (Assembly assembly in assemblies)
{
cfg.AddMappingsFromAssembly(assembly);
}
SessionFactory = cfg.BuildSessionFactory();
ContextDataStore = storage;
return cfg;
}
public static ISessionFactory SessionFactory { get; set; }
public static ISession StoredSession
{
get
{
return (ISession)ContextDataStore[NHibernateSession.CDS_NHibernateSession];
}
set
{
ContextDataStore[NHibernateSession.CDS_NHibernateSession] = value;
}
}
public const string CDS_NHibernateSession = "NHibernateSession";
public const string CDS_IDbConnection = "IDbConnection";
public static IUnitOfWorkDataStore ContextDataStore { get; set; }
private static object locker = new object();
public static ISession Current
{
get
{
ISession session = StoredSession;
if (session == null)
{
lock (locker)
{
if (DBConnection != null)
session = SessionFactory.OpenSession(DBConnection);
else
session = SessionFactory.OpenSession();
StoredSession = session;
}
}
return session;
}
set
{
StoredSession = value;
}
}
public static IDbConnection DBConnection
{
get
{
return (IDbConnection)ContextDataStore[NHibernateSession.CDS_IDbConnection];
}
set
{
ContextDataStore[NHibernateSession.CDS_IDbConnection] = value;
}
}
}
Y la tienda real que estoy usando es el siguiente:
public class HttpContextDataStore : IUnitOfWorkDataStore
{
public object this[string key]
{
get { return HttpContext.Current.Items[key]; }
set { HttpContext.Current.Items[key] = value; }
}
}
Me inicializar la SessionFactory en Application_Start con:
NHibernateSession.Init(new HttpContextDataStore(), new Assembly[] {
typeof(MappedClass).Assembly});
Actualizar
Hola chicos, gracias por su consejo, he intentado algunos diferentes cosas para intentar y simplificar el código, pero todavía me encuentro con los mismos problemas y puedo tener una idea de por qué.
Creo la sesión cada vez que la solicito, pero en mi archivo global.asax dispongo de la sesión en Application_EndRequest. Sin embargo, estoy descubriendo que Application_EndRequest se activa más de una vez mientras estoy en depuración al finalizar la carga de una página. Pensé que el evento solo debía disparar una vez al final de la solicitud, pero si no es así y algunos otros elementos están tratando de usar la sesión (que es de lo que se queja el error) por cualquier razón extraña que podría ser mi problema y la Sesión aún está libre de subprocesos; solo se está desechando a tiempo.
¿Alguien tiene alguna idea? Hice un google y vi que el servidor de desarrollo VS causa problemas como ese, pero lo estoy ejecutando a través de IIS.
Gracias stuart, solo estoy tratando de mantener la sesión durante todo el tiempo que la solicitud a la página está activa, lo que me hubiera parecido bastante corto. Puedo intentar crear una sesión para cada llamada a DB, pero eso parece un poco pesado para mí. –
Ok, veo a dónde vas con esto. Ver editar. Sin embargo, como nota al margen, como mencioné al declarar que ISession es estático, significa que se mantendrá durante más tiempo que una sola solicitud de página (probablemente). –
@StuartChilds ¿me puede apuntar a una implementación sin ningún IHttpModule? Además, ¿cómo gestiona las transacciones y descarga/cierra las sesiones? – Rahatur