C# TransactionBortedException是否隐藏WCF故障?
我有以下情况:C# TransactionBortedException是否隐藏WCF故障?,c#,wcf,transactionscope,C#,Wcf,Transactionscope,我有以下情况: WCF客户端使用TransactionScope启动事务并将其传播到WCF服务 客户合同如下: public interface IMyService { [OperationContract] [FaultContract(typeof(MyException))] [TransactionFlow(TransactionFlowOption.Mandatory)] bool DoSomeTransactionalWork(); [Op
WCF
客户端使用TransactionScope启动事务并将其传播到WCF服务
客户合同如下:
public interface IMyService
{
[OperationContract]
[FaultContract(typeof(MyException))]
[TransactionFlow(TransactionFlowOption.Mandatory)]
bool DoSomeTransactionalWork();
[OperationContract]
[FaultContract(typeof(MyException))]
bool DoSomeWork();
}
未生成使用的代理,它基于众所周知的:
在服务方法的合同不需要事务的类似场景中:
public bool DoSomeWork()
{
throw new FaultException<MyException>(new MyException(myMessage));
}
public bool DoSomeWork()
{
抛出新的FaultException(newmyexception(myMessage));
}
客户端只需通过相同的代理代码调用它,就会收到FaultException
try
{
Service<MyService>.Use(proxy =>
{
proxy.DoSomeWork();
});
}
catch (FaultException<MyException> tae)
{
//
}
试试看
{
使用(代理=>
{
proxy.DoSomeWork();
});
}
捕获(错误异常tae)
{
//
}
我是遗漏了什么还是预期的行为
蒂亚
编辑1
客户端代码中的这种同步调用根本没有问题
但是,如果在使用APM时进行错误的异步调用,您可能会遇到我描述的行为。请参阅我的回答。我的同步呼叫没有这个问题 但是,我进行了一个无效的异步调用,导致了这个错误。因为BeginXXX和相应的EndXXX调用可能在不同的线程上执行,所以我正在创建一个DependentTransaction:
public class APMState
{
public IClientChannel Proxy { get; set; }
public OperationContext Identity { get; set; }
public DependentTransaction Transaction { get; set; }
}
Transaction tx = Transaction.Current;
try
{
DependentTransaction dtx = tx.DependentClone(DependentCloneOption.BlockCommitUntilComplete);
// There is no need for a TransactionScope here, the one set by the calling method is used.
((IMyService)proxy).BeginDoSomeTransactionalWork(..., new APMState{ Identity = OperationContext.Current, Proxy = proxy, Transaction = dtx});
}
catch (TransactionAbortedException tae)
{
}
我的EndXXX调用代码不正确:在调用EndXXX方法之前,应该验证事务是否已中止。如果不这样做,则TransactionScope构造函数将引发TransactionBortedException
APMState initialState = ar.AsyncState as APMState;
DependentTransaction dtx = initialState.Transaction;
if (dtx.TransactionInformation.Status != TransactionStatus.Aborted)
{
using (TransactionScope scope = new TransactionScope (dtx))
{
ae.Result = ((IMyService)initialState.Proxy).EndDoSomeTransactionalWork(ar);
scope.Complete();
}
dtx.Complete();
}
else
{
log.Error(@" The transaction has aborted :-(");
log.Debug(@" --> Calling EndDoSomeTransactionalWork on proxy outside a transaction scope to retreive the WCF fault :-)");
ae.Result = ((IMyService)initialState.Proxy).EndDoSomeTransactionalWork(ar);
}
问题解决了
try
{
Service<MyService>.Use(proxy =>
{
proxy.DoSomeWork();
});
}
catch (FaultException<MyException> tae)
{
//
}
public class APMState
{
public IClientChannel Proxy { get; set; }
public OperationContext Identity { get; set; }
public DependentTransaction Transaction { get; set; }
}
Transaction tx = Transaction.Current;
try
{
DependentTransaction dtx = tx.DependentClone(DependentCloneOption.BlockCommitUntilComplete);
// There is no need for a TransactionScope here, the one set by the calling method is used.
((IMyService)proxy).BeginDoSomeTransactionalWork(..., new APMState{ Identity = OperationContext.Current, Proxy = proxy, Transaction = dtx});
}
catch (TransactionAbortedException tae)
{
}
APMState initialState = ar.AsyncState as APMState;
DependentTransaction dtx = initialState.Transaction;
if (dtx.TransactionInformation.Status != TransactionStatus.Aborted)
{
using (TransactionScope scope = new TransactionScope (dtx))
{
ae.Result = ((IMyService)initialState.Proxy).EndDoSomeTransactionalWork(ar);
scope.Complete();
}
dtx.Complete();
}
else
{
log.Error(@" The transaction has aborted :-(");
log.Debug(@" --> Calling EndDoSomeTransactionalWork on proxy outside a transaction scope to retreive the WCF fault :-)");
ae.Result = ((IMyService)initialState.Proxy).EndDoSomeTransactionalWork(ar);
}