Asynchronous Components

I l @ ve RuBoard

Asynchronous Components

Earlier, you saw how to build a J# client application that accesses the FourthCoffee components hosted within COM+. The components themselves were written in Visual Basic and supported queued method execution and loosely coupled events. Next, we'll look at how to provide the same functionality using serviced components.

Creating a Queued Component

The Oven class (in the file Oven.jsl in the Oven project) models an oven for baking cakes. Before you place a cake in the oven, you must set the oven to the correct temperature and wait for the oven to reach that temperature. The Oven class implements the IQueuedOven interface, which defines the SetTemperature method. This method takes a temperature as a parameter and sets the oven to that temperature, finishing only when the specified temperature has been reached. The method does not return a value and is a prime candidate for queued execution. The interface is tagged with the System.EnterpriseServices.InterfaceQueuingAttribute class, which allows the interface to support queued method calls. The constructor for this attribute takes a Boolean parameter that indicates whether to enable queuing ( true ) or disable queuing ( false ). You can add methods to the IQueuedOven interface as long as you obey the golden rule that they don't return values. (The J# compiler doesn't enforce this rule, but the component won't install in the COM+ catalog if you break it.)

 /** @attribute InterfaceQueuingAttribute(true) */ public interface IQueuedOven {    public void SetTemperature(short temperature); } 

The COM+ application that hosts the Oven class must be configured to support queuing. You do this by applying the System.EnterpriseServices.ApplicationQueuingAttribute class at the assembly level. This attribute provides three properties that you can specify to enable queuing, enable the queue listener, and specify the maximum number of concurrent queued requests that can be processed . You use ApplicationQueuingAttribute , as shown here:

 /** @assembly ApplicationQueuingAttribute(Enabled=true,    QueueListenerEnabled=true, MaxListenerThreads=10) */ 

A client that wants to call the SetTemperature method of the IQueuedOven interface can do so synchronously by instantiating an Oven object in the same way you would an ordinary COM+ component:

 IQueuedOven oven = new Oven(); // Wait for the oven to reach the correct temperature before continuing Oven.SetTemperature((short)200); 

If you want to invoke SetTemperature asynchronously, you use a queue moniker to instantiate the Oven object, you can see in the following code. (You should replace WHITERABBIT in the moniker with the name of your own computer.) This client code is available in the file OvenClient.jsl in the OvenClient project.

 IQueuedOven asyncOven = (IQueuedOven)Marshal.BindToMoniker(    "queue:ComputerName=WHITERABBIT/new:FourthCoffeeOven.Oven"); // Set the temperature, but don't wait for the oven before continuing asyncOven.SetTemperature((short)300); 

Supporting Loosely Coupled Events

As mentioned earlier, the natural companion to a queued method is an LCE. In our example, it would be useful to know when the oven has reached the correct temperature. The System.EnterpriseServices namespace provides attributes that you can use to define event classes. The first step is to create an interface that contains the various event methods. The Oven class will invoke these methods when it wants to raise events. In this example, there's only one method, TemperatureReached , and it takes a single parameter that indicates the new temperature of the oven. Like all event methods, it does not return a value:

 public interface IOvenEvents {    public void TemperatureReached(short temperature); } 

Next, you create a serviced component that implements this interface, as shown in the following code. This is the event class (described earlier in this chapter), and you tag it System.EnterpriseServices.EventClassAttribute . The implementation of the TemperatureReached method should be empty. (The event sink supplied by the client will provide the real implementation.)

 /** @attribute EventClassAttribute() */ public class OvenEventsClass extends ServicedComponent     implements IOvenEvents {    // Method implementations must be empty    public void TemperatureReached(short temperature) {} } 

Finally, to raise the TemperatureReached event, you create an instance of the OvenEventsClass and invoke the TemperatureReached method. The following code shows the body of the SetTemperature method of the Oven class:

 // Set the temperature of the oven public void SetTemperature(short temperature) {    // Wait for the correct temperature to be reached    // The higher the temperature, the longer the wait    System.Threading.Thread.Sleep(temperature * 100);    // Raise the TemperatureReached event    OvenEventsClass evt = new OvenEventsClass();    evt.TemperatureReached(temperature); } 

The completed Oven class, event class, and interfaces are available in Oven.jsl in the Oven project:

A client that wants to sink the TemperatureReached event must create an event sink class and register it in the COM+ catalog. The event sink must be a serviced component and must implement the IOvenEvents interface, as shown by the EventSink class below. (This class is available in EventSink.jsl in the OvenEventSink project.)

 public class EventSink extends ServicedComponent implements IOvenEvents {    public void TemperatureReached(short temperature)    {       MessageBox.Show("The oven is ready. The temperature is " +          temperature + " degrees", "Oven ready");    } } 

The EventSink component must be added to a COM+ application; you can either create a new one or add it to the application used by the Oven component. (If you export the Oven component, you'll also export the event sink.) Once the EventSink component has been installed, you can follow the procedure described earlier in this chapter to attach the IOvenEvents implementation to FourthCoffeeOven.OvenEventsClass and subscribe to the event. If you then execute the OvenClient application, you'll see two message boxes. The first will appear after 20 seconds (when the oven reaches 200 degrees), and the second will appear 30 seconds later (when the oven reaches 300 degrees). In the meantime, the OvenClient program should have finished because the second call to SetTemperature uses the asynchronous interface.

Note

We've provided another project called OvenInstaller that you can execute to create the COM+ application for the oven component if you don't want to do it by hand. The main method of the OvenInstaller class creates a RegistrationHelper object and invokes the InstallAssembly method, installing the FourthCoffeeOven.dll assembly (which contains the Oven components). Depending on where you've located the OvenInstaller and the Oven projects, you might need to change the relative path name indicated by the OvenAssemblyPath variable.


Best Practices for Serviced Component Design

The following list briefly summarizes best practices for designing serviced components.

  • Define interfaces and set the ClassInterfaceAttribute of a serviced component to ClassInterfaceType.None .

  • Supply values for ApplicationNameAttribute , ApplicationIDAttribute , and ApplicationActivationAttribute for an assembly that implements a serviced component.

  • Use JIT activation with AutoCompleteAttribute wherever possible.

  • Minimize the amount of client-specific state information that a serviced component holds.

  • If a component can be called by multiple threads concurrently, choose an appropriate synchronization setting to ensure thread safety.

  • If you're using pooling, implement CanBePooled , Activate , and Deactivate . Do not place initialization code in the constructor unless it needs to be performed only once.

  • Implement and expose the Dispose method if a client needs to be able to destroy a serviced component. Do not use a finalizer.

  • Use short-lived transactions to reduce contention in a resource manager. (Never wait for user input during a transaction.) Use an appropriate isolation level to maximize throughput while maintaining consistency.

  • Do not mix declarative and imperative transactions. (Ideally, do not use imperative transactions at all.)

  • Implement COM+ security. Define security roles using SecurityRoleAttribute .

I l @ ve RuBoard


Microsoft Visual J# .NET (Core Reference)
Microsoft Visual J# .NET (Core Reference) (Pro-Developer)
ISBN: 0735615500
EAN: 2147483647
Year: 2002
Pages: 128

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net