Transactions in .NET


Transactions are necessary to protect the integrity of data in distributed systems. Suppose we’re writing an on-line bill paying application. Paying my phone bill requires us to debit my account in some database and credit the phone company’s account, probably in a different database and possibly on a different machine. If the debit succeeds but the credit somehow fails, we need to undo the debit, or money would be destroyed and the integrity of the data in the system violated. We need to ensure that either both of these operations succeed or both of them fail. Performing both operations within a transaction does exactly that. If both operations succeed, the transaction commits and the new account values are saved. If either operation fails, the transaction aborts and all account values are rolled back to their original values. (To learn more about transactions in general, I highly recommend Principles of Transaction Processing by Philip A. Bernstein and Eric Newcomer, published by Morgan Kaufmann, 1997.)

Transactions ensure the integrity of databases during complex operations.

COM+, and its ancestor, Microsoft Transaction Server (MTS), provided automatic support that made it easy for programmers to write objects that participated in transactions. A programmer marked his objects administratively as requiring a transaction. COM+ then automatically created one when the object was activated. The object used COM+ Resource Managers, programs such as Microsoft SQL Server that support the COM+ way of performing transactions, to make changes to a database. The object then told COM+ whether it was happy with the results. If all the objects participating in a transaction were happy, COM+ committed the transaction, telling the Resource Managers to save all their changes. If any object was unhappy, COM+ aborted the transaction, telling the Resource Managers to discard the results of all objects’ operations, rolling back the state of the system to its original values. To learn more about COM+’s implementation of transactions, read my book Understanding COM+ (Microsoft Press, 1999).

COM+ contains good automatic transaction support.

Native .NET objects can also participate in COM+ transactions. The .NET Framework contains a layer of code that mediates between COM+ and native .NET objects, encapsulated in the base class System.EnterpriseServices.ServicedComponent. Objects that want to participate in COM+ transactions (or use any other COM+ services, for that matter) must inherit from this class. Just as with .NET components accessed from COM, your .NET class must contain a default constructor (one that accepts no parameters), and you must sign it with a strong name. You specify your component’s use of transactions by marking the class with the attribute System.EnterpriseServices.Transaction. The code in Listing 2-14 shows a class from my sample program that demonstrates COM+ transactions in a native .NET object.

Native .NET objects can participate in COM+ transactions by using prefabricated .NET Framework functionality.

Listing 2-14: COM+ transactions in a native .NET object.

start example
Imports System.EnterpriseServices ‘ Mark our class as requiring a transaction <Transaction(TransactionOption.Required)> Public Class Class1 ’ We need to inherit from ServicedComponent, which contains ’ code for interacting with COM+ Inherits ServicedComponent ’ Mark this method to use .NET’s automatic ’ transaction voting (optional) <AutoComplete()> Sub AutoCompleteMethod() (program logic omitted) End Sub End Class 
end example

Your .NET client creates a transactional object using the new operator, exactly as for any other .NET object. When you do this, the ServicedComponent base class from which your object inherits first looks to see if the component is registered with the COM+ catalog. If it’s not, the base class registers the component with the COM+ catalog, creating a COM+ application for it and adding the .NET class to it as a COM+ component, as shown in Figure 2-24. The metadata in the .NET class specifies its transactional requirements, which the base class uses to set the .NET component’s properties in the COM+ catalog. The base class sets not only the component’s use of transactions, but also the other COM+ properties implied by the transaction, such as JIT activation and synchronization. If you want your component to set these or other COM+ properties explicitly, you will find that the namespace System.EnterpriseServices contains many other attributes, such as ObjectPooling, with which you decorate your class to specify its behavior. Once your object is created, your client calls methods on it exactly as for any other .NET object. You can watch the sample program’s transactional operations in Component Services, as shown in Figure 2-25.

The system base class registers your .NET component in the COM+ catalog.

click to expand
Figure 2-24: Transactional .NET component installed in Component Services Explorer.

click to expand
Figure 2-25: .NET component committing and aborting transactions.

An object that participates in a transaction needs to vote on that transaction’s outcome. Your .NET transactional object can do this in one of two ways. The easiest way is to use the automatic transaction voting in .NET. You mark your transactional-component method with the attribute System.EnterpriseServices.AutoComplete, as shown previously in Listing 2-14. In this case, a method that returns without throwing an exception automatically calls SetComplete internally, while a method that throws an exception to its caller automatically calls SetAbort internally. If your methods are self-contained (as they should be anyway for good transactional component design), and if they signal failure to their clients by means of exceptions (as they should do anyway for good .NET component design), this approach is probably the best choice.

A .NET transactional component can be configured so that it votes on its transaction automatically by throwing or not throwing an exception.

Alternatively, your .NET object might want to vote on the outcome of its transaction by means of explicit function calls. In COM+ and MTS, an object fetched its context by calling the API function GetObjectContext and then called a method on the context to indicate its transaction vote. A .NET object will find its context on the system-provided object named System.EnterpriseServices.ContextUtil. This object provides the commonly used methods SetAbort and SetComplete, and their somewhat less common siblings, EnableCommit and DisableCommit. These methods set your object’s happiness and doneness bits in exactly the same manner as they did in COM+. The context also contains everything else you would expect to find in a COM+ context, such as the properties DeactivateOnReturn and MyTransactionVote, which allow you to read and set these bits individually. If your object requires several function calls to accomplish its work within a single transaction, or you haven’t yet converted your error handling code to use structured exception handling, this choice is probably best for you.

A .NET transactional component can also vote on its transaction via explicit function calls.




Introducing Microsoft. NET
Introducing Microsoft .NET (Pro-Developer)
ISBN: 0735619182
EAN: 2147483647
Year: 2003
Pages: 110

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net