使用Castle.Facility.AutoTx和Castle.Facility.NHibernate为每个Web请求创建一个nhibernate会话

时间:2013-01-05 01:56:03

标签: fluent-nhibernate castle-windsor windsor-nhfacility

我正在使用Castle Windors,它是AutoTxNHibernate Facility by haf。最终,我希望AutoTx提供易用的Transaction属性。 (ASP.NET MVC 4项目)。

我使用Castle.Facilities.NHibernate.ISessionManager来管理我的PerWebRequest会话。我已经设置了Windsor安装程序:

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>());
        }

我正在使用SessionPerWebRequest的DefaultLifeStyle,我希望它能完全实现,为我提供一个持续整个Web请求的会话,这样在同一请求中对SessionManager的OpenSession的所有调用都使用相同的会话。我正在使用以下代码对其进行测试:

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();
    }        
}

并检查日志以查看每个已创建会话的ID。 id总是不同的。例如

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 Wiki中看到任何证明这一点的文件)我的期望是同一个会话总是不正确。

我已经查看了该工具的源代码,并且不了解每个Web请求的会话是如何实例化的,以及对OpenSession的多次调用将如何导致同一Web请求中的同一会话。

以下是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

使用以下

在Windsor注册了ISession
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");
    }
}

将Iession注册为PerWebRequest,但是在代码中的任何地方都无法看到需要会话时提取命名注册的地方?

对于我需要做的任何帮助,我们都非常感谢每个网络请求的会话。

更新我决定只使用从容器中获取ISession的代码替换传递给SessionManager构造函数的代码函数,而不是使用工厂。完全符合我的要求,包括在事务中包装,每个Web请求只打开一个会话,或瞬态等。

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 个答案:

没有答案