nhibernatecastle-windsorisession

Cyclic dependency with Castle Windsor IoC for NHibernate ISession


I am using Castle Windsor for my IoC along with NHIbernate in an ASP.NET MVC app. It works great registered as follows (with one exception):

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

All is good except that for my ChangeAuditInterceptor in turn has an IAccountSession service injected which in turn has an NHibernate ISession injected...which leads to the following circular dependency exception:

Dependency cycle has been detected when trying to resolve component 'Late bound NHibernate.ISession'. The resolution tree that resulted in the cycle is the following: Component 'Late bound NHibernate.ISession' resolved as dependency of component 'Blah.Core.Services.AccountSession' resolved as dependency of component 'Blah.Core.Infrastructure.Data.ChangeAuditInfoInterceptor' resolved as dependency of component 'Blah.Core.Infrastructure.Installers.SessionFactoryBuilder' resolved as dependency of component 'Late bound NHibernate.ISessionFactory' resolved as dependency of component 'Late bound NHibernate.ISession' which is the root component being resolved.

For the past couple years I've usually run with an NHibernateSessionManager which took care of plunking in the IInterceptor without causing this circular dependency issue (as opposed to this usage of a SessionFactoryBuilder which uses Castle Windsor's UsingFactoryMethod functionality).

Any suggestions for how to resolve this circular dependency? Short of starting to hack in the ISession for the AccountSession via some other means (i.e. property injection which skirts around the issue and smells as a result). I've switched the ISession injection to property injection for the AccountSession service and it works fine, but I don't like the implicit contract vs. the constructor explicit contract.

public class AccountSession : IAccountSession
{
    private readonly ISession _session;

    public AccountSession(ISession session)
    {
        _session = session;
    }

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

...etc.


Solution

  • Try to add a dependency on Func< ISession > in your interceptor class

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

    And registration:

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