Was this page helpful?
Your feedback about this content is important. Let us know what you think.
Additional feedback?
1500 characters remaining
Export (0) Print
Expand All

Walkthrough: Creating a Message Queue Transaction with COM+ Services

Visual Studio .NET 2003

This walkthrough creates a transaction supported by COM+ Services by using the ServicedComponent class. The walkthrough creates two transactional queues and moves data between them in a transaction hosted by Enterprise Services (COM+ Services). For an overview of Enterprise Services see Writing Serviced Components.

Note   You must install the Message Queuing components of your operating system to complete this walkthrough.

The first step in using a COM+ transaction service is to create a class that derives from the ServicedComponent class, found in the System.EnterpriseServices namespace. The ServicedComponent class is the base class used to create components that are hosted by COM+.

To create the ServicedComponent Class

  1. Create a class library project. Name it TransactionComponent.
  2. Add references to System.Messaging.dll and System.EnterpriseServices.
  3. Replace Class1 with the class below.
    • The TransactionAttribute on the class directs the Distributed Transaction Coordinator to create a context for the object.
    • Classes derived from ServicedComponent must have a public default (parameterless) constructor.
    • Fields are added for the source and destination queues. These are exposed as properties, because the constructor cannot take parameters.
    • The AutoComplete attribute on the Move method indicates that at the end of the method, the component's vote towards the transaction is based on failure or success of this method. The method fails if an exception is thrown. If the method succeeds, the ContextUtil.SetComplete Method is called. For more information, see AutoCompleteAttribute Class and Voting in an Automatic Transaction.
      ' Visual Basic
      <System.EnterpriseServices.TransactionAttribute( _
      System.EnterpriseServices.TransactionOption.Required)> _
      Public Class MessageMover
          Inherits System.EnterpriseServices.ServicedComponent
      
          Private sourceQueue As System.Messaging.MessageQueue
          Private destinationQueue As System.Messaging.MessageQueue
      
          Public Sub New()
          End Sub
      
          Public Property Source() As System.Messaging.MessageQueue
              Get
                  Return sourceQueue
              End Get
              Set(ByVal Value As System.Messaging.MessageQueue)
                  sourceQueue = Value
              End Set
          End Property
      
          Public Property Destination() As System.Messaging.MessageQueue
              Get
                  Return destinationQueue
              End Get
              Set(ByVal Value As System.Messaging.MessageQueue)
                  destinationQueue = Value
              End Set
          End Property
      
          <System.EnterpriseServices.AutoComplete()> _
          Public Sub Move()
              Dim sourceMessage As System.Messaging.Message
              sourceMessage = sourceQueue.Receive( _
                  System.Messaging.MessageQueueTransactionType.Automatic)
              destinationQueue.Send(sourceMessage, _
                  System.Messaging.MessageQueueTransactionType.Automatic)
          End Sub
      End Class
      
      // C#
      [System.EnterpriseServices.TransactionAttribute( 
      System.EnterpriseServices.TransactionOption.Required)]
      public class MessageMover : System.EnterpriseServices.ServicedComponent
      {
         private System.Messaging.MessageQueue sourceQueue;
         private System.Messaging.MessageQueue destinationQueue;
         public MessageMover()
         {
         }
      
         public System.Messaging.MessageQueue Source 
         {
            get 
            {
               return sourceQueue;
            }
            set
            {
               sourceQueue = value;
            }
         }
         public System.Messaging.MessageQueue Destination
         {
            get 
            {
               return destinationQueue;
            }
            set
            {
               destinationQueue = value;
            }
         }
         [System.EnterpriseServices.AutoComplete()]
         public void Move()
         {
            System.Messaging.Message sourceMessage;
            sourceMessage = sourceQueue.Receive(
               System.Messaging.MessageQueueTransactionType.Automatic);
            destinationQueue.Send(sourceMessage,
               System.Messaging.MessageQueueTransactionType.Automatic);
         }
      }
      

To be hosted by COM+, components must have a strong name. The following procedure describes how to create a key file and use it to apply a strong name to the class library.

To give the class a strong name

  1. Locate the Strong Name Tool (Sn.exe) and run it to create a key file, key.snk, in the project directory. The command looks something like this:
    sn –k ProjectDirectory\key.snk
    
  2. In Solution Explorer, double-click AssemblyInfo.vb or AssemblyInfo.cs, depending on the language you are using. Add or replace the attributes for AssemblyDelaySign, AssemblyKeyFile, and AssemblyKeyName. The file location for the key file is given relative to the build location. You will need to confirm that the path is correct for your project configuration. For more information on the interaction of these three attributes, see Global Attributes.
    ' Visual Basic
    <Assembly: AssemblyDelaySign(False)> 
    <Assembly: AssemblyKeyFile("..\..\key.snk")> 
    <Assembly: AssemblyKeyName("")>
    // C#
    [assembly: AssemblyDelaySign(false)]
    [assembly: AssemblyKeyFile("..\\..\\key.snk")]
    [assembly: AssemblyKeyName("")]
    
  3. Build the application to create the DLL.
  4. Now that the assembly has a strong name, it can be registered with COM+. The .NET Framework includes a tool for registering serviced components.

