2013-08-19 72 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