Section 7.3. Transaction Propagation


7.3. Transaction Propagation

WCF can propagate transactions across the service boundary. This enables a service to participate in the client's transaction, and for the client to include operations on multiple services in the same transaction. The client itself may or may not be a WCF service. Both the binding and the operation contract configuration control the decision whether or not the client transaction is propagated to the service. I call a transaction-aware binding any binding that is capable of propagating the client's transaction to the service if configured to do so. Not all bindings are transaction-aware; only the TCP-, IPC- and WS-related bindings are transaction-aware (those would be the NetTcpBinding, the NetNamedPipeBinding, the WSHttpBinding, the WSDualHttpBinding and the WSFederationHttpBinding, respectively).

7.3.1. Transaction Flow and Binding

By default, transaction-aware bindings do not propagate transactions. The reason is that like most everything else in WCF, it is an opt-in setting. The service host or administrator has to explicitly give its consent to accepting incoming transactions, potentially from across the organization or the business boundaries. To propagate a transaction, you must explicitly enable it at the binding on both the service host and the client sides. All transaction-aware bindings offer the Boolean property TRansactionFlow, such as:

 public class NetTcpBinding : Binding,... {    public bool TransactionFlow    {get;set;}    //More members } 

transactionFlow defaults to false.

To enable propagation, simply set this property to true, either programmatically or in the host config file; for example, in the case of the TCP binding:

 NetTcpBinding tcpBinding = new NetTcpBinding( ); tcpBinding.TransactionFlow = true; 

or when using a config file:

 <bindings>    <netTcpBinding>       <binding name = "TransactionalTCP"          transactionFlow = "true"       />    </netTcpBinding> </bindings> 

Note that the value of the TRansactionFlow property is not published in the service metadata. If you use Visual Studio 2005 or SvcUtil to generate the client config file, you will still need to manually enable or disable transaction flow as required.

Transactions and Reliability

Strictly speaking, transactions do not require reliable messaging. The reason is that when reliability is disabled, if the WCF messages are dropped or the client or service becomes disconnected, the transaction will abort. Because the client is guaranteed complete success or complete failure of the transactional operation, transactions are reliable in their own way. However, enabling reliability will decrease the likelihood of aborted transactions because it will make the communication reliable, and so the transaction will be unlikely to abort due to communication problems. I therefore recommend as a best practice when enabling transactions with NetTcpBinding and WSHttpBinding to also enable reliability:

 <netTcpBinding>    <binding name = "TransactionalTCP"                                   transactionFlow = "true">       <reliableSession enabled = "true"/>    </binding> </netTcpBinding> 

There is no need to enable reliability for the NetNamedPipeBinding and WSDualHttpBinding because, as discussed in Chapter 1, these two bindings are always reliable.


7.3.2. Transaction Flow and Operation Contract

Using a transaction-aware binding and even enabling transaction flow does not mean that the service wants to use the client's transaction in every operation, or that the client has a transaction to propagate in the first place. Such service-level decisions should be part of the contractual agreement between the client and the service. To that end, WCF provides the TRansactionFlowAttribute method attribute that controls if and when the client's transaction flows into the service:

 public enum TransactionFlowOption {    Allowed,    NotAllowed,    Mandatory } [AttributeUsage(AttributeTargets.Method)] public sealed class TransactionFlowAttribute : Attribute,IOperationBehavior {    public TransactionFlowAttribute(TransactionFlowOption flowOption); } 

Note that the transactionFlow attribute is a method-level attribute because WCF insists that the decision on transaction flow be made on a per-operation level, not at the service level.

 [ServiceContract] interface IMyContract {    [OperationContract]    [TransactionFlow(TransactionFlowOption.Allowed)]    void MyMethod(...); } 

This is deliberate, to enable the granularity of having some methods that use the client's transaction and some that do not.

The value of the transactionFlow attribute is included in the published metadata of the service, and so when you import a contract definition, the imported definition will contain the configured value. WCF will also let you apply the transactionFlow attribute directly on the service class implementing the operation:

 [ServiceContract] interface IMyContract {    [OperationContract]    void MyMethod(...); } class MyService : IMyContract {    [TransactionFlow(TransactionFlowOption.Allowed)]    public void MyMethod(...)    {...} } 

But such use is discouraged because it splits the definition of the logical service contract that will be published.

7.3.2.1. TransactionFlowOption.NotAllowed

When the operation is configured to disallow transaction flow, the client cannot propagate its transaction to the service. Even if transaction flow is enabled at the binding and the client has a transaction, it will be silently ignored and not propagate to the service. As a result, the service will never use the client's transaction, and the service and the client can select any binding with any configuration. transactionFlowOption.NotAllowed is the default value of the transactionFlowOption attribute, so these two definitions are equivalent:

 [ServiceContract] interface IMyContract {    [OperationContract]    void MyMethod(...); } [ServiceContract] interface IMyContract {    [OperationContract]    [TransactionFlow(TransactionFlowOption.NotAllowed)]    void MyMethod(...); } 

7.3.2.2. TransactionFlowOption.Allowed

When the operation is configured to allow transaction flow by providing transactionFlowOption.Allowed to the transactionFlowOption attribute, if the client has a transaction, the service will allow the client's transaction to flow across the service boundary. However, the service may or may not use the client's transaction even though it was propagated. When you choose TRansactionFlowOption.Allowed, the service can be configured to use any binding, be it transaction-aware or not, but the client and the service must be compatible in their binding configuration. In the context of transaction flow, compatible means that when the service operation allows transaction flow but the binding disallows it, the client should also disallow it in the binding on its side. Trying to flow the client transaction will cause an error because the transaction information in the message will not be understood by the service. However, when the service-side binding configuration is set to allow transaction flow, the client may or may not want to enable propagation on its side, and so may elect to set transactionFlow to false in the binding even if the service has it set to TRue.

7.3.2.3. TransactionFlowOption.Mandatory

When the operation is configured for TRansactionFlowOption.Mandatory, the service and client must use a transaction-aware binding with transaction flow enabled. WCF verifies this requirement at the service load time and throws an InvalidOperationException if the service has at least one incompatible endpoint. transactionFlowOption.Mandatory means the client must have a transaction to propagate to the service. Trying to call a service operation without a transaction throws a FaultException on the client side stating that the service requires a transaction. With mandatory flow, the client's transaction always propagates to the service. Yet again, the service may or may not use the client's transaction.

7.3.3. One-Way Calls

Propagating the client transaction to the service requires, by its very nature, allowing the service to abort the client transaction if so desired. This implies that you cannot flow the client transaction to a service over a one-way operation, because that call does not have a reply message. WCF validates this at the service load time, and will throw an exception when a one-way operation is configured for anything but TRansactionFlowOption.NotAllowed.

 //Invalid definition: [ServiceContract] interface IMyContract {    [OperationContract(IsOneWay = true)]    [TransactionFlow(TransactionFlowOption.Allowed)]    void MyMethod(...); } 




Programming WCF Services
Programming WCF Services
ISBN: 0596526997
EAN: 2147483647
Year: 2004
Pages: 148
Authors: Juval Lowy

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