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

时间:2016-01-13 13:28:11

标签: c# wcf asynchronous async-await transactionscope

TL; DR?

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

问题

等待服务到服务电话

之后,当从客户端将流量转移到服务时 Transaction.Current 变为 null

除非您在服务方法中创建一个新的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在中间变为空,我们在第二次服务调用时会遇到异常

[OperationContract, TransactionFlow(TransactionFlowOption.Mandatory)]
Task WriteAsync();

1 个答案:

答案 0 :(得分:1)

事实证明,我们不应该在服务器上使用async / await关键字以及分布式事务,有关详细信息,请参阅this blog post