How to roll back an nHibernate transaction when an exception occurs during a request that has a Ninject for session management?

I am using nHibernate for ORM and Ninject for IoC. I create nHibernate sessions for each custom scope (which you can take as a request). I am starting an onActivation transaction. I am committing an onDeactivation transaction.

The problem is that if an exception occurs during the request, I want to cancel the transaction, not commit it. Any idea how to detect (in pure form, most likely using the Ninject Context) that an exception has occurred?

Note. I am not interested in exceptions that may occur during commit, which I can easily catch in the following code and role.

protected void BindWithSessionWrapper<T>(Func<IContext, T> creationFunc) where T : ISessionWrapper
{
    Bind<T>().ToMethod(creationFunc)
        .InScope(x => new NinjectCustomScope()) // work in progress !!!
        .OnActivation(t => t.Session.BeginTransaction(IsolationLevel.ReadCommitted))
        .OnDeactivation((c, t) => 
            { 
                t.Session.Transaction.Commit();
                t.Session.Dispose();
            });
}

Update:

I followed the @BatteryBackupUnit suggestion. Therefore, I added the following to the Error EventHandler:

    Error += (s, e) =>
        {
            HttpContext.Current.Items["ErrorRaised"] = true;
        };

OnDeactivation, :

OnDeactivation(t => 
                    { 
                        if ((bool?)HttpContext.Current.Items["ErrorRaised"] == true)
                            t.Session.Transaction.Rollback();
                        else
                            t.Session.Transaction.Commit();

                        t.Session.Dispose();
                    });

, , Ninject , , :)

+2
2

IHTTPModule Error?

Error System.Web.Mvc.DependencyResolver.Current.GetService(typeof (ISession)) .

, , , , , .

- , . .

, Error, HttpContext.Current.Items,

HttpContext.Current.Items["RollbackTransaction"] = true;

OnDeactivation , :

    .OnDeactivation((c, t) => 
        { 
            if(HttpContext.Current.Items.Contains("RollbackTransaction"])
            {
                t.Session.Transaction.Rollback();
            }
            else
            {
                t.Session.Transaction.Commit();
            }
            t.Session.Dispose();
        });

, HttpContext , , null -worst case - HttpContext.

, , . .

+1

HttpContext .

, , : , WebApi, , Ninject:

  • Ninject.Extension.Factory (https://www.nuget.org/packages/Ninject.Extensions.Factory/), ISession .
  • ISessionFactory ISession ( : nhibernate + unit of work + repository + + ninject), ISessionInRequestScopeFactory

    Bind<ISessionFactory>().ToProvider<NhibernateSessionFactoryProvider>().InSingletonScope();
    Bind<ISession>()
            .ToMethod(context => context.Kernel.Get<ISessionFactory>().OpenSession())
            .InRequestScope(); // notice that we don't need to call `BeginTransaction` at this moment 
    Bind<ISessionInRequestScopeFactory>().ToFactory(); // you don't need to make your implementation, the Ninject.Extension.Factory extension will help you so.
    
  • ISessionInRequestScopeFactory:

    public interface ISessionInRequestScopeFactory
    {
        ISession CreateSessionInRequestScope(); // return ISession in the request scope
    }
    
  • ninject, (<4 > ):

    Kernel.BindHttpFilter<ApiTransactionFilter>(System.Web.Http.Filters.FilterScope.Action)
        .WhenControllerHas<ApiTransactionAttribute>();
    
  • [ApiTransaction] :

     [ApiTransaction]
     public class YourApiController{ /* ... */}
    
  • , ApiTransactionFilter YourApiController, [ApiTransaction]

  • ApiTransactionFilter AbstractActionFilter factory ISessionInRequestScopeFactory :

    public class ApiTransactionFilter : AbstractActionFilter{
        private readonly ISessionInRequestScopeFactory factory;
    
        public ApiTransactionFilter(ISessionInRequestScopeFactory factory){
            this.factory = factory;
        }
    
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            ISession session = factory.CreateSessionInRequestScope(); // get the request scope session through factory
            session.BeginTransaction(); // session can begin transaction here ... 
            base.OnActionExecuting(actionContext);
        }
    
        public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
        {
            ISession session = factory.CreateSessionInRequestScope(); // get the request scope session through factory
            if (actionExecutedContext.Exception == null) // NO EXCEPTION!
            {
                session.Transaction.Commit();// session commit here ... may be you like to have try catch here
            }
            else
            {
               session.Transaction.Rollback(); // session rollback here ...
            }
    
            base.OnActionExecuted(actionExecutedContext);
        }
    } 
    
0

All Articles