2013-08-19 2 views
3

Я использую Castle Windsor для моего IoC вместе с NHIbernate в приложении ASP.NET MVC. Он отлично работает на учете следующим образом (за одним исключением):Циклическая зависимость с замком Windsor IoC для 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 связанно 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, которая заботилась о plunking в IInterceptor, не вызывая эту проблему круговой зависимости (в отличие от этого использования в SessionFactoryBuilder, который использует функциональность UsingFactoryMethod Castle Виндзора).

Любые предложения по устранению этой циклической зависимости? За исключением того, что вы начинаете взламывать ISession для AccountSession с помощью некоторых других средств (например, вложения свойств, которые обходятся вокруг проблемы и пахнут в результате). Я переключил внедрение 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 (следовательно, оставляя место для автоматического создания безпараллельного публичного конструктора компилятора). Это стоит попробовать (IMHO) – jbl

+0

Вот что я сделал, и все работает отлично. Тем не менее, мне не нравится иметь этот неявный контракт против явного, особенно когда он используется в другом месте (хотя DI все обрабатывается контейнером, поэтому вам не нужно об этом думать). Это пахнет, потому что это циклическая ссылка, которую я чувствую, что я что-то пропускаю (хотя и не так грязно, как типичная циклическая ссылка). – Ted

+0

О, и спасибо за ваши отзывы об этом и предыдущем выпуске. Похоже, у вас такое же любопытство, как и у того, что будет лучшим/лучшим решением. Раньше я пробовал Facility Castle NHibernate, но он требует разметки [Транзакции], чтобы очистить и ввести заводскую фабрику и т. Д. Возможно, ответ будет состоять в том, чтобы вернуться к диспетчеру сеансов 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 - null). – Ted

+0

К сожалению, слишком рано, поскольку я ошибочно ссылался на _session вместо сеанса в моем перехватчике (и поэтому Func никогда не вызывался, поэтому сеанс был нулевым). Благодаря! – Ted

+0

Также удалено мое использование службы IAccountSession, чтобы все это работало, но я мог бы сделать это еще на один шаг, чтобы правильно ввести ISession в AccountSession почти так же. – Ted