2013-08-19 36 views
3

我在ASP.NET MVC应用程序中使用Castle Windsor作为我的IoC和NHIbernate。它的伟大工程注册(有一个例外)如下:与Castle Windsor IoC for NHibernate的循环依赖关系ISession

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的注入......这导致了下列好循环依赖异常:

尝试解析组件 'Late bound NHibernate.ISession'时检测到依赖关系周期。导致 周期的解析树如下:组件'Late bound NHibernate.ISession' 解析为依赖于组件 'Blah.Core.Services.AccountSession'作为依赖于 组件的'Blah.Core.Infrastructure'解析。 Data.ChangeAuditInfoInterceptor” 解决作为组分 的依赖性‘Blah.Core.Infrastructure.Installers.SessionFactoryBuilder’解决 作为组分的依赖性‘后期绑定NHibernate.ISessionFactory’ 解析为的组分依赖性‘后期绑定NHibernate.ISession’ ,其是正在解决的根组件。

在过去的几年中,我通常与NHibernateSessionManager它照顾了在IInterceptor plunking而不引起这个循环依赖问题(相对于这种用法,它使用温莎城堡的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 
    { 
... 
    } 

...等等。

+0

我想你应该给一个尝试转变_session到一个公共的自动属性(get; set;)并删除AccountSession的构造函数(因此留给编译器自动生成的无参数公共构造函数)。值得一试(恕我直言) – jbl

+0

这就是我所做的,它工作得很好。但是,我不喜欢需要隐式契约与显式契约,特别是在其他地方使用它(尽管DI都由容器处理,因此您不必考虑它)。它闻起来是因为这是一个周期性的参考,我觉得我错过了一些东西(尽管不像典型的循环参考那样脏)。 – Ted

+0

哦,并感谢您对此和上一期的反馈。这听起来像你和我一样对好的/最好的解决方案有同样的好奇心。我之前已经尝试了Castle NHibernate Facility,但它需要[Transaction]标记来刷新和注入工厂等。也许答案是要返回NHibernate会话管理器,它将被注入到处(而且可以处理IInterceptor注射本身)。多年来,我使用Ninject,最近更换了Castle和Autofac。 – Ted

回答

4

尝试添加依赖于Func键<的Isession>在你的拦截器类

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; 
    })); 
+0

感谢您的建议!然而,虽然这解决了循环引用并且在第一次调用时工作,但后续调用中的ISession失败并返回空引用(ISession为空)。 – Ted

+0

糟糕,因为我错误地在我的拦截器中引用了_session而不是Session,并且因此Func从未被唤起,所以会话为空。谢谢! – Ted

+0

也删除了我使用IAccountSession服务以使其全部正常工作,但我可以更进一步,以便以相同的方式将ISession正确注入到AccountSession中。 – Ted