|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionMicrosoft has released its first WinFx CTP with Indigo, which includes the much anticipated support for Distributed Transaction (WS-Atomic Transaction). In this article, I will write some very simple C# code to illustrate the concept of Distributed Transaction in Indigo. The only requirements for running the sample application is to download and install the WinFx CTP onto Windows XP with SP2, no need for Visual Studio. NET 2005 Beta. I hope this will help you to understand the semantics of transaction programming and how you can leverage Transaction Model in dealing with common business problems. Transaction CodeMost developers are familiar with database transaction code as illustrated in the following code segment: void DoLocalDBTransaction(int OrderID)
{
System.Configuration.AppSettingsReader reader =
new System.Configuration.AppSettingsReader();
string cnstr =
reader.GetValue("ConnectionString",typeof(string)).ToString();
SqlConnection cn = new SqlConnection(cnstr);
cn.Open((new SqlCommand("update orders set orderDate='" +
DateTime.Now.ToString() + "' where OrderID=" + OrderID.ToString());
cn.ExecuteNonQuery();
cn.Close();
}
This type of transaction code can be found in local executables as well as in a WebMethod of a remote WebService. Interesting scenarios arise when multiple calls to this function are made: what if the first call succeeds and last call to the function fails, resulting in partial update of the database? The standard solution in the .NET 1.1 Framework is to use COM+ or ADO.NET transaction support to rollback. But if one of the transactions is executed through a call to a remote Web Service, then the rollback will not happen since COM+ and ADO.NET cannot run on SOAP/HTTP. This is where the .NET framework 2.0 Basic Model of Distributed TransactionWS-Atomic Transaction is a very simple but elegant idea as depicted in the following diagram:
This diagram illustrates several key elements of WS-Atomic Transaction (also known as WS-AT):
This is just a high level simplified model of WS-AT transaction specification. Let us now take a look at some code. WS-AT CoordinatorCoordinator can be represented by using (TransactionScope scope = new TransactionScope())
{
DoLocalDBTransaction(10248);
DoWSDBTransaction(10249);
DoWSNonDBTransaction(CustomerID);
scope.Complete();
}
We already saw code for local database transaction in the Introduction. And here are the codes for the other two functions: void DoWSDBTransaction(int OrderID)
{
EndpointAddress address =
new EndpointAddress("http://localhost/TransactionalWS/Service.svc");
WSProfileBinding binding = new WSProfileBinding();
binding.FlowTransactions = ContextFlowOption.Required;
TransactionalWebServiceProxy proxy =
new TransactionalWebServiceProxy(address, binding);
proxy.NewInnerProxy.DoDBTransaction(OrderID);
}void DoWSNonDBTransaction(int CustomerID)
{
EndpointAddress address =
new EndpointAddress("http://localhost/TransactionalWS/Service.svc");
WSProfileBinding binding = new WSProfileBinding();
binding.FlowTransactions = ContextFlowOption.Required;
TransactionalWebServiceProxy proxy =
new TransactionalWebServiceProxy(address, binding);
proxy.NewInnerProxy.DoNonDBTransaction(CustomerID);
}
Just as ASMX web services model, Indigo still uses Proxy/Stub Network communication architecture and here is the Indigo Proxy code generated by the svcutil.exe tool first and then manually changed: class TransactionalWebServiceProxy :
ProxyBase<ITransactionalWebService><ITRANSACTIONALWEBSERVICE>
{
public TransactionalWebServiceProxy(
EndpointAddress address, WSProfileBinding binding)
: base(address, binding)
{
}
public ITransactionalWebService NewInnerProxy
{
get { return InnerProxy; }
}
}
where public interface ITransactionalWebService
{
[OperationContract()]
void DoDBTransaction( int OrderID);
[OperationContract()]
void DoNonDBTransaction(int CustomerID);
}
These are boiler-template code to “get on Indigo Messaging Bus”, much like adding Web Reference in VS.NET 2003. In essence, we are building an Indigo Communication by establishing a proxy and flowing Context through it. Still there are some interesting details about Indigo Messaging bus for network communication and we will now take a look at it. Indigo ABCA stands for Address, B stands for Binding and C is standard for Contract. To establish an Indigo communication, we must take care of ABC on both ends of the communication. For IndigoABC on the physical machine 1 where the Transaction Coordinator resides, we have seen the following code above: EndpointAddress address =
new EndpointAddress("http://localhost/TransactionalWS/Service.svc");
WSProfileBinding binding = new WSProfileBinding();
binding.FlowTransactions = ContextFlowOption.Required;
TransactionalWebServiceProxy proxy =
new TransactionalWebServiceProxy(address, binding);
proxy.NewInnerProxy.DoNonDBTransaction(CustomerID);
Here A is http://localhost/TransactionalWS/Service.svc; B is To take care of IndigoABC on physical machine 2, I used VS.NET 2005 Feb CTP Indigo Service Project template to generate a special Web virtual directory “TransactionalWS” with one sub directory “App_Code” and three files: \TransactionalWS
\App_Code
Service.cs
Service.svc
Web.Config
The content of Service.svc is similar to that of Service.asmx: <%@ Service Language="C#"
CodeBehind="~/App_Code/Service.cs" Class="MyService" %>
Service.cs is the code-behind file: [ServiceContract()]
public interface ITransactionalWebService
{
[OperationContract]
[OperationBehavior(AutoCompleteTransaction =true,AutoEnlistTransaction =true)]
void DoDBTransaction(int OrderID);
[OperationContract]
[OperationBehavior(AutoCompleteTransaction = true, AutoEnlistTransaction = true)]
void DoNonDBTransaction(int CustomerID);
}
public class MyService : ITransactionalWebService
{
public void DoDBTransaction(int OrderID) {...}
public void DoNonDBTransaction(int CustomerID) { ….}
}
Web.Config has the following content: <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<system.serviceModel>
<services>
<service serviceType="MyService">
<endpoint contractType="ITransactionalWebService"
bindingSectionName="wsProfileBinding"
bindingConfiguration="wsProfileConfig"/>
</service>
</services>
<behaviors>
<behavior configurationName="" returnUnknownExceptionsAsFaults="true" />
</behaviors>
<bindings>
<wsProfileBinding>
<binding flowTransactions="Required" configurationName="wsProfileConfig"/>
</wsProfileBinding>
</bindings>
</system.serviceModel>
</configuration>
Here A is the virtual directory address http://localhost/TransactionWS/Service.svc; B is Ideally, I would like to also use code rather than configuration on the Indigo Transaction Web Services end of the sample application. But I could not get it to work stably using the other host (such as console, Windows services). So I decided to stay with hosting the Indigo Service inside such a Web Directory structure. Future releases of Indigo will un-doubtfully allow WS-AT in any other type of hosts. You may have noticed two modifications of “behaviors” for Indigo Web Service. [OperationBehavior(AutoCompleteTransaction = true, AutoEnlistTransaction = true)]
<behavior configurationName="" returnUnknownExceptionsAsFaults="true" />
And let us discuss these behavior changes briefly. AutoCompleteTransaction= true or falseA participating transactional WebService can impact the Coordinator in one of the four ways:
Here is the C# code representing the above four scenarios: public void DoNonDBTransaction(int CustomerID)
{
switch (CustomerID)
{
case 1:
OperationContext.Current.SetTransactionComplete();
break;
case 2:
System.Transactions.Transaction.Current.Rollback(new
Exception("Customer has bad credit"));
break;
case 3:
throw new Exception("Unknown exception" +
" for CustomerID=3 and converted into fault");
break;
default:
// refrain from vote, customer has unknown credit.
// In this case, transaction complete or abort depend on
// AutoCompleteTransaction= true or false.
break;
}
Obviously, the Coordinator has to know if the participant voted complete or rolled back before it made the final decision. And this is where
For example, if we are calling a credit report web service inside a loan transaction context, a customer with no credit (because the credit report Web Service cannot decide), can be either a good customer getting loan or a bad customer not getting loan, depending on our judgment of risk versus revenue. Bottom line, setting It is interesting to know that Rollback actually throws a known exception and Indigo actually allows How to set up and run the sample code
Warning: Since this is pre-beta software, there could be abnormal behavior for sample code. For example, I have experienced sudden break-down of the sample and had to re-build the Web Directory, re-start IIS/DTC etc. Also, future releases of CTP or Beta may break the code. ConclusionIndigo transaction programming is relative simple and straightforward, if we spend enough time to understand the basics of WS-AT model. Hope this article and included sample code proved just that.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||