How to prohibit a transaction scope to throw an exception that I have already handled?

I have a WCF operation conceptually:

    [OperationBehavior(TransactionScopeRequired = true)]
    public void Foo() 
    {
        try { DAL.Foo(); return Receipt.CreateSuccessReceipt(); }
        catch (Exception ex) { return Receipt.CreateErrorReceipt(ex); }
    }

If something goes wrong (for example, breaking a foreign key) while executing DAL code, control passes to the catch block, as I expected. But when the method returns, it seems that the transaction area sniffed out, that the transaction failed, and she decides that it is better to throw an exception to notify the caller.

In turn, my client application does not receive the receipt that I want to return, but rather the exception:

System.ServiceModel.FaultException:  
  The transaction under which this method call was executing was asynchronously aborted.

What is wrong with my design?

, , , ( , ) . , , .

+5
2

! TransactionAutoComplete = true, , , . ( , ), . . http://msdn.microsoft.com/en-us/library/system.servicemodel.operationbehaviorattribute.transactionautocomplete.aspx.

, DAL, (, NullReferenceException). , , , ErrorReceipt.

, , . :

[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = false)]
public Receipt Foo() 
{   
    // Create TransactionScope using the ambient transaction
    using (var scope = new TransactionScope() )
    {
        try { DAL.Foo(); return Receipt.CreateSuccessReceipt(); scope.Complete(); }
        catch (Exception ex) { return Receipt.CreateErrorReceipt(ex); }
    }
}

, , , // .

[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = false)]
public Receipt Foo() 
{   
    return ProcessWithTransaction(() =>
        {
            DAL.Foo();
            return Receipt.CreateSuccessReceipt();
        }
        , (ex) =>
        {
            return Receipt.CreateErrorReceipt(ex);
        }
    );
}

T ProcessWithTransaction<T>(Func<T> processor, Func<Exception, T> exceptionHandler)
{
    using (var scope = new TransactionScope())
    {
        try
        {
            T returnValue = processor();
            scope.Complete();
            return returnValue;
        }
        catch (Exception e)
        {
            return exceptionHandler(e);
        }
    }
}

, . , , ( ).

, :

[OperationBehavior(TransactionScopeRequired = true)]
public void Foo() 
{
    // Resolve the default ExceptionManager object from the container.
    ExceptionManager exManager = EnterpriseLibraryContainer.Current.GetInstance<ExceptionManager>();

    exManager.Process(() => 
      {
          DAL.Foo(); 
          return Receipt.CreateSuccessReceipt(); 
      }, 
      "ExceptionShielding");
}

( ) FaultException, .

+7
[OperationBehavior(TransactionAutoComplete = true, TransactionScopeRequired = true)]

, , , , : D, , , , , .

( , . , Q & , .)

0

All Articles