How to Detect a Transaction Abort in a ServicedComponent?

422 views Asked by At

I'm trying to create a System.EnterpriseServices.ServicedComponent in order to participate in a distributed transaction. My main method looks something like this:

public void DoSomething()
{
    try
    {
      // do something useful

      // vote for commit

      if (ContextUtil.IsInTransaction)
          ContextUtil.MyTransactionVote = TransactionVote.Commit;
    }

    catch
    {
      // or shoud I use ContextUtil.SetAbort() instead?

      if (ContextUtil.IsInTransaction)
          ContextUtil.MyTransactionVote = TransactionVote.Abort;

      throw;
    }
}

What I'm trying to do is detecting whether the distributed transaction has been aborted (or rolled back) and then proceed to rollback my changes as well. For instance, I might have created a file on disk, or done some side effects that need to be undone.

I have tried to handle the SystemTransaction.TransactionCompleted event or inspected the state of the SystemTransaction in the Dispose() method without success.

I understand that this is similar to "compensation" rather than "transaction".

Does what I'm trying to do even make sense ?

2

There are 2 answers

0
Maxime Labelle On BEST ANSWER

Answering my own question, this is possible by deriving the ServicedComponent from System.Transactions.IEnlistmentNotification as well.

1
Luis Quijada On

I would recommend to not manage the transaction in such way unless you need it.

If you want your operation to vote abort if any of the other operations involved in the chain fail, or vote for commit if everything went fine; just place an [AutoComplete] atttribute (see Remarks section at this article) just above your method's declaration.

In this way the current transaction will be aborted just in case an exception raises and will be completed otherwise, automatically.

Consider the code below (this could be a typical serviced component class):

using System.EnterpriseServices;

// Description of this serviced component
[Description("This is dummy serviced component")]
public MyServicedComponent : ServicedComponent, IMyServiceProvider
{
    [AutoComplete]
    public DoSomething()
    {
        try {
            OtherServicedComponent component = new OtherServicedComponent()
            component.DoSomethingElse();

            // All the other invocations involved in the current transaction
            // went fine... let's servicedcomponet vote for commit automatically
            // due to [AutoComplete] attribute
        }
        catch (Exception e)
        {
            // Log the failure and let the exception go
            throw e;
        }
    }
}