Transactions Made Simple with Windows Communication Foundation

he ACME Toothpick Company has a problem: their applications do not communicate. The toothpick making process is causing big headaches for the purchasing and sales departments. The problem stems from the way toothpicks are manufactured. First, a log is selected from inventory and fed into the toothpick maker. Approximately three minutes later, a brand new toothpick emerges. The left over wood is sent offsite for a separate project.

There are two applications involved in the log making process: the Log Inventory Manager (LIM) and the Toothpick Manufacturing Manager (TMM). Unfortunately for ACME, LIM and TMM do not communicate.

First, an employee goes into LIM and removes a log from the inventory. Then the employee logs into TMM to start the manufacturing process. Problems occur when the toothpick machine is ordered to build a new toothpick, but finds that there are no logs left in inventory. Other times, the employee finds that the toothpick machine is broken but the log was removed from inventory. Together, these issues caused an inaccurate log inventory. The purchasing department has no idea how many logs they need to order or how many logs they actually have in inventory. In addition, the sales department has no idea how many toothpicks they have available to sell to customers (see Figure 1).

?
Figure 1. ACME’s Current Process: An ACME employee has to manually update both systems and hope everything works out.

The ACME IT Department decides to use web services to solve their business problem. A new application is constructed to control toothpick production and coordinate efforts between the toothpick building machine and the log inventory manager. The key challenge is ensuring the toothpick manufacturing and the log inventory stay synchronized. Web services alone are not an adequate solution to this problem because ACME needs to use transactions. The good news for ACME is that both LIM and TMM were built using the Microsoft .NET platform. The Windows Communication Foundation (WCF), with its built-in support for transactions, is the best choice.

Before discussing the details of how transactions are implemented in WCF, it makes sense to say a few words about transactions. A transaction is defined as a unit of work that is atomic, consistent, isolated, and durable. Together, these four qualities form the acronym ACID (see Figure 2). :

  • Atomic means that after a transaction completes, either all the changes are successful or they are all undone. The data is not left in a state where only a portion of the changes is complete.
  • In addition, the database is always in a consistent state. Whether a transaction completes or fails, the data must be in a proper state.
  • Isolated refers to the fact that transactions cannot see changes happening in another transaction while they are in process. In other words, transactions only see the before and the after, not during.
  • Finally, durable means that after a transaction successfully completes, the changes remain.

Together, these four ACID qualities ensure the log inventory and toothpick manufacturing process work together and guarantee ACME accurate data.

?
Figure 2. ACME’s Proposed System: An ACME Employee interacts with a single system and a WCF transaction ensured the accuracy of the data.

The first task for ACME developers is to expose the functionality in the LIM and TMM applications as WCF based services. The starting point for any WCF service is the contract. Below is the listing for the LIM service contract:

[ServiceContract]public interface ILogManager{    [OperationContract]    int GetCurrentInventory();    [OperationContract]    [TransactionFlow(TransactionFlowOption.Mandatory)]    void SubtractInventory(int amount);    [OperationContract]    [TransactionFlow(TransactionFlowOption.Allowed)]    void AddInventory(int amount);}

The key attribute is TransactionFlow. The TransactionFlow attribute informs the WCF runtime how it should behave with respect to transactions flowed from the caller. The available options are:

  • Mandatory: The caller must flow a transaction.
  • Allowed: The caller may flow a transaction.
  • NotAllowed: The caller cannot flow a transaction.

The ILogManager interface uses both the Mandatory and Allowed options on the SubtractInventory and AddInventory operations, respectively. What this means from an implementation perspective is that a caller to the SubtractInventory operation must flow a transaction while a transaction is optional for callers to the AddInventory operation. Understand that the TransactionFlow attribute does not control how the service operations will actually use the flowed transaction; it simply defines what the service caller may or may not do. As you will see, you control participation in a transaction at the service implementation level.

After you define the contract, you can create the actual service implementation (see Listing 1).

