NHibernate, et impair "Session is Closed!" Erreurs
Note: Maintenant que j'ai tapé, je dois m'excuser pour le super longue question, cependant, je pense que tout le code et les informations présentées ici est, d'une certaine façon pertinente.
D'accord, je suis bizarre "de la fermeture de la Session" les erreurs, à des points aléatoires dans mon ASP.NET formulaires de demande. Aujourd'hui, cependant, c'est enfin passe au même endroit, encore et encore. Je suis près certain que rien n'est de l'élimination ou de la fermeture de la session dans mon code, comme les morceaux de code qui utilisent sont bien contenues à l'écart de tous les autres code comme vous le verrez ci-dessous.
Je suis également en utilisant ninject que mon CIO, qui peuvent /ne peuvent pas être important.
Bon, alors, tout d'Abord, ma SessionFactoryProvider
et SessionProvider
classes:
SessionFactoryProvider
public class SessionFactoryProvider : IDisposable
{
ISessionFactory sessionFactory;
public ISessionFactory GetSessionFactory()
{
if (sessionFactory == null)
sessionFactory =
Fluently.Configure()
.Database(
MsSqlConfiguration.MsSql2005.ConnectionString(p =>
p.FromConnectionStringWithKey("QoiSqlConnection")))
.Mappings(m =>
m.FluentMappings.AddFromAssemblyOf<JobMapping>())
.BuildSessionFactory();
return sessionFactory;
}
public void Dispose()
{
if (sessionFactory != null)
sessionFactory.Dispose();
}
}
SessionProvider
public class SessionProvider : IDisposable
{
ISessionFactory sessionFactory;
ISession session;
public SessionProvider(SessionFactoryProvider sessionFactoryProvider)
{
this.sessionFactory = sessionFactoryProvider.GetSessionFactory();
}
public ISession GetCurrentSession()
{
if (session == null)
session = sessionFactory.OpenSession();
return session;
}
public void Dispose()
{
if (session != null)
{
session.Dispose();
}
}
}
Ces deux classes sont câblés avec Ninject de la manière suivante:
NHibernateModule
public class NHibernateModule : StandardModule
{
public override void Load()
{
Bind<SessionFactoryProvider>().ToSelf().Using<SingletonBehavior>();
Bind<SessionProvider>().ToSelf().Using<OnePerRequestBehavior>();
}
}
et aussi loin que je peux dire à fonctionner comme prévu.
Maintenant mon BaseDao<T>
classe:
BaseDao
public class BaseDao<T> : IDao<T> where T : EntityBase
{
private SessionProvider sessionManager;
protected ISession session { get { return sessionManager.GetCurrentSession(); } }
public BaseDao(SessionProvider sessionManager)
{
this.sessionManager = sessionManager;
}
public T GetBy(int id)
{
return session.Get<T>(id);
}
public void Save(T item)
{
using (var transaction = session.BeginTransaction())
{
session.SaveOrUpdate(item);
transaction.Commit();
}
}
public void Delete(T item)
{
using (var transaction = session.BeginTransaction())
{
session.Delete(item);
transaction.Commit();
}
}
public IList<T> GetAll()
{
return session.CreateCriteria<T>().List<T>();
}
public IQueryable<T> Query()
{
return session.Linq<T>();
}
}
Qui est lié à Ninject comme suit:
DaoModule
public class DaoModule : StandardModule
{
public override void Load()
{
Bind(typeof(IDao<>)).To(typeof(BaseDao<>))
.Using<OnePerRequestBehavior>();
}
}
Maintenant le web demande qui est à l'origine de ce est quand je suis à la sauvegarde d'un objet, il n'a pas eu lieu jusqu'à j'ai apporté quelques modifications au modèle d'aujourd'hui, cependant, les changements à mon modèle n'a pas changé le code d'accès aux données dans de toute façon. Si elle a changé un peu de mappages NHibernate (je peux poster ces trop si quelqu'un est intéressé)
D'aussi loin que je peux dire, BaseDao<SomeClass>.Get
est appelé ensuite BaseDao<SomeOtherClass>.Get
est appelé ensuite BaseDao<TypeImTryingToSave>.Save
est appelé.
c'est le troisième appel à la ligne dans Save()
using (var transaction = session.BeginTransaction())
qui échoue avec "la Session est Fermée!" ou plutôt de l'exception:
Session is closed!
Object name: 'ISession'.
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: System.ObjectDisposedException: Session is closed!
Object name: 'ISession'.
Et en effet, suite à la Débogueur affiche le troisième temps de la séance est demandée à partir du SessionProvider
il est en effet fermé et n'est pas connecté.
J'ai vérifié que Dispose
sur mon SessionFactoryProvider
et sur mon SessionProvider
sont appelés à la fin de la demande, et pas avant la Save
appel est effectué sur mon Dao.
Alors maintenant, je suis un peu coincé. Un peu de choses de la pop à l'esprit.
- Suis-je en train de faire quelque chose de toute évidence mal?
- Ne NHibernate jamais fermer les sessions sans me demander?
- Des solutions de contournement ou des idées sur ce que je pourrais faire?
Merci d'avance
source d'informationauteur Sekhat
Vous devez vous connecter pour publier un commentaire.
ASP.NET est multi-thread de sorte que l'accès à la ISession doit être thread-safe. En supposant que vous êtes à l'aide de session-par-requête, de la façon la plus simple de le faire est d'utiliser NHibernate est intégré dans la gestion des des sessions contextuelles.
D'abord configurer NHibernate pour utiliser le web session le contexte de la classe:
Puis utilisez le
ISessionFactory.GetCurrentSession()
pour obtenir une session existante, ou de lier une nouvelle session de l'usine s'il n'en existe aucun. Ci-dessous je vais couper-coller de mon code pour l'ouverture et la fermeture d'une session.J'ai couru dans la Session Fermée/ObjectDisposedExceptions par intermittence lors de l'exécution des tests d'intégration pour un projet d'API Web, j'ai été travailler sur.
Aucun des conseils ici résolu, j'ai donc construit une version de débogage de NHibernate pour en savoir plus, et je l'ai vu faire une requête linq lorsque le contrôleur est
Get
fonction était de retour avec laIEnumerable
de réponse objets.Il s'est avéré que notre référentiel était en train de faire une requête linq et le retour de l'
IEnumerable
des objets du domaine, mais jamais appelerToList()
forcer l'évaluation de la requête. Le service remis leIEnumerable
et le Contrôleur a enveloppé le énumérable à la réponse des objets et l'a retourné.Lors de cette déclaration, la requête linq finalement obtenu exécuté, mais la NHibernate session est fermé dans l'intérim à un certain point, alors, il a jeté une exception. La solution est de toujours s'assurer que nous appelons
.ToList()
dans le référentiel au sein de la session à l'aide de bloc avant de nous le retourner au service.Je vous suggère de définissez un point d'arrêt sur
SessionImpl.Close
/SessionImpl.Dispose
et de voir qui est de l'appeler via la trace de la pile. Vous pourriez tout aussi bien construire une version de débogage de NH pour vous-même et faire de même.