Distributed Transactions with Indigo and WS-AT
This evening I played with Indigo and WS-AT, to see if it works, in order to use it in a project of a customer of mine.
First of all the good news: it works :-) as it did in PDC03 bits! Great job guys!
Second news: it's not so easy to manage all the stuff, but at least it works fine.
I developed two different services, working on a couple of SQL Server 2005 database.
One service is exposed using a net.tcp (netProfileTcpBinding) binding. The other is exposed using http (wsProfileBinding), self-hosted.
Both are used by a third party client, that covers the transactional work with a TransactionScope.
Here is a sample of one of the two transactional services:
namespace ServiceOne
{
[ServiceContract(
FormatMode=ContractFormatMode.XmlFormatter,
Namespace="http://schemas.devleap.com/Services/OrderService1",
Style=ServiceOperationStyle.DocumentBare,
Use=ServiceOperationBindingUse.Literal)]
[BindingRequirements(
TransactionFlowRequirements = RequirementsMode.Require)]
public interface ITxServiceOne
{
[OperationContract(
Action="urn:saveOrder1")]
Int32 SaveOrder(OrdersLibrary.Order order);
}
[ServiceBehavior(
AllowConcurrentTransactions=true,
TransactionIsolationLevel=IsolationLevel.ReadCommitted)]
public class TxServiceOne: ITxServiceOne
{
[OperationBehaviorAttribute(
AutoEnlistTransaction = true,
AutoCompleteTransaction = true)]
public int SaveOrder(OrdersLibrary.Order order)
{
OrdersLibrary.OrderBiz ob = new OrdersLibrary.OrderBiz();
return (ob.SaveOrder(order));
}
}
}
Take care of BindingRequirements and OperationBehavior attributes, respectively on the service contract and on the operation implementation.
Here is the service side configuration file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<appSettings>
<add key="SqlConnectionString" value="..."/>
</appSettings>
<system.serviceModel>
<services>
<service
serviceType="ServiceOne.TxServiceOne, ServiceOne"
behaviorConfiguration="txServiceBehavior">
<endpoint
contractType="ServiceOne.ITxServiceOne, ServiceOne"
address="http://localhost:35000/TxServiceOne.svc"
bindingConfiguration="txBinding"
bindingSectionName="wsProfileBinding" />
</service>
</services>
<bindings>
<wsProfileBinding>
<binding configurationName="txBinding" flowTransactions="Required" />
</wsProfileBinding>
</bindings>
<behaviors>
<behavior
configurationName="txServiceBehavior"
returnUnknownExceptionsAsFaults="true" >
</behavior>
</behaviors>
</system.serviceModel>
</configuration>
Pay attention to the behaviors section, where I declare to manage any exception as a Fault.
Take a look also at the custom binding configuration, defined in order to require transactions.
The other service is very similar to the first one.
Lastly here is the main part of client code:
schemas.devleap.com.EntitiesOrder.Order order = new schemas.devleap.com.EntitiesOrder.Order();
order.id = 10;
order.description = "Order 10";
TransactionOptions options = new TransactionOptions();
options.IsolationLevel = IsolationLevel.ReadCommitted;
options.Timeout = TimeSpan.FromSeconds(30);
using(TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, options))
{
TxServiceOneProxy svcOne = null;
TxServiceTwoProxy svcTwo = null;
try
{
// External transactional activity
svcOne = new TxServiceOneProxy();
Console.WriteLine("Service One: {0}", svcOne.SaveOrder(order));
try
{
// Internal transactional activity
svcTwo = new TxServiceTwoProxy();
Console.WriteLine("Service Two: {0}", svcTwo.SaveOrder(order));
// Transaction commit, in case of success
scope.Complete();
}
finally
{
// Internal channel closing
svcTwo.Close();
}
}
finally
{
// External channel closing
svcOne.Close();
}
}
Here you can find all the code of the demo solution I developed to test WS-AT support in Indigo.
In order to make it work, don't forget to download this fix (published on 21/06/2005):
I hope you'll enjoy your Indigo transactional experience :-) !