NHibernate ISession 与 Castle Windsor IoC 的循环依赖

Posted

技术标签:

【中文标题】NHibernate ISession 与 Castle Windsor IoC 的循环依赖【英文标题】:Cyclic dependency with Castle Windsor IoC for NHibernate ISession 【发布时间】:2013-08-21 11:48:18 【问题描述】:

我在 ASP.NET MVC 应用程序中将 Castle Windsor 与 NHIbernate 一起用于我的 IoC。注册后效果很好(有一个例外):

container.Register(Component.For<ISessionFactoryBuilder.().ImplementedBy<SessionFactoryBuilder>().LifestyleSingleton());

// Register the NHibernate session factory as a singleton using custom SessionFactoryBuilder.BuildSessionFactory method.
container.Register(Component.For<ISessionFactory>().UsingFactoryMethod(k => k.Resolve<ISessionFactoryBuilder>().BuildSessionFactory("ApplicationServices")).LifestyleSingleton());

container.Register(Component.For<IInterceptor>().ImplementedBy<ChangeAuditInfoInterceptor>().LifestylePerWebRequest());
container.Register(Component.For<ISession>().UsingFactoryMethod(k => k.Resolve<ISessionFactory>()
            .OpenSession(container.Resolve<IInterceptor>())).LifestylePerWebRequest()); 

一切都很好,除了我的 ChangeAuditInterceptor 又注入了一个 IAccountSession 服务,该服务又注入了一个 NHibernate ISession...这导致以下循环依赖异常:

在尝试解析组件时检测到依赖循环 '后期绑定 NHibernate.ISession'。导致的解析树 周期如下:组件'后期绑定NHibernate.ISession' 解析为组件的依赖 'Blah.Core.Services.AccountSession' 解析为依赖 组件'Blah.Core.Infrastructure.Data.ChangeAuditInfoInterceptor' 解析为组件的依赖 'Blah.Core.Infrastructure.Installers.SessionFactoryBuilder' 已解决 作为组件“后期绑定 NHibernate.ISessionFactory”的依赖项 解析为组件“后期绑定 NHibernate.ISession”的依赖项 这是正在解析的根组件。

在过去的几年里,我通常使用 NHibernateSessionManager 运行,它负责插入 IInterceptor 而不会导致这种循环依赖问题(与使用 Castle Windsor 的 UsingFactoryMethod 功能的 SessionFactoryBuilder 的用法相反)。

关于如何解决这种循环依赖的任何建议?没有开始通过其他方式(即绕过问题并因此产生气味的属性注入)来破解 AccountSession 的 ISession。我已将 ISession 注入切换为 AccountSession 服务的属性注入,它工作正常,但我不喜欢隐式契约与构造函数显式契约。

public class AccountSession : IAccountSession

    private readonly ISession _session;

    public AccountSession(ISession session)
    
        _session = session;
    

    public Account GetCurrentAccount() // Called by a method in ChangeAuditInterceptor
    
...
    

...等等。

【问题讨论】:

我想你应该尝试将 _session 转换为公共自动属性(get;set;)并删除 AccountSession 的构造函数(因此为编译器自动生成的无参数公共构造函数留出位置) .值得一试(恕我直言) 这就是我所做的,它工作正常。但是,我不喜欢需要隐式契约和显式契约,尤其是在其他地方使用它时(尽管 DI 仍然由容器处理,所以你不必考虑它)。它闻起来很臭,因为它是一个周期性参考,我觉得我错过了一些东西(尽管不像典型的周期性参考那么脏)。 哦,感谢您对本期和上期的反馈。听起来你和我一样好奇什么是更好/最好的解决方案。我之前尝试过 Castle NHibernate Facility,但它需要 [Transaction] 标记来刷新和注入工厂等。也许答案是回到一个 NHibernate 会话管理器,它将被注入到任何地方(并且可以处理 IInterceptor注射本身)。多年来,我一直在使用 Ninject,最近转而尝试使用 Castle 和 Autofac。 【参考方案1】:

尝试在你的拦截器类中添加对 Func 的依赖

public class CustomInterceptor : EmptyInterceptor

    private readonly Func<ISession> sessionFunc;
    private ISession session;

    protected ISession Session
    
        get
        
            return session ?? (session = sessionFunc());
        
    

    public CustomInterceptor(Func<ISession> sessionFunc)
    
        this.sessionFunc = sessionFunc;
    

及注册:

container.Register(Component.For<ISession>().
    LifestylePerWebRequest()
    .UsingFactoryMethod(container =>
    
        var interceptor = container.Resolve<IInterceptor>();
        return container.Resolve<ISessionFactory>.OpenSession(interceptor);
    ));
container.Register(Component.For<Func<ISession>>()
    .LifestylePerWebRequest()
    .UsingFactoryMethod(container =>
    
        Func<ISession> func = container.Resolve<ISession>;
        return func;
    ));

【讨论】:

感谢您的建议!但是,虽然这解决了循环引用并在第一次调用时工作,但后续调用中的 ISession 失败并出现空引用(ISession 为空)。 糟糕,说得太快了,因为我在拦截器中错误地引用了 _session 而不是 Session(因此从未调用过 Func,因此会话为空)。谢谢! 还删除了我对 IAccountSession 服务的使用以使其全部正常工作,但我可以更进一步,以便以几乎相同的方式将 ISession 正确注入 AccountSession。 果然,只需要通过与上面Func相同的方法来解析IAccountSession(ISession被注入)。 Func 就是现在我的 ChangeAuditInfoInterceptor 是原来的样子,但是我的 AccountSession 现在已被覆盖并且不会导致循环引用。谢谢! 做到这一点:将 IAccountSession 注入 ChangeAuditInfoInterceptor,就像 ISession 注入如上所示。

以上是关于NHibernate ISession 与 Castle Windsor IoC 的循环依赖的主要内容,如果未能解决你的问题,请参考以下文章

NHibernate ISession Flush:何时何地使用它,为啥?

使用 Moq 模拟 NHibernate ISession

NHibernate Isession管理

如何让 NHibernate ISession 缓存主键未检索到的实体

会话已关闭对象名称:'ISession'。在 NHibernate.Impl.AbstractSessionImpl.ErrorIfClosed() - 如何阻止会话过早关闭

Nhibernate in asp,net ISession 帮助