To register the component with COM+

  1. Locate the .NET Services Installation Tool (Regsvcs.exe), located in the .NET Framework installation folder. The .NET Framework is installed in the operating system folder, not in the Program Files folder.
  2. Run the tool to register TransactionComponent.dll. The command looks something like this:
    regsvcs c:\DllPath\TransactionComponent.dll
    
    Note   The registration tool may report that "The class TransactionComponent.MessageMover has no class interface, which means that unmanaged late bound calls cannot take advantage of AutoComplete methods." The message is a warning that because the component does not implement an interface, you will not be able to use the component in a late-bound call, such as if you were using VBScript. The component will work in this walkthrough.

You can use the Component Services tool to see the COM+ component you created.

To verify the results with Component Services

  1. Open Control Panel.
  2. Double-click the Administrative Tools icon.
  3. Open Component Services.
  4. Double-click the Component Services node under the Console Root to expand it.
  5. Expand the Computers node.
  6. Expand the My Computer node.
  7. Expand the COM+ Applications node.
  8. Find the TransactionComponent entry. Its presence verifies that the component is registered with Component Services. When you create an instance of TransactionComponent, it will be hosted in a COM+ Services context. The code executed (the ProcessOrder method) will run in the managed space, but the context (which tracks the success or failure of the transaction) will be maintained by COM+ Services.

The client application will be a Windows Form with code that is able to create and delete a message queue. The application will include two methods that use the COM+ transaction. The first will be a successful transaction. The second will be coded so that the transaction fails. This will allow you to experiment with the exception-handling features of COM+.

