Стратегия управления сессиями Nhibernate для веб-приложений с фоновыми рабочими? - PullRequest
5 голосов
/ 02 мая 2011

Для веб-приложения хорошим способом обработки сеанса является использование параметра <property name="current_session_context_class">managed_web</property>, вызов CurrentSessionContext.Bind/Unbind в Begin / EndRequest.Тогда я могу просто использовать sessionFactory.GetCurrentSession() в классе репозитория.

Это прекрасно работает для всех запросов страниц.Но у меня есть фоновые работники, которые делают вещи и используют те же классы репозитория, чтобы делать вещи.Они не выполняются в рамках веб-запроса, поэтому обработка сеанса не будет работать.

Есть предложения о том, как это можно решить?

Ответы [ 3 ]

15 голосов
/ 03 мая 2011

Я решил это, создав собственный класс контекста сеанса:

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;
        }
    }
}
2 голосов
/ 03 мая 2011

Мне показалось, что в этом сценарии проще всего самостоятельно обрабатывать создание сеанса с использованием библиотеки DI и «гибридной» области (в StructureMap это определяется как InstanceScope.Hybrid).Это будет охватывать экземпляры с помощью HttpContext в домене приложения ASP.net и ThreadStatic в обычном домене приложения, что позволяет использовать один и тот же подход в обоих случаях.

Я уверен, что другие библиотеки DI предлагают аналогичную функцию.

0 голосов
/ 02 мая 2011

В моем проекте я написал небольшой класс-оболочку для CurrentSessionContext.
Возможно, вы сможете расширить его в соответствии со своими потребностями.
Я думаю, что вам просто нужно настроить реализацию BindSessionToRequest и 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();
        }
    }
...