0
votes

I'm using Castle Windsor 3.0 for dependency injection in a demo ASP.NET app. One of my controllers takes an ICustomerService instance, which in turn takes an ISession instance, all via constructor. The ISession is registered with Windsor using a factory method and PerWebRequest life style.

_container.Register(Component.For<ISessionFactory>().Instance(DbHelper.BuildSessionFactory()).LifestyleSingleton());
_container.Register(Component.For<ISession>().LifestylePerWebRequest().UsingFactoryMethod(x => x.Resolve<ISessionFactory>().OpenSession()));

In the global.asax file, I have an Application_EndRequest handler that attempts to commit the transaction:

protected void Application_EndRequest(object sender, EventArgs e) 
{
    if (!IsStaticResourceRequest())
    {
        var app = (HttpApplication)sender;
        var factory = _container.Resolve<ISessionFactory>();
        var session = ManagedWebSessionContext.Unbind(Context, factory);

        if (session != null && 
            session.Transaction != null && 
            session.Transaction.IsActive)
        {
            session.Transaction.Commit();
            session.Transaction.Dispose();
            session.Dispose();
        }                    
    }
}

The problem is that the PerWebRequest lifestyle of Windsor has its own Application_EndRequest event handler which disposes of the service prior to my Application_EndRequest handler (in global.asax) executing, so the code in my Application_EndRequest handler never gets a chance to commit the transaction. Is there a workaround for this?

2

2 Answers

0
votes

I moved away from this pattern and rather have the commit happen in your controller action. Why wait until you have left the page and at the end of the request before committing. Makes passing UI messages a lot more difficult. Currently I take in the ISession as a param in the controller to ensure it gets injected:

public void SomeController(ISession session)
{
  _session = session;
}

then in your Action:

using(var trans = new _session.BeginTransaction()){
   try{
   ..update etc
   trans.commit();
   }
   catch(Exception ex){
   trans.rollback();
   // return message, log etc
   }
}

Windsor will cleanup the session for you at the end of the request.

0
votes

The solution ended up being committing my transaction in an event earlier in the ASP.NET lifecycle. I picked ReleaseRequestState, but any of the methods leading up to the EndRequest event should be adequate, as long as the handler has finished processing the request.