I currently get my session from the globalasax as follows…
public class MvcApplication : HttpApplication
{
public static readonly ISessionFactory SessionFactory = NHibernateHelper.CreateSessionFactory();
public MvcApplication()
{
BeginRequest += delegate
{
if (!HttpContext.Current.Request.Url.AbsolutePath.StartsWith("/_cassette/"))
{
CurrentSession = SessionFactory.OpenSession();
CurrentSession.FlushMode = FlushMode.Auto;
}
};
EndRequest += delegate
{
if (CurrentSession != null)
{
CurrentSession.Flush();
CurrentSession.Dispose();
}
};
}
public static ISession CurrentSession
{
get { return (ISession) HttpContext.Current.Items["current.session"]; }
set { HttpContext.Current.Items["current.session"] = value; }
I was looking at the Sharp Architecture Transaction attribute and a similar one http://weblogs.asp.net/srkirkland/archive/2009/09/03/asp-net-mvc-transaction-attribute-using-nhibernate.aspx but whats the best way of handling sessions in an MVC4 project to make use of none-implicit transactions ala http://nhprof.com/Learn/Alerts/DoNotUseImplicitTransactions
I can easily wrap everything by adding the transaction/commit to the begin request/end request but the attribute method seems cleaner (actually handles errors); or should I be using a filter now?
What is the best practice for MVC4 with NHibernate?
Your current session handling has one serious problem (been there done that ;)). CurrentSession is static and hence it is shared among all concurrent requests. NHibernate’s ISession is NOT thread safe (unlike ISessionFactory which IS thread safe).
NHibernate offers session contextes into which the session can be bound and after which the bound session can be acquired from session factory (.GetCurrentSession() -method). To be able to use CurrentSessionContext like in the next example you need to tell NHibernate which session context to use. For web applications WebSessionContext is good choice.
When I’m using MVC I write an action filter which takes care of the session handling. Here is an example (written for MVC 2):
It shouldn’t be too much of a problem to add transaction management also into the same filter. In OnActionExecuting-method you could open transaction with ISession’s .BeginTransaction() and in OnActionExecuted you get the current transaction from ISession’s Transaction-property which can then be committed and disposed.