在 WebAPI 中为异步操作中的 TransactionScope 使用自定义 IHttpActionInvoker

Using Custom IHttpActionInvoker in WebAPI for TransactionScope in Async actions

我想为每个异步控制器操作应用 TransactionScope。我不想在每个动作中都这样做,而是想在一个中心位置进行,以便它适用于所有动作。我尝试创建一个继承自 ApiControllerActionInvoker

的自定义 IHttpActionInvoker
public class ControllerActionTransactionInvoker : ApiControllerActionInvoker
{
    public override Task<HttpResponseMessage> InvokeActionAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
    {

        using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
        {
            Task<HttpResponseMessage> result;

            result = base.InvokeActionAsync(actionContext, cancellationToken);

            scope.Complete();

            return result;
        }

    }
}

然后在 Web Api 的启动 class 中用新创建的

替换默认的 IHttpActionInvoker
config.Services.Replace(typeof(IHttpActionInvoker), new ControllerActionTransactionInvoker());

现在,我可以调用控制器操作并获得结果,但我手动引发了一系列 Db 操作的异常,并且所需的事务处理不起作用。所以在数据库中完成了部分工作。 在 Azure api 应用程序中托管 api 后,它根本不起作用。它说找不到控制器操作。

如何解决?

您的 scope 正在完成并在控制器操作完成执行之前被处置,因为您没有等待响应。试试这样:

public class ControllerActionTransactionInvoker : ApiControllerActionInvoker
{
    public override async Task<HttpResponseMessage> InvokeActionAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
    {
        using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
        {
            HttpResponseMessage result = await base.InvokeActionAsync(actionContext, cancellationToken);
            scope.Complete();
            return result;
        }
    }
}

虽然这可能很有效,但您可能还想考虑在 Web API 堆栈的更高层执行此操作 - 也许在处理程序中 - 因为您可能会错过其他事务 activity 例如处理程序、过滤器等。取决于您想要进出范围的内容。