oreilly.comSafari Books Online.Conferences.


AddThis Social Bookmark Button

.NET Serviced Components
Pages: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11

The TransactionContext Object

Related Reading

COM and .NET Component ServicesCOM and .NET Component Services
By Juval Lwy
Table of Contents
Sample Chapter
Full Description

A nontransactional managed client creating a few transactional objects faces a problem discussed in Chapter 4 (see the section "Nontransactional Clients"). Essentially, if the client wants to scope all its interactions with the objects it creates under one transaction, it must use a middleman to create the objects for it. Otherwise, each object created will be in its own separate transaction. COM+ provides a ready-made middleman called TransactionContext. Managed clients can use TransactionContext as well. To use the TransactionContext object, add to the project references the COM+ services type library. The TransactionContext class is in the COMSVCSLib namespace.

The TransactionContext class is especially useful in situations in which the class is a managed .NET component that derives from a class other than ServicedComponent. Remember that a .NET component can only derive from one concrete class and since the class already derives from a concrete class other than ServicedComponent, it cannot use the Transaction attribute. Nevertheless, the TransactionContext class gives this client an ability to initiate and manage a transaction.

Example 10-8 demonstrates usage of the TransactionContext class, using the same use-case as Example 4-6.

Example 10-8: A nontransactional managed client using the TransactionContext helper class to create other transactional objects

using COMSVCSLib;
IMyInterface obj1,obj2,obj3;
ITransactionContext transContext;
transContext = (ITransactionContext) new TransactionContext(  );
obj1 = (IMyInterface)transContext.CreateInstance("MyNamespace.MyComponent");
obj2 = (IMyInterface)transContext.CreateInstance("MyNamespace.MyComponent");
obj3 = (IMyInterface)transContext.CreateInstance("MyNamespace.MyComponent");
   obj1.MyMethod(  );    
   obj2.MyMethod(  );    
   obj3.MyMethod(  );    
   transContext.Commit(  );   
catch//Any error - abort the transaction 
   transContext.Abort(  );   

Note that the client in Example 10-8 decides whether to abort or commit the transaction depending on whether an exception is thrown by the internal objects.

COM+ Transactions and Nonserviced Components

Though this chapter focuses on serviced components, it is worth noting that COM+ transactions are used by other parts of the .NET framework besides serviced components--in particular, ASP.NET and Web Services.

Web services and transactions

Web services are the most exciting piece of technology in the entire .NET framework. Web services allow a middle-tier component in one web site to invoke methods on another middle-tier component at another web site, with the same ease as if that component were in its own assembly. The underlying technology facilitating web services serializes the calls into text format and transports the call from the client to the web service provider using HTTP. Because web service calls are text based, they can be made across firewalls. Web services typically use a protocol called Simple Object Access Protocol (SOAP) to represent the call, although other text-based protocols such as HTTP-POST and HTTP-GET can also be used. .NET successfully hides the required details from the client and the server developer; a web service developer only needs to use the WebMethod attribute on the public methods exposed as web services. Example 10-9 shows the MyWebService web service that provides the MyMessage web service--it returns the string "Hello" to the caller.

Example 10-9: A trivial web service that returns the string "Hello"

using System.Web.Services;
public class MyWebService : WebService
    public MyWebService(  ){}
    public string MyMessage(  )
       return "Hello";

The web service class can optionally derive from the WebService base class, defined in the System.Web.Services namespace (see Example 10-9). The WebService base class provides you with easy access to common ASP.NET objects, such as those representing application and session states. Your web service probably accesses resource managers and transactional components. The problem with adding transaction support to a web service that derived from WebService is that it is not derived from ServicedComponent, and .NET does not allow multiple inheritance of implementation.

To overcome this hurdle, the WebMethod attribute has a public property called TransactionOption, of the enum type Enterprise.Services.TransactionOption discussed previously.

The default constructor of the WebMethod attribute sets this property to TransactionOption.Disabled, so the following two statements are equivalent:

[WebMethod(TransactionOption = TransactionOption.Disabled)]

If your web service requires a transaction, it can only be the root of a transaction, due to the stateless nature of the HTTP protocol. Even if you configure your web method to only require a transaction and it is called from within the context of an existing transaction, a new transaction is created for it. Similarly, the value of TransactionOption.Supported does not cause a web service to join an existing transaction (if called from within one).

Consequently, the following statements are equivalent--all four amount to no transaction support for the web service:

[WebMethod(TransactionOption = TransactionOption.Disabled)]
[WebMethod(TransactionOption = TransactionOption.NotSupported)]
[WebMethod(TransactionOption = TransactionOption.Supported)]

Moreover, the following statements are also equivalent--creating a new transaction for the web service:

[WebMethod(TransactionOption = TransactionOption.Required)]
[WebMethod(TransactionOption = TransactionOption.RequiresNew)]

The various values of TransactionOption are confusing. To avoid making them the source of errors and misunderstandings, use TransactionOption.RequiresNew when you want transaction support for your web method; use TransactionOption.Disabled when you want to explicitly demonstrate to a reader of your code that the web service does not take part in a transaction. The question is, why did Microsoft provide four overlapping transaction modes for web services? I believe that it is not the result of carelessness, but rather a conscious design decision. Microsoft is probably laying down the foundation in .NET for a point in the future when it will be possible to propagate transactions across web sites.

Finally, you do not need to explicitly vote on a transaction from within a web service. If an exception occurs within a web service method, the transaction is automatically aborted. Conversely, if no exceptions occur, the transaction is committed automatically (as if you used the AutoComplete attribute). Of course, the web service can still use ContextUtil to vote explicitly to abort instead of throwing an exception, or when no exception occurred and you still want to abort.

ASP.NET and transactions

An ASP.NET web form may access resource managers (such as databases) directly, and it should do so under the protection of a transaction. The page may also want to create a few transactional components and compose their work into a single transaction. The problem again is that a web form derives from the System.Web.UI.Page base class, not from ServicedComponent, and therefore cannot use the [Transaction] attribute.

To provide transaction support for a web form, the Page base class has a write-only property called TransactionMode of type TransactionOption. You can assign a value of type TransactionOption to TransactionMode, to configure transaction support for your web form. You can assign TransactionMode programmatically in your form contractor, or declaratively by setting that property in the visual designer. The designer uses the Transaction page directive to insert a directive in the aspx form file. For example, if you set the property using the designer to RequiresNew, the designer added this line to the beginning of the aspx file:

<@% Page Transaction="RequiresNew" %>

Be aware that programmatic setting will override any designer setting. The default is no transaction support (disabled).

The form can even vote on the outcome of the transaction (based on its interaction with the components it created) by using the ContextUtil methods. Finally, the form can subscribe to events notifying it when a transaction is initiated and when a transaction is aborted.

Pages: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11

Next Pagearrow