Управление NHibernate ISession с помощью Autofac

Есть ли у кого-нибудь советы или рекомендации относительно того, как Autofac может помочь управлять экземпляром ISIBernate ISession (в случае приложения ASP.NET MVC)?

Ответы

Ответ 1

Я не слишком разбираюсь в том, как следует обрабатывать сеансы NHibernate. Тем не менее, Autofac имеет отличную обработку жизненного цикла экземпляров (scoping и детерминированное удаление). Некоторые связанные ресурсы эта статья и этот вопрос. Поскольку вы находитесь в среде ASP.Net MVC, убедитесь, что вы также смотрите в материал для интеграции MVC.

Чтобы проиллюстрировать эту точку, здесь приведено краткое описание того, как вы можете использовать делегаты Autofac factory и Owned generic, чтобы получить полный контроль над временем жизни экземпляра:

public class SomeController
{
    private readonly Func<Owned<ISession>> _sessionFactory;

    public SomeController(Func<Owned<ISession>> sessionFactory)
    {
        _sessionFactory = sessionFactory;
    }

    public void DoSomeWork()
    {
        using (var session = _sessionFactory())
        {
             var transaction = session.Value.BeginTransaction();
             ....   
        }
    }
}

Настройка контейнера, чтобы заставить это работать, довольно проста. Обратите внимание, что нам не нужно ничего делать, чтобы получить типы Func<> и Owned<>, они автоматически становятся доступны Autofac:

builder.Register(c => cfg.BuildSessionFactory())
    .As<ISessionFactory>()
    .SingleInstance();
builder.Register(c => c.Resolve<ISessionFactory>().OpenSession());

Обновление:. Мое рассуждение заключается в том, что согласно этот учебник NHibernate, время жизни экземпляра сеанса должен быть "единицы работы". Таким образом, нам нужен какой-то способ управления как при создании экземпляра сеанса, так и при размещении сеанса.

С Autofac мы получим этот элемент управления, запросив вместо Func<> вместо типа. Не используя Func<>, требуется, чтобы экземпляр сеанса был создан заранее до создания экземпляра контроллера.

Далее, по умолчанию в Autofac указано, что экземпляры имеют срок службы своего контейнера. Поскольку мы знаем, что нам нужна возможность утилизировать этот экземпляр, как только будет завершена часть работы, мы запрашиваем экземпляр Owned. Утилизация принадлежащего экземпляру в этом случае немедленно удалит основной сеанс.

Ответ 2

Edit: Звучит как Autofac, и, возможно, другие контейнеры могут масштабировать время жизни правильно. Если это произойдет, идите на это.

Не рекомендуется использовать ваш контейнер IoC для управления сеансами напрямую. Срок действия вашей сессии должен соответствовать вашей единице работы (граница транзакции). В случае веб-приложения это почти наверняка будет временем жизни веб-запроса.

Наиболее распространенный способ достижения этого - с HttpModule, который создает ваш сеанс и запускает транзакцию при начале запроса, а затем фиксирует, когда запрос завершен. Я хотел бы, чтобы HttpModule зарегистрировал сеанс в коллекции HttpContext.Items.

В вашем контейнере IoC вы можете зарегистрировать что-то вроде HttpContextSessionLocator для ISessionLocator.

Я должен упомянуть, что ваша общая обработка ошибок должна находить текущий сеанс и автоматически откатывать транзакцию, или вы можете завершить половину единицы работы.