在使用异步主机实现(在我的情况下使用任务)并异步抛出异常(即从延续)的服务上调用标记为“TransactionScopeRequired = true”的 WCF 操作,似乎总是导致以下异常(而不是我抛出的异常)在客户端收到:
System.AggregateException: One or more errors occurred. ---> System.ServiceModel.ProtocolException: The transaction under which this method call was executing was asynchronously aborted.
at System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message reply, MessageFault fault, String action, MessageVersion version, FaultConverter faultConverter)
at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)
at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)
at System.ServiceModel.Channels.ServiceChannelProxy.TaskCreator.<>c__DisplayClass6_0.<CreateTask>b__0(IAsyncResult asyncResult)
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at System.Threading.Tasks.Task.Wait()
at WcfTransactionScopeRequiredAsync.Program.Main(String[] args) in D:\\WcfTransactionScopeRequiredAsync\\WcfTransactionScopeRequiredAsync.Client\\Program.cs:line 19
---> (Inner Exception #0) System.ServiceModel.ProtocolException: The transaction under which this method call was executing was asynchronously aborted.
at System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message reply, MessageFault fault, String action, MessageVersion version, FaultConverter faultConverter)
at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)
at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)
at System.ServiceModel.Channels.ServiceChannelProxy.TaskCreator.<>c__DisplayClass6_0.<CreateTask>b__0(IAsyncResult asyncResult)
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)<---
服务合约:
[ServiceContract]
public interface IService
{
[FaultContract(typeof(SomeFault))]
[TransactionFlow(TransactionFlowOption.Allowed)]
[OperationContract]
Task DoItAsync();
}
服务主机实现:
[OperationBehavior(TransactionScopeRequired = true)]
public async Task DoItAsync()
{
using (TransactionScope tx = new TransactionScope(TransactionScopeOption.Required, TransactionScopeAsyncFlowOption.Enabled))
{
await Task.Delay(1000).ConfigureAwait(continueOnCapturedContext: false);
throw new FaultException<SomeFault>(new SomeFault());
tx.Complete();
}
}
客户端是同步的:
service.DoItAsync().Wait();
在这种情况下,客户端不会处理事务(因此这绝对不是分布式事务(通过检查 Transaction.Current.TransactionInformation.DistributedIdentifier 进行验证)。
此代码已使用 .NET 框架 4.7.2 进行了测试。
到目前为止,我的研究表明,这个 ProtocolException 是由服务主机上的 WCF 管道引发的(从 Exception 中的堆栈跟踪也很明显),并且应该是为了处理在主机控制之外中止的分布式事务(即,当DTC 发出中止)。尽管这似乎有些道理,但这里显然不是这种情况。
在主机上仍然使用异步实现的同时,有什么方法可以避免这个 ProtocolException?