是否可以在自定义WCF服务行为中创建TransactionScope?(异步,等待,TransactionScopeSy
本文关键字:TransactionScope 异步 等待 创建 TransactionScopeSy 自定义 WCF 服务行 是否 | 更新日期: 2023-09-27 18:30:04
TL;博士
屏幕截图解释问题:https://youtu.be/B-Q3T5KpiYk
问题
当事务从客户端流向服务时事务。在等待服务对服务调用后,当前变为空。
当然,除非你在你的服务方法中创建一个新的TransactionScope,如下所示:
[OperationBehavior(TransactionScopeRequired = true)]
public async Task CallAsync()
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
await _service.WriteAsync();
await _service.WriteAsync();
scope.Complete();
}
}
为什么TransactionScopeSyncFlowOption在默认情况下没有启用我不知道,但我不想重复我自己,所以我想我总是会使用自定义行为创建一个内部事务来处理该选项。
问题更新
它甚至不必是服务对服务的调用,对本地异步方法的等待也为Transaction.Current为null
[OperationBehavior(TransactionScopeRequired = true)]
public async Task CallAsync()
{
await WriteAsync();
// Transaction.Current is now null
await WriteAsync();
}
尝试的解决方案
我创建了一个消息检查器,实现了IDispatchMessageInspector,并将其作为服务行为附加,代码执行,一切都没有问题,但它的效果与在服务方法中声明事务作用域不同。
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();
事务。当前变为空。如果没有从消息检查器中的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关键字,有关详细信息,请参阅这篇博客文章。