我有以下情况:
WCF
客户端使用TransactionScope启动并将事务传播到WCF服务。
客户合同如下:
public interface IMyService
{
[OperationContract]
[FaultContract(typeof(MyException))]
[TransactionFlow(TransactionFlowOption.Mandatory)]
bool DoSomeTransactionalWork();
[OperationContract]
[FaultContract(typeof(MyException))]
bool DoSomeWork();
}
使用的代理不会生成,它基于众所周知的wrapper:
using (TransactionScope ts = new TransactionScope())
{
Service<IMyService>.Use(proxy =>
{
proxy.DoSomeTransactionalWork();
});
}
WCF服务方法需要合同定义中的事务并为其隐式投票,抛出FaultException<MyException>
。
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public bool DoSomeTransactionalWork()
{
throw new FaultException<MyException>(new MyException(myMessage));
}
WCF代理收到TransactionAbortedException
,InnerException
设置为null,因此丢失了WCF错误。
try
{
using (TransactionScope ts = new TransactionScope())
{
Service<IMyService>.Use(proxy =>
{
proxy.DoSomeTransactionalWork();
});
}
}
catch (TransactionAbortedException tae)
{
// tae.InnerException is null
}
在类似的情况下,服务方法的合同不要求交易:
public bool DoSomeWork()
{
throw new FaultException<MyException>(new MyException(myMessage));
}
,客户端只需通过相同的代理代码调用它,就会收到FaultException<MyException>
。
try
{
Service<MyService>.Use(proxy =>
{
proxy.DoSomeWork();
});
}
catch (FaultException<MyException> tae)
{
//
}
我错过了什么或是预期的behavior
?
TIA。
编辑1
客户端代码中的此同步调用完全没有问题。
但是,如果在使用APM时进行错误的异步调用,可能会遇到我描述的行为。请参阅我的回复。
答案 0 :(得分:0)
同时调用我没有这个问题。
但是,我正在进行无效的异步调用,导致此错误。因为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构造函数抛出一个TransactionAbortedException。
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);
}
解决了问题。