At the service implementation level, attributes control the transactions. For example, the ServiceBehavior attribute offers a TransactionIsolationLevel property that you can use to set the isolation level. In this case, the default of Unspecified is used. The TransactionAutoCompleteOnSessionClose is used to indicate whether the transaction should complete if the session ends and no errors have occurred. Again, in this case, the default of false is used. A final property, TransactionTimeout, is available to set a timeout for active transactions but not used here.

At the service operation level, the OperationBehavior attribute has two key properties: TransactionAutocomplete indicates that a transaction should automatically complete if the operation completes without error. The TransactionScopeRequired property tells WCF whether or not this particular operation must be run within the scope of a transaction. A transaction may be flowed from the caller or created specifically for an operation.

The combination of TransactionFlow and TransactionScopeRequired can be confusing. The following table should provide clarity:

Table 1. Combining Attributes: This table helps with clarification.
TransactionFlow TransactionScopeRequired Uses Flowed Transaction from Caller Result
Mandatory True Yes Uses Flowed Transaction
Allowed True Yes Uses Flowed Transaction
NotAllowed True Yes Throws Exception
Mandatory False Yes No transaction used
Allowed False Yes No transaction used
NotAllowed False Yes Throws Exception
Mandatory True No Throws Exception
Allowed True No A new transaction is created for the operation
NotAllowed True No A new transaction is created for the operation
Mandatory False No Throws Exception
Allowed False No Uses No Transaction
NotAllowed False No Uses No Transaction

Note that in cases where TransactionFlow is set to NotAllowed, an attempt to flow a transaction will result in an error. At first it may seem counterintuitive to allow a transaction to be flowed to a service operation that will not perform its operation within that transaction but, this capability can be quite useful. A transaction that does not utilize a flowed transaction can still vote on the outcome of the transaction. What this means is that operations can help determine the outcome of a transaction even if they themselves are not transactional.

The final step is to update the application configuration file for the service. Specifically, the Bindings element needs to be updated.

        

In this case, use the wsHttpBinding and tell it to allow transactions to flow via the transactionFlow attribute. The default value for this attribute is false, so it must be explicitly set to true.

After the service for LIM completes, the same pattern is followed for the TMM service (see Listing 2).

The ConstructAToothpick operation utilizes the Mandatory setting to require a flowed transaction. Also notice that the ConstructAToothpick operation throws an exception, indicating that the machine is broken. The act of throwing the exception causes the transaction to fail. In the actual production code, the TMM API would be called.The final phase in the development process is to create the new ACME Manufacturing Manager (AMM) application. The AMM is a Windows Forms application with references to both the LIM and TMM services created previously (see Listing 3).

Recall that the two services require the caller to flow a transaction. To that end, the client code creates an instance of TransactionScope within a using block. All service calls executed within that using block will have the transaction flowed to them. Also note that the client explicitly completes the transaction by calling the Complete method.

The TransactionCompleted event handler was added here simply for illustrative purposes. It is not required.

While the process appears involved, further examination reveals only five steps were performed:

  1. Add a TransactionFlow attribute to the service contract.
  2. Add a ServiceBehavior attribute to the service implementations.
  3. Add an OperationBehavior attribute to the operation implementations.
  4. Update the Bindings element in the configuration file.
  5. Add basic transaction code to the service client.

Notice that most of the steps involved adding attributes and not writing new code. In this way, WCF abstracts the actual service implementation away from its transactional behavior.

The rollout of the new ACME Manufacturing Manager application was a resounding success. Now purchasing knows exactly how many logs are in inventory and sales knows exactly how many toothpicks are available. Thanks to WCF and its built-in support for transactions, IT built the application in record time. The savings from the new application allowed ACME to purchase a chopstick-manufacturing machine. Of course, the Chopstick Manufacturing Manager runs on a different platform. Thanks to the foresight of IT, ACME’s new machine will be talking to its other systems right away.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

Recent Articles: