Transactions with .NET 2.0
One disadvantage of automatic transactions with serviced components is that these transactions always make use of the DTC, even when local transactions would be enough. Of course, using DTC is more expensive than a local programmatic transaction as was used in Listing 7-2.
With .NET 2.0, a new assembly System.Transactions will be available that includes some new classes dealing with transactions. Particularly worth mentioning are the classes Transaction, TransactionScope, and TransactionManager. These classes are in the namespace System.Transactions. The big advantage of these classes is that the new transaction services know about local and DTC transaction and will support the Web services standard WS-AtomicTransaction6 in the future. Depending on the scope of the transaction, the fastest possible technology is used.
Listing 7-11 shows one way to create transactions with .NET 2.0.7 Creating and disposing of a TransactionScope object defines a transactional code block. With the constructor of the TransactionScope object and the TransactionScope-Option enumeration, you can define whether a new transaction is required or whether a transaction that already exists from the outer block should be used. With the parameter of type EnterpriseSerivcesInteropOption, you can specify the interaction with COM+ contexts. The method Complete() indicates that all operations within the scope of the transaction have been successful. At the end of the using statement (where the Dispose() method gets called), the transaction outcome of the block is defined. If the Complete method was not called because an exception occurred, the transaction is aborted. If the scope of the transaction was successful, the transaction is committed if it is a root transaction. If the scope is not the root of the transaction, the outcome of the transaction is influenced.
Listing 7-11 Programming Transactions with .NET 2.0
using System; using System.Transactions; using Samples.Courses.Entities; using Samples.Courses.Data; class TxDemo { static void Main() { using (TransactionScope scope = new TransactionScope( TransactionScopeOption.Required)) { Course c = new Course(); c.Number = "MS-2557"; c.Title = ".NET Enterprise Services"; c.Active = true; CourseData db = new CourseData(connectionString); db.AddCourse(c); scope.Complete(); } }
With Indigo Services, you may declare transactions, as shown in Listing 7-12. This should look similar to the declarative transactions of the serviced components model. The attribute [OperationContract(TransactionFlowAllowed=true)] defines that a transaction is created. The attribute [OperationBehavior(Auto-EnlistTransaction=true)] defines that the transaction is automatically enlisted with the transaction coordinator.
Listing 7-12 Declaring Transactions with Indigo Services
[ServiceContract] [ServiceBehavior(InstanceMode=InstanceMode.PerCall)] public interface IDemoService { [OperationContract(TransactionFlowAllowed=true)] [OperationBehavior(AutoEnlistTransaction=true)] void AddCourse(Course course); } [BindingRequirements( TransactionFlowRequirements = RequirementsMode.Require, QueuedDeliveryRequirements = RequirementsMode.Disallow, RequireOrderedDelivery = true )] public class DemoService : IDemoService { public void AddCourse(Course course) { //... } }