NHibernate session management and WCF, redux

It’s been nearly a year since I published my method for getting one NHibernate session per WCF operation using Castle’s NHibernate Facility and AutoTx AOP Facility — a method I developed for an application which was having serious session management issues (it was using one session per SQL statement). However, today I ripped it all out.

The method itself still works. There’s nothing wrong with it. As long as you’re only doing one session per WCF operation (or one session per ASP.NET MVC request for that matter), it works great. However, problems arise when you mix other session styles.

For example, our application has a series of long-running background threads for processing jobs on a queue (up to an hour each) — as well as synchronous WCF operations — all requiring NHibernate. In this case, the one-size-fits-all approach using AOP and the container simply couldn’t give us the control we needed over each session’s lifetime, so we removed the Facility from our Windsor container, and instead now do:

  • Register the ISessionFactory in the container, singleton scoped.
  • Inject ISessionFactory and call ISessionFactory.OpenSession(), ISession.BeginTransaction() and ITransaction.Commit() at outer boundaries of your application (e.g. WCF service implementations), and background jobs executing outside the context of a WCF operation.
  • Pass ISession down through your application as a parameter into any methods that access the database. Callees must not hold any reference to it, or try to manage its lifestyle (e.g. closing it, opening their own transactions etc).

(Note: all NHibernate calls are wrapped in a transaction and committed. Even if they are only SELECT statements, it’s still a good practice.)

It has more-or-less the same end effect as AutoTx facility and CallContext-scoped SessionManager, but with the added control of being able to explicitly manage session lifetimes in other situations. It’s a few more lines of code, but it’s also a good example of stop trying to hide your ORM, and just embrace the ISession directly. And a reminder that technical solutions are never infallible, no matter how elegant they might seem.

April 22, 2011


Berke Sökhan on May 23, 2011 at 6:44 pm.

…”Pass ISession down through your application as a parameter into any methods that access the database.”

So you went backwards in technology, how very wise :)

Richard on May 23, 2011 at 8:39 pm.

@Berke: and upwards in control, yes.

Henrik on November 28, 2011 at 3:10 pm.

I’m not so sure I agree that you can’t use my facility (Castle.Facilities.NHibernate) for this; for background processing we have [Transaction(Fork=true)] which gives you a session-per-forked-thread, there the called method is called within a transaction and the ISession scoped to that transaction.

That would solve the background-processing requirement.

In terms of lazily loaded entities; pre-load everything through fetching strategies and you won’t need a lazy open session.

For your “top transaction” approach, I’ve created the life-style called exactly that; “PerTopTransaction” in the Registration namespace of AutoTx. This is the default lifestyle.

Also, in fact, you may dispose the ISession as much as you want, it won’t *actually* be disposed until the end of the transaction anyway.

In the case you need more control over your session lifestyle at some point in the application, you can either depend on Func<ISession> or ISessionManager and have that create your ISession.

Furthermore, if you need to open a lazy, transient session, then you can depend on the ISession with the key "MySessionFactoryKey" + NHibernateFacility.SessionTransientSuffix

For more details, you can browse the source code:

And of course e-mail me at any time, you have my e-mail. I’m happy to help and it would be interesting to see a use-case that isn’t covered by my facility. In that case, I’d be happy to add that use-case to it. You can describe issues you find on the issues page of my github (https://github.com/haf).


Leave a Reply