Queued Components

In Chapter 8, we learned that .NET provides a mechanism to invoke method calls on an object asynchronously. Using the BeginInvoke call on the delegate of a method, a client can invoke the method asynchronously, either on the same machine or on a remote machine.

Although the support provided by .NET in its current release is a good first step toward asynchronous programming, it still lacks a few useful features. For instance, there is no support for disconnected work; the client and the server have to be running at the same time. There is no built-in mechanism for auto-retry in case the server is down at the time the client is making a call. This gap is filled by the support provided by COM+ for queued components.

A queued component looks and feels like any other .NET component that you develop. When a client instantiates a queued component, the infrastructure returns a proxy object to the client. The real object is not yet created. The client makes method calls on a queued object much like any other .NET object, except that the proxy simply records the method calls (and its parameter values). When the client releases the object, the infrastructure stores the sequence of method calls as a message and sends it to an MSMQ queue that is associated with the COM+ application. The COM+ application is configured to listen on this queue. The infrastructure reads the message that arrives on the queue, creates an instance of the queued component (the real object), and plays back the method calls on the real object in the same sequence as the original caller.

If the COM+ application queue is not reachable at the time the proxy sends the message, then the message is stored in a local outgoing queue. The MSMQ infrastructure automatically forwards the message whenever the COM+ application queue becomes available.

Note that to use queued components, MSMQ has to be installed on both the client machine and the server machine.

Configuring a Queued Component

We will extend our Employee Information System COM+ application to avail COM+ queuing services. This is a three-step process.

The first step is to configure the COM+ application as a server application. Only server applications can avail COM+ queuing services.

[assembly: ApplicationActivation(ActivationOption.Server)]

The second step is to enable the application for queuing. This is done by means of an assembly-level attribute, ApplicationQueuingAttribute, as shown in the following code excerpt:

[assembly: ApplicationQueuing(Enabled=true,
     QueueListenerEnabled = true)]

Setting the property Enabled to true results in the creation of seven message queues on the local machine at the time of registering the application. Figure 10.5 shows a snapshot of the message queues created for our Employee Information System application. Note that this machine is set up in workgroup mode, so all the queues are created as private. If your machine is set up in the domain mode, you see one public queue and six private queues.

Figure 10.5. Message queues for queued components.


The queues that are created are called transactional type queues. This essentially ensures that the messages sent to the queue are never lost or duplicated.

Also note that uninstalling the COM+ application does not automatically remove the message queues. You will need to remove them explicitly.

Enabling the application for queuing simply allows request messages to be sent to the application queue. However, you also need to set the application to begin processing these queued requests. This is done by setting the ApplicationQueuingAttribute property QueueListenerEnabled to true, as shown in the preceding code. When the application is started, the infrastructure creates a listener thread for the application that processes the queued requests.

The final step in configuring the queued component is to encapsulate all the methods that the client will use in an interface, and enable the interface for queuing support. The latter part is done by marking the interface with an attribute InterfaceQueuingAttribute. The following code excerpt enables queuing on an interface ISetSalary. The client is expected to use this interface.

// Project QueuedComponent/Employee

[InterfaceQueuing(Enabled = true)]
public interface ISetSalary {
     String Name {set; }
     void SetSalary(long newSalary);
}

Note that the methods of a queuing interface cannot have out or ref type parameters, nor can they have a return value. As the methods will be invoked asynchronously, the return type parameters do not make any sense. Recall from Chapter 8 that similar restrictions were placed on methods based on the .NET asynchronous programming model.

The serviced component requires no further configuration, except, of course, to support the queuing interface. This is highlighted in the following code excerpt:

// Project QueuedComponent/Employee

public class Employee : ServicedComponent, ISetSalary {
     ...
     public String Name {
       get {return m_employeeName; }
       set {
          m_employeeName = value;
          m_Salary=100000; //hardcoded value is ok for our test
       }
     }

     public void SetSalary(long newSalary) {
       if (null == m_employeeName) {
          throw new Exception("Set the employee name first");
       }
       m_Salary = newSalary;
     }
}

Managed Clients

For a queued component's client, the identification of the queued component is represented as a textual string of the form:

"queue:ComputerName=MachineName/new:ProgId"

For example, our Employee serviced component running on a machine MYDEV can be represented as:

"queue:ComputerName=MYDEV/new:MyCompany.Employee"

If the queued component is running on the local machine, the ComputerName field can be omitted and the component can simply be represented as:

"queue:/new:MyCompany.Employee"

The mechanism of resolving arbitrary object names, such as the preceding one, onto the object to which they refer is a standard part of COM. This mechanism is based on using locator objects (formally called monikers) to properly bind to the desired object.

The COM interoperability layer under .NET provides a static method, Marshal.BindToMoniker (the class Marshal can be found under the namespace System.Runtime.InteropServices) to bind to an object specified by its moniker name. The following code excerpt shows how a client for our Employee component can obtain an ISetSalary interface using Marshal.BindToMoniker:

// Project QueuedComponents/MyClient

static void Main(string[] args) {
     String s = "queue:/new:MyCompany.Employee";
     ISetSalary sal = (ISetSalary) Marshal.BindToMoniker(s);
     sal.Name = "Jay";
     sal.SetSalary(110000);
     ...
}

Note that clients can also instantiate the serviced component directly (and not use Marshal.BindToMoniker). In this case, however, COM+ does not provide queuing services for the component. Any method call that the client makes on the object is invoked synchronously. You could use this to your advantage for testing the functionality of your component. Essentially, it is up to each client to decide if it wishes to use the serviced component synchronously or as a queued component.

Recall that the client has to release the proxy object for the queued component so that the recorded sequence of method calls can be dispatched to the queued component's queue. For a .NET client, this would happen when the proxy object is garbage collected. However, the .NET client can expedite releasing the proxy object by calling a static method, Marshal.ReleaseComObject. This is highlighted in the following code excerpt:

// Project QueuedComponents/MyClient

static void Main(string[] args) {
     ...
     ISetSalary sal = (ISetSalary) Marshal.BindToMoniker(s);

     ... // use the object

     // Dispose the object after done with using it
     Marshal.ReleaseComObject(sal);
     Console.WriteLine("Done...");
}

This concludes our discussion on queued components. There are many other possibilities with queued components. For example, you can also set the client to get a response back from the queued component. An easy way to do this is for the client to create a message queue and pass the identity of the message queue as a method parameter to the queued component. Interested readers may wish to check [Tap-01] to learn more about MSMQ and to explore various possibilities with queued components.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.171.202