Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/wcf/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# TransactionBortedException是否隐藏WCF故障?_C#_Wcf_Transactionscope - Fatal编程技术网

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