Friday, June 22, 2007

Figuring Out TransactionScope

One of the things that came out of Tech Ed was TransactionScope (and the other things in the System.Transactions assembly) for distributed transactions. Prior to TransactionScope the only way of having a transaction span remote SQL connections was to use the System.EnterpriseServices pattern: derive a class from ServicedComponent, mark it with Transaction and AutoComplete attibutes, install the component into Component Services and you're done!

This is a pattern I'm very familiar with, but I don't need to tell those of you that use it how much trouble it quickly becomes. But for those of you that don't, here's a few of my pet peeves:

  • During development a COM+ Server application will run outside of the debugger, so you have to explicitly tell Visual Studio to attach to the dllhost.exe process if you want to debug the code within it.
  • The ASP.Net user that web applications run under don't have the permissions to lazy load the component as it's needed, so you have to either run impersonated as another user, or add a post build event into your project to manually call into Regsvcs every time your assembly changes.
  • Deployment is difficult as the COM+ components have to be installed (which seems to take longer on each install)
  • Tests using the components are slow as they have to be registered before they are run
  • Transactions are declared at a class level, which means if you want to go from no transaction to required, to requires new, you have to create 3 classes and figure out a way of chaining them together in the way you want.
In short, COM+ is a pain that I've had ill feelings towards for a while, but there seemed no alternative for what we need.

Until now that is.

Using TransactionScope certainly seems as simple as is documented, and it does have a performance increase over COM+ (from the limited tests that I've done). The transaction management seems faster and we're not calling into another process to do the work like I think we do with COM+.

A couple of things I found though, that do seem quite reasonable:
  • The TransactionScope needs to be instantiated before the object that will be controlling your transaction, so you need to create a scope before you create a SqlConnection
  • You don't seem to be able to enlist in a new SqlTransaction inside of a required scope and have that SqlTransaction commit separately from the ambient transaction. However, you can create a new connection inside a new scope declared with a Suppress TransactionScopeOption
Which do seem quite reasonable, if you understand that they will happen. Although, I'm not convinced I've fully explored the options available to me for the second point. If anyone knows if this is actually the case then please let me know.

But for now it looks like TransactionScope executes faster than using COM+, and it looks to be easier to develop as well.

No comments: