2
votes

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?

1
might be a (really) stupid comment, but wouldn't the execution be delayed to the right time if you move container.Resolve<IInterceptor>() inside the lambda, in place of the interceptor parameter of OpenSession ?jbl
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<ISession>().UsingFactoryMethod(k => k.Resolve<ISessionFactory>().OpenSession(container.Resolve<IInterceptor>())).LifestylePerWebRequest()); Put yours in as an answer and I'll mark it as such.Ted
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
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
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 : stackoverflow.com/q/7715702/1236044jbl

1 Answers

0
votes

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