Warum teilt Nhibernate die Sitzung über mehrere Anforderungen in meiner MVC-Anwendung hinweg?

Wir haben ein MVC-Projekt, das die NHibernate-Abhängigkeiten über StructureMap wie folgt erstellt

var sessionFactory = ConnectionRegistry.CreateSessionFactory<NHibernate.Context.WebSessionContext>();
For<ISessionFactory>().Singleton().Use(sessionFactory);
For<INHibernateSessionManager>().Singleton().Use<NHibernateWebSessionManager>();

Die ConnectionRegistry.CreateSessionFactory sieht folgendermaßen aus

public static ISessionFactory CreateSessionFactory<T>() where T : ICurrentSessionContext
        {
            if (_sessionFactory == null)
            {
                lock (_SyncLock)
                {
                    if (_sessionFactory == null)
                    {
                        var cfg = Fluently.Configure()
                            .Database(MsSqlConfiguration.MsSql2005.ConnectionString(DataFactory.ConnectionString))
                            .CurrentSessionContext<T>()
                            .Mappings(m => m.FluentMappings.AddFromAssemblyOf<IInstanceFactory>())
                            .ExposeConfiguration(c => c.SetProperty("generate_statistics", "true"))
                            .ExposeConfiguration(c => c.SetProperty("sql_exception_converter", typeof(SqlServerExceptionConverter).AssemblyQualifiedName));

                        try
                        {
                            _sessionFactory = cfg.BuildSessionFactory();
                        }
                        catch (Exception ex)
                        {
                            Debug.Write("Error loading Fluent Mappings: " + ex);
                            throw;
                        }
                    }
                }
            }

            return _sessionFactory;
        }

NHibernateWebSessionManager sieht so aus

public ISession Session
        {
            get
            {               
                return OpenSession();
            }
        }

public ISession OpenSession()
        {
            if(CurrentSessionContext.HasBind(SessionFactory))
            _currentSession = SessionFactory.GetCurrentSession();
            else
            {
                _currentSession = SessionFactory.OpenSession();
                CurrentSessionContext.Bind(_currentSession);
            }
            return _currentSession;
        }

        public void CloseSession()
        {
            if (_currentSession == null) return;
            if (!CurrentSessionContext.HasBind(SessionFactory)) return;
            _currentSession = CurrentSessionContext.Unbind(SessionFactory);
            _currentSession.Dispose();
            _currentSession = null;
        }

In Application_EndRequest machen wir das

ObjectFactory.GetInstance<INHibernateSessionManager>().CloseSession();
ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();

Unsere Controller sind persistenzunabhängig und erfordern Aktionen, um Modellanbieter oder Befehlsprozessoren abzufragen, denen der sessionManager hinzugefügt wurde, und um ihre eigenen Transaktionen zu verwalten.

Zum Beispiel:

public ActionResult EditDetails(SiteDetailsEditViewModel model)
{
    _commandProcessor.Process(new SiteEditCommand { //mappings }

    //redirect
}

Im CommandProcessor:

public void Process(SiteEditCommand command)
        {
            using (var tran = _session.BeginTransaction())
            {
                var site = _session.Get<DeliveryPoint>(command.Id);
                site.SiteName = command.Name;
                //more mappings
                tran.Commit();
            }
        }

Wir haben auch ein ActionFilter-Attribut, das den Zugriff auf jede Controller-Aktion protokolliert.

public void OnActionExecuted(ActionExecutedContext filterContext)
{
    SessionLogger.LogUserActionSummary(session, _userActionType);
}

Der SessionLogger verwaltet auch seine eigenen Transaktionen über einen injizierten SessionManager

public void LogUserActionSummary(int sessionId, string userActionTypeDescription)
        {

            using (var tx = _session.BeginTransaction())
            {
                //get activity summary
                _session.Save(userActivitySummary);
                tx.Commit();
            }
        }

All dies funktioniert einwandfrei, bis zwei Browser auf die App zugreifen. In diesem Szenario werden zeitweise Fehler ausgegeben, da die Sitzung (NHibernate) geschlossen ist. NHProfiler zeigt SQL-Anweisungen an, die aus beiden CommandProcessor-Methoden und SessionLogger-Methoden in beiden Browsersitzungen innerhalb derselben Transaktion erstellt wurden.

Wie kann dies im WebSessionContext-Bereich geschehen? Ich habe auch versucht, den Bereich des SessionManager über StructureMap auf HybridHttpOrThreadLocalScoped festzulegen.

Antworten auf die Frage(1)

Ihre Antwort auf die Frage