To create the client application

  1. Add a new Windows Application project to the solution. Name it MessageMoverClient.
  2. Add a reference to the TransactionComponent project. To use the .NET serviced component, you add a reference to the DLL and instantiate the class.
  3. Add references to System.Messaging.dll and System.EnterpriseServices.
  4. Add a button to the form. Name the button moveSucceeds and set the Text property to Succeed. This button will execute code that successfully moves a new message from one queue to another in a complete transaction.
  5. Create the Click event handler for the moveSucceeds button and add the code below to the method.
    Note   This code creates and deletes message queues named SourceQueue and DestinationQueue. If these queues already exist on your computer, they may be deleted in the course of this walkthrough. Use the Computer Management application in the Control Panel item named Administrative Tools to look for these queues. See Step 7 below, for information on using the Computer Management application to examine message queues.
    ' Visual Basic
    Dim mover As New TransactionComponent.MessageMover
    Dim sourcePath As String = ".\SourceQueue"
    Dim destinationPath As String = ".\DestinationQueue"
    
    If System.Messaging.MessageQueue.Exists(sourcePath) Then
        Dim queue As New System.Messaging.MessageQueue(sourcePath)
        If (Not queue.Transactional) Then
            System.Messaging.MessageQueue.Delete(sourcePath)
            System.Messaging.MessageQueue.Create(sourcePath, True)
        End If
    Else
        System.Messaging.MessageQueue.Create(sourcePath, True)
    End If
    
    If System.Messaging.MessageQueue.Exists(destinationPath) Then
        Dim queue As New System.Messaging.MessageQueue(destinationPath)
        If (Not queue.Transactional) Then
            System.Messaging.MessageQueue.Delete(destinationPath)
            System.Messaging.MessageQueue.Create(destinationPath, True)
        End If
    
    Else
        System.Messaging.MessageQueue.Create(destinationPath, True)
    End If
    
    mover.Source = New System.Messaging.MessageQueue(sourcePath)
    mover.Destination = New System.Messaging.MessageQueue(destinationPath)
    
    mover.Source.Send("some message", System.Messaging.MessageQueueTransactionType.Single)
    mover.Move()
    
    MessageBox.Show("Move complete.")
    
    // C#
    TransactionComponent.MessageMover mover;
    mover = new TransactionComponent.MessageMover();
    string sourcePath = ".\\SourceQueue";
    string destinationPath = ".\\DestinationQueue";
    
    if (System.Messaging.MessageQueue.Exists(sourcePath)) 
    {
       System.Messaging.MessageQueue queue = new System.Messaging.MessageQueue(sourcePath);
       if (!queue.Transactional) 
       {
          System.Messaging.MessageQueue.Delete(sourcePath);
          System.Messaging.MessageQueue.Create(sourcePath, true);
       }
    }
    else 
    {
       System.Messaging.MessageQueue.Create(sourcePath, true);
    }
    
    if (System.Messaging.MessageQueue.Exists(destinationPath)) 
    {
       System.Messaging.MessageQueue queue = new System.Messaging.MessageQueue(destinationPath);
       if (!queue.Transactional) 
       {
          System.Messaging.MessageQueue.Delete(destinationPath);
          System.Messaging.MessageQueue.Create(destinationPath, true);
       }
    }
    else 
    {
       System.Messaging.MessageQueue.Create(destinationPath, true);
    }
    
    mover.Source = new System.Messaging.MessageQueue(sourcePath);
    mover.Destination = new System.Messaging.MessageQueue(destinationPath);
    
    mover.Source.Send("some message", System.Messaging.MessageQueueTransactionType.Single);
    mover.Move();
    
    MessageBox.Show("Move complete.");
    
  6. In Solution Explorer, right-click the MessageMoverClient project and select "Set as Startup Project."
  7. Run the application and click the Succeed button.
    Note   If the computer is on a domain, there may be a delay between when the queue is created programmatically and when the queue is available to move messages. This delay may result in a failure of the Move method. You can add a call to the Thread.Sleep method to allow the queue to be created, or you can eliminate the code to create the queue and use Server Explorer to create the queue.
  8. In the Control Panel item named Administrative Tools, open Computer Management. Expand the Services and Applications node and then the Message Queuing and Public Queues nodes. Locate the SourceQueue and DestinationQueue. Confirm that a new message was created and exists in DestinationQueue.
  9. Add a button to the form. Name the button moveFails and set the Text property to Fail. This button will execute code that is not able to move a new message from one queue to another, because the destination queue does not exist.
  10. Create the Click event handler for the moveFails button and add the code below to the method:
    ' Visual Basic
    Try
        Dim mover As New TransactionComponent.MessageMover
        Dim sourcePath As String = ".\SourceQueue"
        Dim destinationPath As String = ".\DestinationQueue"
    
        If System.Messaging.MessageQueue.Exists(sourcePath) Then
            Dim queue As New System.Messaging.MessageQueue(sourcePath)
            If (Not queue.Transactional) Then
                System.Messaging.MessageQueue.Delete(sourcePath)
                System.Messaging.MessageQueue.Create(sourcePath, True)
            End If
        Else
            System.Messaging.MessageQueue.Create(sourcePath, True)
        End If
    
        If System.Messaging.MessageQueue.Exists(destinationPath) Then
            Dim queue As New System.Messaging.MessageQueue(destinationPath)
            If (Not queue.Transactional) Then
                System.Messaging.MessageQueue.Delete(destinationPath)
                System.Messaging.MessageQueue.Create(destinationPath, True)
            End If
    
        Else
            System.Messaging.MessageQueue.Create(destinationPath, True)
        End If
    
        mover.Source = New System.Messaging.MessageQueue(sourcePath)
        mover.Destination = _
            New System.Messaging.MessageQueue(destinationPath)
        System.Messaging.MessageQueue.Delete(destinationPath)
    
        mover.Source.Send("some message", _
            System.Messaging.MessageQueueTransactionType.Single)
    
        mover.Move()
    
        MessageBox.Show("Move complete.")
    Catch
        MessageBox.Show("Didn't move the message.")
    End Try
    
    // C#
    try 
    {
        TransactionComponent.MessageMover mover;
        mover = new TransactionComponent.MessageMover();
        string sourcePath = ".\\SourceQueue";
        string destinationPath = ".\\DestinationQueue";
    
        if (System.Messaging.MessageQueue.Exists(sourcePath)) 
        {
            System.Messaging.MessageQueue queue = 
                new System.Messaging.MessageQueue(sourcePath);
            if (!queue.Transactional) 
            {
                System.Messaging.MessageQueue.Delete(sourcePath);
                System.Messaging.MessageQueue.Create(sourcePath, true);
            }
        }
        else 
        {
            System.Messaging.MessageQueue.Create(sourcePath, true);
        }
    
        if (System.Messaging.MessageQueue.Exists(destinationPath)) 
        {
            System.Messaging.MessageQueue queue = 
                new System.Messaging.MessageQueue(destinationPath);
            if (!queue.Transactional) 
            {
                System.Messaging.MessageQueue.Delete(destinationPath);
                System.Messaging.MessageQueue.Create(destinationPath,
                    true);
            }
        }
        else 
        {
            System.Messaging.MessageQueue.Create(destinationPath, true);
        }
    
        mover.Source = new System.Messaging.MessageQueue(sourcePath);
        mover.Destination = 
            new System.Messaging.MessageQueue(destinationPath);
        System.Messaging.MessageQueue.Delete(destinationPath);
    
        mover.Source.Send("some message", 
            System.Messaging.MessageQueueTransactionType.Single);
        mover.Move();
    
        MessageBox.Show("Move complete.");      
     }
     catch 
     {
         MessageBox.Show("Didn't move the message.");
     }
    
  11. Run the application and click the Fail button.
  12. In the Control Panel item named Administrative Tools, open the Computer Management application. Expand the Services and Applications node and then the Message Queuing and Public Queues nodes. Locate the SourceQueue and DestinationQueue. Confirm that a new message was created and exists in SourceQueue. Even though the message was removed in the Move method, the message was returned to the queue when the transaction failed.

Next Steps

The message queues involved in your application may not all reside on the same server. For information on using queues in a domain, see Message Queues and Messaging Technology Backgrounder.

In this example, the information in the queue was a simple string. You may want to move more complicated objects between queues. For more information, see Message Serialization and Introduction to Reading and Retrieving Messages.

See Also

Transactional Message Processing | Creating Queues | MessageQueue Class | Writing Serviced Components

Show:
© 2015 Microsoft