Using TIP Transactions in Enterprise Services

As promised this entry will explain a bit about TIP Transactions and how to implement or use these from Enterprise Services.

First off, let me explain what the Transaction Internet Protocol (TIP) is all about. It is an application layer two-phase commit protocol to be used in heterogeneous and distributed transactional situations. You can read more in RFC 2371 and 2372 and on the W3C site here. It was expected to offer exactly what was needed to build the next generation of Internet applications, where distributed transactions across different Resource Managers (RM) from various vendors would be necessary. TIP differs from other two-phase commit protocols (2PC) in that it is very simple and is lightweight.

The general idea is that one transaction manager (TM) communicates to another TM to include work into an existing transaction, through a push or pull construction. This request is made by sending a TIP uniform resource locator (TIP URL) of a specific form to the subsidiary TM. They will then communicate through a different protocol to coordinate the outcome of the transaction.

The TIP URL includes the originating TM’s address and an string identifier/name for the existing transaction. It looks like this:

tip://<TM address>/<path>?<transaction string>

The TM address consists of a DNS name or IP-address (or NETBEUI computer name). There are several formats for the name of the transaction, but the Distributed Transaction Coordinator from Microsoft (MSDTC) uses an “OleTx-” prefixed transaction GUID. An example for a MSDTC TIP URL would be tip://killer-code2/?OleTx-2806bec0-2d09-4dd4-8a55-cb7539a7d817.

What does this mean to you as a Microsoft developer? It means that whenever an arbitrary (read: even non-MS, such as TMF/Pathway or ACMS) TM that supports TIP can initiate a transaction and request MSDTC to do work on RMs just by sending you a TIP URL, that identifies the running transaction. You will need to do some work to create a TIP transaction (which is like an ordinary 2PC MSDTC transaction) using the TIP URL. Alternatively, you can stream transactions to other arbitrary TMs by sending them the TIP URL that you compose for a running transaction. The TIP URL is send through any means that the receiving party acknowledges, which can be a TCP/IP or HTTP channel.

So, three questions arise:

  • What does this have to do with Enterprise Services (ES)/COM+?
  • When given a TIP URL, how do you create a MSDTC transaction?
  • How do you compose a TIP URL if you want to stream your MSDTC transaction to another TM?

Starting with the first question:

Enterprise Services has a lot to do with the MSDTC controlled transaction, as it uses the declarative programming model to make programming (distributed) transactions transparent. Being able to do TIP transactions from ES will save you a lot of low-level DTC programming and makes your life easier in general.

Getting the TIP URL in COM is done through the ITipTransaction interface. There is no managed equivalent, so we are stuck with making a COMImport of the interface or building a RCW by creating a COM reference to the appropriate dll. We’ll go for the first option:

[ComImport]
[Guid(“17CF72D0-BAC5-11d1-B1BF-00C04FC2F3EF”)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
publicinterface ITipTransaction
{
  void Push([MarshalAs(UnmanagedType.LPStr)] string remoteTmUrl,
      [MarshalAs(UnmanagedType.LPStr)] outstring remoteTxUrl);

  // Get TIP Transaction URL identifying transaction object
  // It is of form “tip://<tm-address>/<path>?<transaction identifier string>”.
  void GetTransactionUrl([MarshalAs(UnmanagedType.LPStr)] outstring localTxUrl);
}

and a helper class takes care of getting an interface reference:

publicclass TransactionHelper
{
  publicstatic ITipTransaction GetTipTransaction()
  {
    try
    {
      if (ContextUtil.IsInTransaction)
     
{
        return (ITipTransaction)ContextUtil.Transaction;
      }
      else
      {
        returnnull;
      }
    }
    catch(Exception ex)
    {
      System.Diagnostics.Trace.WriteLine(ex);
      returnnull;
    }
  }
}

Now it is easy-peasy to get the TIP URL from within a COM+/MSDTC initiated transaction. The TipTransactionDemo class is markes as a transaction requiring class.

[Transaction(TransactionOption.Required)]
[EventTrackingEnabled(true)]
publicclass TipTransactionDemo: ServicedComponent
{
  publicstring DoSomething()
  {
    ITipTransaction tipTran = TransactionHelper.GetTipTransaction();
    string txUrl;
    tipTran.GetTransactionUrl(out txUrl);
    System.Diagnostics.Debug.WriteLine(txUrl);

    // Do whatever you want with TIP URL
    
TipDemoWebService proxy = new TipDemoWebService();
    proxy.ContinueTipTransaction(txUrl);

  }
}

That answers question 2. Now on to question 3. Getting a TIP Transaction started will involve using the System.EnterpriseServices.ServiceConfig class in combination with System.EnterpriseServices.ServiceDomain (this was the reason of my previous post). ServiceDomain is the class that will allow you to use “Services without Components”, a COM+ 1.5 feature. Services without Components (SwC) means you can use COM+ Services without having a configured component. For Enterprise Services you will not need to have a strong-named assembly. When you enter a ServiceDomain, essentially you will get a COM+ ObjectContext provided to you, representing the desired contextual settings. These settings are indicated through an instance of the ServiceConfig class. This class has properties such as Transaction that allows you to set a TransactionOption, just as you would for a configured class.

Our link to a TIP transaction is the ServiceConfig.TipUrl property. By setting this property, COM+ will create a TIP transaction based on the TIP URL you provide. Here’s a sample from a ASMX Web Service TipDemoWebService class:

[WebMethod]
publicvoid ContinueTipTransaction(string tipUrl)
{
  ServiceConfig config = new ServiceConfig();
  config.TipUrl = tipUrl;
  ServiceDomain.Enter(config);
  ITransaction tran = (ITransaction)ContextUtil.Transaction;

  ContextUtil.SetAbort(); 

  TransactionStatus status = ServiceDomain.Leave();
  System.Diagnostics.Debug.WriteLine(status);
}

In this sample, the transaction is always aborted, so you can check if we were enlisted in the distributed transaction. Upon leaving the ServiceDomain COM+ will check client-side policies just as if a method call returns through a COM+ interceptor, meaning it will check (amongst other things) the happy and done flag. With the return value of type TransactionStatus you can check the outcome of your piece of the transaction.

So, what we did in this way was flow a transaction across a Web Service boundary. Great, isn’t it? Well, it is, but be cautious though. The TIP protocol requires a second TCP connection over port 3372 and all communication across this channel is unencrypted. Use a secure connection. Second, if you enlist a RM in a TIP transaction, it will remain locked until the initiating TM releases it. Think about deadlocks and Distributed Denial of Service attacks.

That being said, let me mention a very nice implementation by Clemens Vasters that is available through the newtelligence SDK. Take a look again at the samples I gave. Clemens has built a SOAP implementation where the TIP URL is embedded in the SOAP header automatically, whenever you set the attribute [TipTransaction] on a [WebMethod] marked Web Service method. Recommended stuff.

This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s