dcsimg
July 27, 2017
Hot Topics:

System.Transactions: Implement Your Own Resource Manager

  • November 18, 2005
  • By Sahil Malik
  • Send Email »
  • More Articles »

Now that you have created an RM that works with System.Transactions, you can leverage the framework to write simple and reliable code. Using the above RM is rather simple. For example, entering the following code:

VolatileRM vrm = null ;
using (TransactionScope txSc = new TransactionScope())
{
   vrm = new VolatileRM();
   vrm.SetMemberValue(3);
   txSc.Complete();
}
Console.WriteLine("Member Value:" + vrm.MemberValue);

Produces the following output:

VolatileRM: SetMemberValue - EnlistVolatile
VolatileRM: Prepare
VolatileRM: Commit
Member Value:3

As you can see, the Member Value is updated, and the RM got notifications at the Prepare and Commit stages because it enlisted in a volatile fashion.

If you wanted to force a rollback through the RM, you could simply change the RM's Prepare method to the following:

public void Prepare(PreparingEnlistment preparingEnlistment)
{
   Console.WriteLine("VolatileRM: Prepare");
   preparingEnlistment.ForceRollback();
}

By doing so, you force a rollback, which will cause an exception as shown in Figure 1.



Click here for a larger image.

Figure 1. An Exception from a Forced Rollback

You can in fact force a custom exception by using a suitable overload of the preparingEnlistment.RollBack method.

Yet another method for issuing a rollback is using the client program, or the consumer of the RM. Simply remove the TransactionScope.Complete statement, or enlist another RM that enlists within the same transaction and issues a rollback on the entire transaction:

VolatileRM vrm = null ;
using (TransactionScope txSc = new TransactionScope())
{
   vrm = new VolatileRM();
   vrm.SetMemberValue(3);
   // txSc.Complete();
}
Console.WriteLine("Member Value:" + vrm.MemberValue);

When you run this code, it produces the following output:

VolatileRM: SetMemberValue - EnlistVolatile
VolatileRM: Rollback
Member Value: 0

At this point, you may be wondering what the big deal is with this paradigm? Well, the big deal is that by following this paradigm now, you can effectively created an RM that will allow its consumers to easily write transactional code that may or may not include operations of other RMs. For instance, you can easily enlist your RM, which performs the non-database operation of modifying a member variable, in the same transaction as a database transaction. You can do this easily by setting up a database using the following T-SQL script:

Create Database Test
Go
Create Table Demo
(
   DemoValue varchar(5)
)

The following code then will enlist VolatileRM and two instances of SqlConnection in the same transaction:

private static string connStr =
   "Data Source=(local);Initial Catalog=Test;
    Integrated Security=True";
static void Main(string[] args)
{
   VolatileRM vrm = null ;
   using (TransactionScope txSc = new TransactionScope())
   {
      vrm = new VolatileRM();
      vrm.SetMemberValue(3);
      using (SqlConnection cn = new SqlConnection(connStr))
      {
         SqlCommand cmd = cn.CreateCommand();
         cmd.CommandText = "Insert into Demo(DemoValue)
                            Values ('XXX')";
         cn.Open();
         cmd.ExecuteNonQuery();
         cn.Close();
      }
      using (SqlConnection cn = new SqlConnection(connStr))
      {
         SqlCommand cmd = cn.CreateCommand();
         cmd.CommandText = "Insert into Demo(DemoValue)
                            Values ('YYY')";
         cn.Open();
         cmd.ExecuteNonQuery();
         cn.Close();
      }
      Console.WriteLine( "Transaction identifier:" +
         Transaction.Current.TransactionInformation.
         DistributedIdentifier);
      txSc.Complete();
   }
   Console.WriteLine("Member Value:" + vrm.MemberValue);
}

The framework is smart enough to recognize that your SqlConnection instance participates in the transaction using PSPE. As soon as a second SqlConnection instance shows up, it will automatically escalate the transaction to MSDTC when the second cn.Open is called. You can see this in the applet at Control Panel à Administrative Tools à Component Services (see Figure 2).



Click here for a larger image.

Figure 2. Transaction List Applet for Your Enlisted RM

Note: SqlConnection connected to SQL Server 2005 exhibits promotable enlistment, but SqlConnection connected to SQL Server 2000 or below will enlist in a durable fashion even though only a single RM exists in the current transaction scope.

When you run the program now, it produces the following output:

VolatileRM: SetMemberValue - EnlistVolatile
Transaction identifier:c40015f6-5086-4688-b565-c65db1cbc8e7
VolatileRM: Prepare
VolatileRM: Commit
Member Value:3

As you can see, you are still enlisting volatile. However, as need be, your transaction is automatically promoted to MSDTC and it gets a distributed identifier, which (surprise, surprise) matches the GUID reported by MSDTC in Figure 2. If you're an architect, this gives you the best of both worlds: transactional integrity and the best possible performance. And you get all of this by writing consumer code in a rather simplistic fashion:

Transaction
{
   Operation A ;
   Operation B ;
   ....
   ....
   Commit()
}

Implementing a System.Transactions-based Transaction

Now you know the basics of how to implement a System.Transactions-based transaction. You learned the various ways of enlisting with a current running transaction and saw how easy it is to implement your very own RM that enlists in a volatile fashion.

Download the Code

To download the accompanying source code for the examples, click here.

About the Author

Sahil Malik has worked for a number of top-notch clients in Microsoft technologies ranging from DOS to .NET. He is the author of Pro ADO.NET 2.0 and co-author of Pro ADO.NET with VB.NET 1.1. Sahil is currently also working on a multimedia series on ADO.NET 2.0 for Keystone Learning. For his community involvement, contributions, and speaking, he has also been awarded the Microsoft MVP award.





Page 2 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date
Rocket Fuel