是否可以在自定义WCF服务行为中创建TransactionScope? (async,await,TransactionScopeAsyncFlowOption.Enabled)
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并将其作为服务行为附加,代码执行并且没有任何问题,但它与在service方法中声明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,那么使用以下服务契约显然会在第二个服务调用上获得exception
[OperationContract, TransactionFlow(TransactionFlowOption.Mandatory)] Task WriteAsync();
事实certificate,我们不应该在服务器上使用async / await关键字以及分布式事务,有关详细信息,请参阅此博客文章 。