2

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

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<ISession>().UsingFactoryMethod(k => k.Resolve<ISessionFactory>().OpenSession()).LifestylePerWebRequest()); 

However, I want to introduce an NHibernate IInterceptor in order to provide easy auditing. Typically I've used a NHibernate session manager in which it's easy to pass in an interceptor later on because SessionFactory.OpenSession(...) would typically be called in Begin_Request as opposed to "sort of" during component registration (which is in App_Start). Unfortunately, the LifestylePerWebRequest module can't be accessed at that point so for i.e., the following understandably fails:

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

What would be the best way to introduce an NHibernate Interceptor (which is usually inserted in SessionFactory.OpenSession(IInterceptor) when using this approach to NHibernate session management with Castle Windsor?

Ted
  • 7,122
  • 9
  • 50
  • 76
  • 1
    might be a (really) stupid comment, but wouldn't the execution be delayed to the right time if you move container.Resolve() inside the lambda, in place of the interceptor parameter of OpenSession ? – jbl Aug 19 '13 at 13:11
  • Well, why didn't I realize that!? Thanks. I did get it working by injecting my IInterceptor in my SessionBuilder and adding it my NHibernate config via Configuration.SetInterceptor(_interceptor); However, it's nice to plunk it where it usually goes via container.Register(Component.For().UsingFactoryMethod(k => k.Resolve().OpenSession(container.Resolve())).LifestylePerWebRequest()); Put yours in as an answer and I'll mark it as such. – Ted Aug 19 '13 at 15:15
  • I have run into another issue along the same lines however, which I should put as a separate question, but because my ChangeAuditInterceptor in turn uses a service that has a dependency on the NHibernate ISession (to get user information), I get cyclical dependency: – Ted Aug 19 '13 at 15:17
  • 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...AccountSession' resolved as dependency of component 'Blah.Core.Infrastructure.Data.ChangeAuditInfoInterceptor' resolved as dependency of component 'Blah...SessionFactoryBuilder' resolved as dependency of component 'Late bound NHibernate.ISessionFactory' resolved as dependency of...NHibernate.ISession' which is the root component being resolved. – Ted Aug 19 '13 at 15:19
  • You should post another question, adding the code of your Interceptor and all relevant code. This is an interesting issue. Would be interested in the answer This seems interesting, but I don't see exactly how it would be implemented : http://stackoverflow.com/q/7715702/1236044 – jbl Aug 19 '13 at 15:41
  • Thanks again for the response (I thought this would be a question that I would ask and then slap myself right before hitting submit as usually happens...but instead, it made it to you slapping my face for me ;-) Posted new question at http://stackoverflow.com/questions/18317900/cyclic-dependency-with-castle-windsor-ioc-for-nhibernate-isession. Thought of switching to property injection already for the service, but that just smells and then makes it unclear to any callers how to actually implement. – Ted Aug 19 '13 at 15:51

1 Answers1

0

As stated in the comments, you should put the code to instantiate your interceptor in the lambda. This way, the code would execute on the right time :

container.Register(Component.For<ISession>()
                            .UsingFactoryMethod(k => k.Resolve<ISessionFactory>()
                               .OpenSession(container.Resolve<IInterceptor>()))
                            .Lif‌​estylePerWebRequest()); 
jbl
  • 15,179
  • 3
  • 34
  • 101