Создание сеанса nhibernate для каждого веб-запроса с помощью Castle.Facility.AutoTx и Castle.Facility.NHibernate

Я использую Castle Windors, и это AutoTx и NHibernate Facility от haf. В конечном итоге я хочу воспользоваться преимуществами простоты использования атрибута Transaction, предоставляемого AutoTx. (Проект ASP.NET MVC 4).

Я использую Castle.Facilities.NHibernate.ISessionManager для управления своими сеансами PerWebRequest. Я установил Виндзорский Установщик так:

public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
        {
            container.AddFacility<AutoTxFacility>();
            container.Register(Component.For<INHibernateInstaller>().ImplementedBy<NHibernateInstaller>().LifeStyle.Singleton);            
            container.AddFacility<NHibernateFacility>(f => f.DefaultLifeStyle = DefaultSessionLifeStyleOption.SessionPerWebRequest);

            container.Install(FromAssembly.Containing<PersonRepository>());
        }

Я использую DefaultLifeStyle SessionPerWebRequest, который, как я ожидаю, сделает именно это, предоставит мне сеанс, который длится весь веб-запрос, так что все вызовы OpenSession в SessionManager внутри одного запроса используют один и тот же сеанс. Я проверяю это с помощью следующего кода:

public class HomeController : Controller
{        
    private readonly ISessionManager _sessionManager;

    public HomeController(ISessionManager sessionManager)
    {            
        _sessionManager = sessionManager;
    }

    public ActionResult Index()
    {
        using (var session1 = _sessionManager.OpenSession())
        {
            var person = session1.Get<Person>(1);
            using (var session2 = _sessionManager.OpenSession())
            {
                var person2 = session2.Get<Person>(1);
            }
        }

        return View();
    }        
}

и проверка журнала, чтобы увидеть идентификатор каждого созданного сеанса. Идентификатор всегда отличается. например

05/01/2013 11:27:39.109 DEBUG 9 NHibernate.Impl.SessionImpl - [session-id=c1ba248a-14ba-4468-a20c-d6114b7dac61] opened session at timestamp: 634929820591, for session factory: [/ea869bb12b4d4e51b9f431a4f9c9d9fa]
05/01/2013 11:30:36.383 DEBUG 9 NHibernate.Impl.SessionImpl - [session-id=72481180-625d-4085-98e9-929e3fd93e8a] opened session at timestamp: 634929822363, for session factory: [/ea869bb12b4d4e51b9f431a4f9c9d9fa]

Стоит отметить, что я ничего не добавил в web.config в качестве обработчиков. Нужно ли мне? (Я не видел никакой документации, предлагающей это в вики-сайте NHib Facility) Мои ожидания, что одна и та же сессия всегда будет возвращаться неверно.

Я просмотрел исходный код объекта и не понимаю, как создается экземпляр сеанса на веб-запрос и как многократные вызовы OpenSession приводят к одному и тому же сеансу в одном и том же веб-запросе.

Ниже описано, как SessionManager зарегистрирован в Windsor:

Component.For<ISessionManager>().Instance(new SessionManager(() =>
                    {
                        var factory = Kernel.Resolve<ISessionFactory>(x.Instance.SessionFactoryKey);
                        var s = x.Instance.Interceptor.Do(y => factory.OpenSession(y)).OrDefault(factory.OpenSession());
                        s.FlushMode = flushMode;
                        return s;
                    }))
                        .Named(x.Instance.SessionFactoryKey + SessionManagerSuffix)
                        .LifeStyle.Singleton

ISession зарегистрирован в Windsor с использованием следующего

private IRegistration RegisterSession(Data x, uint index)
{
    Contract.Requires(index < 3,
                      "there are only three supported lifestyles; per transaction, per web request and transient");
    Contract.Requires(x != null);
    Contract.Ensures(Contract.Result<IRegistration>() != null);

    return GetLifeStyle(
        Component.For<ISession>()
            .UsingFactoryMethod((k, c) =>
            {
                var factory = k.Resolve<ISessionFactory>(x.Instance.SessionFactoryKey);
                var s = x.Instance.Interceptor.Do(y => factory.OpenSession(y)).OrDefault(factory.OpenSession());
                s.FlushMode = flushMode;
                logger.DebugFormat("resolved session component named '{0}'", c.Handler.ComponentModel.Name);
                return s;
            }), index, x.Instance.SessionFactoryKey);
}

private ComponentRegistration<T> GetLifeStyle<T>(ComponentRegistration<T> registration, uint index, string baseName)
            where T : class
{
    Contract.Requires(index < 3,
                      "there are only three supported lifestyles; per transaction, per web request and transient");
    Contract.Ensures(Contract.Result<ComponentRegistration<T>>() != null);

    switch (defaultLifeStyle)
    {
        case DefaultSessionLifeStyleOption.SessionPerTransaction:
            if (index == 0)
                return registration.Named(baseName + SessionPerTxSuffix).LifeStyle.PerTopTransaction();
            if (index == 1)
                return registration.Named(baseName + SessionPWRSuffix).LifeStyle.PerWebRequest;
            if (index == 2)
                return registration.Named(baseName + SessionTransientSuffix).LifeStyle.Transient;
            goto default;
        case DefaultSessionLifeStyleOption.SessionPerWebRequest:
            if (index == 0)
                return registration.Named(baseName + SessionPWRSuffix).LifeStyle.PerWebRequest;
            if (index == 1)
                return registration.Named(baseName + SessionPerTxSuffix).LifeStyle.PerTopTransaction();
            if (index == 2)
                return registration.Named(baseName + SessionTransientSuffix).LifeStyle.Transient;
            goto default;
        case DefaultSessionLifeStyleOption.SessionTransient:
            if (index == 0)
                return registration.Named(baseName + SessionTransientSuffix).LifeStyle.Transient;
            if (index == 1)
                return registration.Named(baseName + SessionPerTxSuffix).LifeStyle.PerTopTransaction();
            if (index == 2)
                return registration.Named(baseName + SessionPWRSuffix).LifeStyle.PerWebRequest;
            goto default;
        default:
            throw new FacilityException("invalid index passed to GetLifeStyle<T> - please file a bug report");
    }
}

который регистрирует ISession как PerWebRequest, но я не вижу нигде в коде, где эта именованная регистрация извлекается, когда требуется сеанс?

Любая помощь в том, что мне нужно сделать, чтобы получить сеанс для каждого веб-запроса, приветствуется.

ОБНОВЛЕНИЕ Я решил просто заменить функцию кода, передаваемую в конструктор SessionManager, кодом, который захватывает ISession из контейнера, а не использует фабрику. Прекрасно работает для того, что я хочу, включая завершение транзакций и открытие только одного сеанса на веб-запрос, или переходный процесс и т. Д.

Component.For<ISessionManager>().Instance(new SessionManager(() =>
{
    var s = Kernel.Resolve<ISession>();
    s.FlushMode = flushMode;
    return s;
}))
//Component.For<ISessionManager>().Instance(new SessionManager(() =>
//{
//    var factory = Kernel.Resolve<ISessionFactory>(x.Instance.SessionFactoryKey);
//    var s = x.Instance.Interceptor.Do(y => factory.OpenSession(y)).OrDefault(factory.OpenSession());
//    s.FlushMode = flushMode;
//    return s;
//}))
    .Named(x.Instance.SessionFactoryKey + SessionManagerSuffix)
    .LifeStyle.Singleton

Kernel.Resolve () Я ожидаю, будет захватить первый зарегистрированный сервис в контейнере. Это будет то, что я установил для образа жизни.

0 ответов

Другие вопросы по тегам