是否可以在自定义WCF服务行为中创建TransactionScope? (异步,等待,TransactionScopeAsyncFlowOption.Enabled) [英] Is it possible to create a TransactionScope in a Custom WCF Service Behavior? (async, await, TransactionScopeAsyncFlowOption.Enabled)

查看:218
本文介绍了是否可以在自定义WCF服务行为中创建TransactionScope? (异步,等待,TransactionScopeAsyncFlowOption.Enabled)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Screencast explaining problem: https://youtu.be/B-Q3T5KpiYk

将交易从客户端流向服务时,等待服务呼叫后, Transaction.Current 变为.

When flowing a transaction from a client to a service Transaction.Current becomes null after awaiting a service to service call.

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

Unless of course you create a new TransactionScope in your service method as follows:

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

我不知道为什么默认情况下未启用TransactionScopeAsyncFlowOption,但是我不想重复我自己,所以我想我总是会使用自定义行为使用该选项创建一个内部transactionscope.

Why TransactionScopeAsyncFlowOption isn't enabled by default I don't know, but I don't like to repeat myself so I figured I'd always create an inner transactionscope with that option using a custom behavior.

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

It doesn't even have to be a service to service call, an await to a local async method also nulls Transaction.Current. To clearify with an example

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

尝试的解决方案

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

Attempted Solution

I created a Message Inspector, implementing IDispatchMessageInspector and attached it as a service behavior, code executes and everyting no problem there, but it doesn't have the same effect as declaring the transactionscope in the service method.

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();
        }
    }
}

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

by looking at the identifiers when debugging I can see that it in fact is the same transaction in the message inspector as in the service but after the first call, i.e.

await _service_WriteAsync();

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

Transaction.Current becomes null. Same thing if not getting the current transaction from OperationContext.Current in the message inspector as well so it's unlikely that is the problem.

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

Is it even possible to accomplish this? It appears like the only way is to declare a TransactionScope in the service method, that is:

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

使用以下服务合同,很明显,如果之间的transaction.current变为null,则第二个服务调用会获得异常

with the following service contract it's obvious that we get an exception on the second service call if transaction.current became null inbetween

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

推荐答案

原来我们不应该在服务器上与分布式事务一起真正使用async/await关键字,请参见

Turns out we shouldn't really be using the async/await keyword on the server together with distributed transactions, see this blog post for details.

这篇关于是否可以在自定义WCF服务行为中创建TransactionScope? (异步,等待,TransactionScopeAsyncFlowOption.Enabled)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