Calling methods of different classes into same Transaction Scope using System.Transactions

SheoNarayan
Posted by in ASP.NET category on for Advance level | Views : 15547 red flag
Rating: 4 out of 5  
 1 vote(s)

We must have came across a situation where we have to call methods of different classes under same transaction scope and rollback the operations if any error occurs during execution of any methods. For eg. If we have Debit and Credit class and DebitAmount method of Debit class executed successfully but an error occurred while calling CreditAmount method of Credit class, we should be able to rollback all operations done by DebitAmount method. In scenario like this we can use System.Transactions.TransactionScope to rollback all operations done by DebitAmount method.
Introduction

All most all of us generally use SqlTransaction in our day to day coding. But in this article I am going to explain about System.Transaction namespace that allows us to call different methods of different classes under a TransactionScope and commit the tranaction only if all of them are successfully executed.

Problem

SqlTransaction doesn't suits us in the scenaior explained above. As different methods of different classes are using their own SqlConnection object and we don't have any control over them.

For easy understanding of the above scenario, I am going to take example of Debit and Credit class that has DebitAmount and CreditAmount method with parameter as accountNo and amount. In my TransferAmount method, I have to call DebitAmount method of Debit class and then CreditAmount method of Credit class so that the transfer of fund happen successfully. So my normal code will look like:

Normal TransferAmount Method

protected void TransferAmount(object sender, EventArgs e)
{
DebitBAL debit = new DebitBAL();
CreditBAL credit = new CreditBAL();

try
{
int dAccountNo = int.Parse(txtDAccountNo.Text);
int cAccountNo = int.Parse(txtCAccountNo.Text);
decimal amount = decimal.Parse(txtAmount.Text);

// Debit amount from the account
debit.DebitAmount(dAccountNo, amount);

// Credit amount to the account
credit.CreditAmount(cAccountNo, amount);

}
catch (Exception ee)
{
lblMessage.Text = ee.Message.ToString();
}
finally
{
debit.Dispose();
credit.Dispose();
}
}

In the above method, I am instantiating my Debit class (DebitBAL) and Credit class (CreditBAL) and calling DebitAmount and CreditAmount method respectively. The above code will work fine if no error will occur in the CreditAmount method. But the gotcha :) here is that if while calling CreditAmount method any error occurs then amount will be debited from the account but it will not be credited into other account. In this case we can't use SqlTransaction as we don't have any parameter to pass other than accountNo and amount and also both classes are using different SqlConnection objects to connect to the database.

Get video of hundreds of ASP.NET Tips and Tricks - http://www.itfunda.com/aspnet-how-to-tips-and-tricks/Show/50

Solution

In scenaio like this, System.Transaction namespace comes into the picture and this solves our problem very easily. This namespace has several classes but we are going to focus on TransactionScope class that makes the code block transactional. To overcome the problem identified above, we will need to modify our code as follows:

Modified code using System.Transactions.TransactionScope

protected void TransferAmount(object sender, EventArgs e)
{
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required))
{
DebitBAL debit = new DebitBAL();
CreditBAL credit = new CreditBAL();

try
{
int dAccountNo = int.Parse(txtDAccountNo.Text);
int cAccountNo = int.Parse(txtCAccountNo.Text);
decimal amount = decimal.Parse(txtAmount.Text);

// Debit amount from the account
debit.DebitAmount(dAccountNo, amount);

// Credit amount to the account
credit.CreditAmount(cAccountNo, amount);

// notify the TransactionScope that transaction is complete now
// If you will not write following statement the transaction
// will be automatially rolledback. There is no separate Rollback method for TransactionScope
ts.Complete();
}
catch (Exception ee)
{
lblMessage.Text = ee.Message.ToString();
}
finally
{
debit.Dispose();
credit.Dispose();
}

} // TransactionScope
}


In the above modified code, I am using TransactionScope class and instantiating with TransactionScopeOption.Required parameter and doing the same thing as I had done in my normal code (instantiating Debit and Credit class and calling respective methods). After my DebitAmount and CreditAmount method have been called I am calling Complete() method of the TransactionScrope class to notify it that all the operations within transaction scope completed successfully. You can notice that there is no separate method like rollback (rollback of of SqlTransaction) here so if you will not call ts.Complete() then automatically all operations will be rolled back as a result no change will be made even if your methods inside your TransactionScope block executed successfully.

What you need to do to work with System.Transactions

Add Reference
In order to work your modified code, you need to add reference of System.Transactions namespace by right clicking on your project's bin folder and selecting Add Reference ... When you do that your web.config file Compilation section will be modified something like this

<compilation>

<assemblies>
<add assembly="System.Transactions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
</assemblies>
</compilation>


Start Distributed Transaction Coordinator service
You need to start the Distributed Transaction Coordinator service on your server (or machine you are working on) by going through START > SETTINGS > CONTROL PANEL > ADMINISTRATIVE TOOLS > SERVICES.


Conclusion

Using System.Transactions.TransactionScope we can call different methods of different classes within a scope and commits all changes once all methods executed successfully.

Hope this article looks interesting to you. If you have something to say, please feel free to write your feedback.

References:
http://msdn.microsoft.com/en-us/library/ms229977.aspx
http://msdn.microsoft.com/en-us/library/ms172152.aspx
Page copy protected against web site content infringement by Copyscape

About the Author

SheoNarayan
Full Name: Sheo Narayan
Member Level: HonoraryPlatinum
Member Status: Administrator
Member Since: 7/8/2008 6:32:14 PM
Country: India
Regards, Sheo Narayan http://www.dotnetfunda.com
http://www.snarayan.com
Ex-Microsoft MVP, Author, Writer, Mentor & architecting applications since year 2001. Connect me on http://www.facebook.com/sheo.narayan | https://twitter.com/sheonarayan | http://www.linkedin.com/in/sheonarayan

Login to vote for this post.

Comments or Responses

Login to post response

Comment using Facebook(Author doesn't get notification)