In this article i will touch on the areas that need to be configured for transactions in WCF. I will also discuss the attributes and attempt to explain how each one might affect the other.
So lets start, what is transaction?
In computer programming, a transaction usually means a sequence of information exchange and related work (such as database updating) that is treated as a unit for the purposes of satisfying a request and for ensuring database integrity.
Definition from searchcio.techtarget.com
If you are lucky enough to have an architect in your team taking care of your SOA solution, he should be providing the engineers on the team with a diagram similar to this. The diagram is part of a much bigger design for a SOA solution that i work on.
The diagram looks simplistic but it communicates to the engineer which components form part of the use case, the dependencies between the components, the exchange pattern and the transaction boundaries. The key thing to notice in the diagram above is the red squares which indicates the transaction boundaries. From this diagram one can observe which components are taking part in a diagram and which run within their own transactions.
Right, back to software engineering and the actual implementation of the transactions.
Choosing a binding.
The solid lines in the diagram above between the client (website) and the service (community) indicates that we are using a request response pattern here which will be something like Http, net.pipe or net.tcp. Normally the decision for the binding would have been decided long before the engineer needs to implement the service class.
Not all bindings support transactions. For example the BasicHttpBinding does not support Transaction flow.
In this example i am using the net.tcp binding which supports request response and transactions over boundaries.
Transactions over process boundaries are achieved through something called a transaction manager like DTC (Distributed Transaction Coordinator ) but there are other manager types.
Configuring WCF for services.
The following areas need to be configured.
- The binding configuration. – Transaction Flow
- The service & client endpoint.
- The service contract. – Transaction Isolation Level
- The operation contract. – TransactionFlow
- The operation implementation in the service class. – TransactionAutoComplete & TransactionScopeRequired
The binding configuration
As discussed under the binding heading. We need a binding that supports transaction flow. Transaction Flow allows a transaction to be flown over a boundary like a network and to continue within the other process.
In the image above you can see how easy it is not enable transactionFlow. Note that I am using a named binding called “netTcp” as i did not want transactions enabled on all my tcp bindings. To enabled transactions on all tcp bindings, simply omit the named attribute from the configuration.
Although a binding might support transaction flow, if it is not explicitly enabled the binding will not flow a transaction even if the operation contract on the service defines that it is allowing transaction flowing.
The client and service will each need its own defined binding configuration.
The service and client endpoint
The service endpoint as the name suggests is exposed by the service. If the service is not configured for a transaction then nothing the client does can make it take part in the transaction.
The images above of the client & service endpoints are very small due to it being very wide, but there are two thing to take note of in relation to transactions.
- Make sure the endpoint is using the correct binding type.
- Make sure that the bindingConfiguration element has the same name as the defined binding configuration.
Remember that one service might be a client to another, so the configuration needs to be done on those client endpoints as well.
The service contract
The service contract is where the transaction isolation level must be specified. If one does not specify it the default will apply. The default transaction isolation level is Unspecified.
When unspecified is used the service will automatically use the transaction isolation level of the transaction that flowing in from the client. If the transaction scope (to be discussed later) is set to required and there is no transaction coming from the client transaction isolation level of serialized will be used.
Normally the transaction isolation level will be decided upfront my the architect.
The operation contract
Service Operations need to opt-in to be part of a client transaction. They do this by specifying if they will allow a client transaction to be flowed into itself. This is done by adding a TransactionFlow attribute to the operation contract.
There are 3 possible options for transaction flow on a operation.
- Allowed – A operation will take part in a client transaction if one exists.
- Mandatory – The operation specifies that it requires a a transaction to be flowed in. If no transaction exists a service exception will be thrown. This will also happen if the endpoint are not configured for transaction flow.
- NotAllowed – This is the default. The operation will not take part in the transaction all data read and set from this point on will be outside the transaction.
Note that when transaction flow is enabled the client and service need to be using compatible transaction isolation levels otherwise a not supported exception will occur.
The operation implementation
The operation implementation is where two additional attributes need to be defined for transactions.
- TransactionScopeRequired – If TransactionScopeRequired is set to true the operation will automatically create a new transaction if it is not already part of one.The transaction scope attribute indicates if the operation must have a transaction where transaction flow indicates if it will be allowed as part of a client transaction.
- TransactionAutoComplete – TransactionAutoComplete is enabled by default. It is used by the voting process in WCF to determine if a transaction has completed or not.TransactionAutoComplete can only work if TransactionScopeRequired is set to true.
I hope that this will assist someone. WCF has lots of “knobs” to turn and is very powerful but it is important to understand how all the settings work and related to one another.