Search code examples
asp.net-mvcnhibernatehttpcontext

HttpContext in MVC Attributes - threading issues?


I had my NHibernate session management setup like follows:

    protected MvcApplication()
    {
        BeginRequest += delegate
                            {
                                NHibernateSessionManager.Instance.OpenSession();
                             };
        EndRequest += delegate
                            {

                                NHibernateSessionManager.Instance.CloseSession();
                            };
    }

And for when I needed to save to the database, I made an ActionFilterAttribute that looked like this:

public class TransactionAttribute: ActionFilterAttribute { private ITransaction _currentTransaction;

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        _currentTransaction = NHibernateSessionManager.Instance.CurrentSession.Transaction;
        _currentTransaction.Begin();
    }


    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (_currentTransaction.IsActive)
        {
            if (filterContext.Exception == null)
                _currentTransaction.Commit();
            else
            {
                _currentTransaction.Rollback();
            }
        }
        _currentTransaction.Dispose();
    }
}

and then I could just add [Transaction] to my action method. This seemed to work in initial testing, but I then I tried using at HttpWebRequest to call an action method from another app multiple times and I had issues. Testing with Fiddler I setup a POST request and then fired them off in quick succession and it showed up the following: WebRequests

THe red ones are various errors that I believe is to do with threading.

My NHibernateSessionManager uses the HTtpContext to store the session like this:

    public ISession CurrentSession
    {
        get { return (ISession)HttpContext.Current.Items["current.session"]; }
        set { HttpContext.Current.Items["current.session"] = value; }
    }

So, to fixed it, I moved my Transaction code into my BeginRequest and EndRequest methods - and then I could fire off heaps in succession.

My question is - why did this fix it? I would have thought that I would have had something similar to this: Begin Request - opens session OnActionExecuting - starts transaction action code OnActionExecuted - commits transaction End Request - closes session

and that this would be unique to each request, so it shouldn't interfere with one another, because there should be a different HttpContext for each request shouldn't there? Or are they shared or something??

Can someone enlighten me?


Solution

  • Quote from the release notes of ASP.NET MVC 3:

    In previous versions of ASP.NET MVC, action filters were created per request except in a few cases. This behavior was never a guaranteed behavior but merely an implementation detail and the contract for filters was to consider them stateless. In ASP.NET MVC 3, filters are cached more aggressively. Therefore, any custom action filters which improperly store instance state might be broken.

    This basically means that the _currentTransaction instance you have in your action filter might not be what you think it is. So be careful how/when is this property injected => it is not clear from the code you have shown.