是否可以在自定义 WCF 服务行为中创建 TransactionScope? (异步,等待,TransactionScopeAsyncFlowOption.Enabled)

Is it possible to create a TransactionScope in a Custom WCF Service Behavior? (async, await, TransactionScopeAsyncFlowOption.Enabled)

TL;DR ?

解释问题的截屏视频:https://youtu.be/B-Q3T5KpiYk

问题

当一个交易从一个客户端流向一个服务时 Transaction.Currentwaiting[ 之后变为 null =55=] 服务到服务调用。

当然,除非您在服务方法中创建一个新的 TransactionScope,如下所示:

[OperationBehavior(TransactionScopeRequired = true)]
public async Task CallAsync()
{
    using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
    {
        await _service.WriteAsync();
        await _service.WriteAsync();            
        scope.Complete();
    }
}

为什么默认情况下不启用 TransactionScopeAsyncFlowOption 我不知道,但我不想重复自己所以我想我总是使用自定义行为创建一个带有该选项的内部事务范围。

问题更新

它甚至不必是服务到服务调用,对本地异步方法的等待也为空 Transaction.Current。举例说明

[OperationBehavior(TransactionScopeRequired = true)]
public async Task CallAsync()
{
    await WriteAsync();
    // Transaction.Current is now null
    await WriteAsync();                     
}

尝试的解决方案

我创建了一个 Message Inspector,实现了 IDispatchMessageInspector 并将其附加为服务行为,代码执行并且那里的一切都没有问题,但它与在服务方法中声明 transactionscope 的效果不同。

public class TransactionScopeMessageInspector : IDispatchMessageInspector
{
    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
    {
        var transactionMessage = (TransactionMessageProperty)OperationContext.Current.IncomingMessageProperties["TransactionMessageProperty"];
        var scope = new TransactionScope(transactionMessage.Transaction, TransactionScopeAsyncFlowOption.Enabled);            
        return scope;
    }

    public void BeforeSendReply(ref Message reply, object correlationState)
    {
        var transaction = correlationState as TransactionScope;
        if (transaction != null)
        {
            transaction.Complete();
            transaction.Dispose();
        }
    }
}

通过在调试时查看标识符,我可以看到消息检查器中的事务实际上与服务中的事务相同但是 在第一次通话后,即

await _service_WriteAsync();

Transaction.Current 变为 null。如果在消息检查器中也没有从 OperationContext.Current 获取当前事务,情况也是一样,所以这不太可能是问题所在。

问题

有没有可能做到这一点?似乎唯一的方法是在服务方法中声明一个 TransactionScope,即:

public async Task CallAsync()
{
    var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled);
    await _service.WriteAsync();
    await _service.WriteAsync();            
    scope.Complete();
}

使用以下服务合同很明显,如果 transaction.current 在

之间变为 null,我们会在第二次服务调用时出现异常
[OperationContract, TransactionFlow(TransactionFlowOption.Mandatory)]
Task WriteAsync();

原来我们真的不应该在服务器上将 async/await 关键字与分布式事务一起使用,有关详细信息,请参阅 this blog post