整个请求持续时间的显式事务,错误时自动提交/回滚(EF6、Web API2、NInject)



我正在启动一个新的Web API应用程序,但我不确定如何处理事务(以及在异常情况下的后续回滚(。

我的总体目标是为每个请求提供一个数据库连接,并将整个事情包装在一个显式事务中。我将需要一个显式事务,因为我也将执行存储过程,并且如果我的应用程序引发任何异常,则需要回滚这些过程的任何结果。

我的计划是重用我过去在 MVC 应用程序中使用的一种方法,粗略地说,它只是使用 ninject 将我的数据库上下文绑定到 requestscope,然后在 ondeactivation 事件中处理回滚/提交。

假设我有一个具有两种方法的控制器。

public class MyController : ApiController {
  public MyController(IRepo repo) {
  }
  }

  public string SimpleAddElement() {
    _repo.Add(new MyModel());
  }
  public string ThisCouldBlowUp() {
    // read from context
    var foo = _repo.ReadFromDB();
    // execute stored prodecure which changes some content
    var res = _repo.StoredProcOperation(); 
    // throw an exception due to bug/failsafe condition
    if (res == 42)
      throw Exception("Argh, an error occured");
  }
}

我的回购骨架

public class Repo : IRepo {
  public Repo(IMyDbContext context) {
  }
}

从这里开始,我的计划是简单地使用

kernel.Bind<IRepo>().To<Repo>();

并为每个请求提供单个数据库上下文

kernel.bind<IMyDbContext>().To<CreateCtx>()
      .InRequestScope()
      .OnDeactivate(FinalizeTransaction);
private IMyDbContext CreateCtx(IMyDbContext ctx) {
  var ctx = new DbContext();
  ctx.Database.BeginTransaction();
}
private void FinalizeTransaction(IMyDbContext ctx) {  
  if (true /* no errors logged on current HttpRequest.AllErrors */)
    ctx.Commit();
  else
    ctx.Rollback();    
}

现在,如果我从浏览器中调用 SimpleAddElement,FinalizeTransaction 永远不会被调用......所以要么我突然做错了什么,要么错过了与 WebAPI 管道相关的内容

那么我应该如何实现事务性"每个请求单个数据库会话"模块呢?什么是最佳实践?如果可能的话,我希望解决方案也支持 ASP vNext

我想一个潜在的解决方案可以放弃"ondeactivation"处理程序并实现一个 HTTP 模块,该模块将在 Endrequest 中提交并在错误中回滚......但

有些东西我不喜欢。

代码中缺少抽象。您在控制器中执行业务逻辑,这是错误的位置。如果将此逻辑提取到业务层并将其隐藏在抽象后面,则将所有业务层操作包装在事务中将变得微不足道。看看这篇文章,了解这方面的一些例子。

最新更新