The COM Events Service

[Previous] [Next]

COM+ Events is similar to QC in that it's a framework that's been added to COM+ and Windows 2000. This service helps you supply notifications to certain users and/or applications when interesting events occur. It's a new solution to a very old problem.

Many applications need to notify other applications when important things occur. Perhaps one application needs to inform another that a stock price has changed or that an inventory level has dropped below a certain point. COM+ Events makes it easier for applications to raise events and to respond to events.

In the COM+ Events model, applications that fire events are called publishers. Components and applications that receive and respond to events are called subscribers. The architecture of the COM+ Events service is said to be loosely coupled because publishers and subscribers don't require knowledge of one another. This is why the COM+ Events system also goes by the name Loosely Coupled Events (LCE). The act of decoupling is achieved through a layer of indirection between publishers and subscribers called an event class.

Here's how it works. An event class instance is an object who's implementation is provided by the system. However, an event class implements one or more interfaces that are defined by you. Each interface defines a group of methods that represent a set of events. When a publisher application instantiates an event class object, it can fire events. However, a publisher doesn't know or care about which subscribers are associated with an event class. A subscriber is associated with an event class through configuration data known as a subscription. An event class object uses subscription data kept in the COM+ catalog to locate and fire events on registered subscribers. Subscribers and subscriptions don't know or care which publishers are firing events on the event class. The key point here is that publishers and subscribers have no dependencies on one another.

This loosely-coupled architecture offers several benefits. First, you don't have to worry about subscribers when you design and write a publisher application. This means that there's less code to write and maintain. Also, once a publisher application is in production, you don't have to modify it if you want to add or remove subscribers. Furthermore, you don't have to modify subscribers or subscriptions when you want to add or remove the publishers that fire events on the event class.

The Architecture of COM+ Events

The high-level architecture of the COM+ Events model is depicted in Figure 10-11. The COM+ Events system deals with four main types of entities: publishers, event classes, subscribers, and subscriptions.

A publisher is an application that fires events. An event class object acts as a dispatching device for sending out event notifications. You define the interfaces for an event class, but COM+ actually implements the event class. The event class object locates each registered subscriber and forwards events as they're fired by a publisher. A subscriber is a class or an application that receives and responds to events. A subscription is a set of configuration data kept in the COM+ catalog that binds a subscriber to an interface in a specific event class. In other words, a subscription is a request to receive a specific set of events.

click to view at full size.

Figure 10-11 The architecture of COM+ Events is based on a publisher, an event class, subscribers, and subscriptions.

There are two types of subscriptions: persistent and transient. You can use a persistent subscription to configure a component to be a subscriber. When an event is delivered to a persistent subscription, the COM+ Event service creates a new object from a configured subscriber component and invokes the method associated with the event. The event service wakes up the subscriber component's application if it's not already running. Note that for a persistent subscription, an object is created and destroyed each time an event is fired.

If you register a callback object using a transient subscription, you can make a running application a subscriber. Once an application is running, it can register a callback object with a specific event class. This allows a transient subscriber to set up an event sink into which the event class can send notifications. In the case of a transient subscription, the event service doesn't have to create and destroy an object each time an event is fired. One big difference between the two types of subscriptions is that a transient subscription forces you to create a new subscription and register an active callback object programmatically. Unlike a transient subscriber, you can completely configure a subscription for a persistent subscriber by hand using the Component Services administrative tool.

You should note that an event system must exist on one specific computer. There is no integration with Active Directory to publish an event system as a network-wide resource. This means that the firing and dispatching of events always takes place on a specific computer. This raises fault tolerance issues because this computer represents a single point of failure for the entire event system.

Creating an event class

An event class is registered as a special type of configured component. An event class is a mapping of one or more event interfaces to a system-supplied implementation of a class. You define an event class interface as you would any other COM interface. You have the option of using Visual Basic or IDL. However, as you'll see, using Visual Basic is much easier.

To create an event class, you must create a definition for a coclass that implements the interface or interfaces that hold your events. This is a little strange because you don't supply an implementation for the coclass; COM+ supplies it for you. Here's a watered-down version of the IDL source code required to define an interface and coclass for an event class:

 library MyTypeLibrary {        [ uuid(IID_MyEventInterface) ]     interface MyEventInterface : IUnknown {         HRESULT OnThisHappened( BSTR Param1 );         HRESULT OnThatHappened( BSTR Param1, double Param2 );     }     [ uuid(CLSID_MyEventClass) ]     coclass MyEventClass {          [default] interface _MyEventInterface;     } } 

The difficulty with using IDL to define an event class is that you can't simply build a type library using MIDL.EXE and install it in a COM+ application. The type library must be embedded in a self-registering DLL. While you can do this using some C++ code and the Visual C++ development environment, you can't do it using the Visual Basic IDE.

The easy way to define an event class with Visual Basic is to simply create a multiuse class with public methods in an ActiveX DLL project. As you know, Visual Basic creates a definition for the default interface and the coclass in the DLL's type library. The resulting DLL is self-registering and meets all the requirements for installing the event class into a COM+ application.

Things will seem a little strange the first time you create an event class using Visual Basic because you define method signatures without any implementation. You might be tempted to set the instancing property of the class to PublicNotCreatable because you're defining a module of method signatures without implementation. You should resist this temptation, however, and leave the class's instancing setting at MultiUse. Here's a MultiUse class definition that can be used to define an event class:

 ' MultiUse class MyEventClass Sub OnThisHappened(ByVal Param1 As String)     ' No implementation End Sub Sub OnThatHappened(ByVal Param1 As String, ByVal Param2 As Double)     ' No implementation End Sub 

If you decompile the DLL's type library using OLEVIEW.EXE, it will look something like this:

 [ uuid(IID_Default_MyEventClass) ] interface _MyEventClass : IDispatch {     HRESULT OnThisHappened( BSTR Param1 );     HRESULT OnThatHappened( BSTR Param1, double Param2 ); } [ uuid(CLSID_MyEventClass) coclass MyEventClass {      [default] interface _MyEventClass; } 

This example keeps things simple by creating an event class that implements a single interface. This is the most straightforward approach. Keep in mind that you can define event classes that implement multiple interfaces. You can also exploit polymorphism by creating a design in which multiple event classes implement the same interface.

Installing and configuring an event class

Once you've compiled the multiuse class that defines your event class into an ActiveX DLL, you can install it in a COM+ application. When you install a component in a COM+ application using the Component Services administrative tool, you have a choice of installing a new component or a new event class. You should select the option to install a new event class. Note that the COM+ Admin objects also provide a special method for installing an event class.

When you install a new event class, COM+ never uses the implementation that's supplied by your DLL. That's why you don't need to include an implementation for any of its methods. Instead, COM+ creates a synthetic class implementation from a system-supplied component in ES.DLL. All that COM+ uses from your DLL's type library is the interface definition and the CLSID for the event class.

An event class is a configured component that has the same attributes as other standard configured components. However, it has a few additional attributes that are pertinent only to an event class. Figure 10-12 shows the Advanced tab of the Properties dialog box for an event class, on which you can configure LCE attributes that aren't available for configured components that aren't event classes.

In the Publisher ID field, you can enter a friendly name for an event class. Note that the Publisher ID is associated with an event class and not a publisher application. When you create a subscription for an event class, you have the option of identifying the event class using either its CLSID or its Publisher ID.

Figure 10-12 The Advanced tab of an event class's Properties dialog box has a few extra settings for configuring loosely coupled events.

If you clear the Allow In-Process Subscribers check box, you disallow subscribers from running in the same process as the event class. This option is selected by default. You might consider clearing it in some situations to achieve higher levels of security and fault tolerance.

The last option on the Advanced tab, Fire In Parallel, informs the COM+ event system whether to notify different subscribers on different threads. This option is cleared by default, which means that the event system uses a single thread to notify subscribers one by one, in a serialized fashion. If you select this option, the COM+ event system uses multiple threads to notify subscribers in parallel.

Configuring a persistent subscription

You can configure a component to be a subscriber by creating a persistent subscription. Like event classes, subscriptions are registered with the event system and their configuration data is stored in the COM+ catalog. A persistent subscription must be associated with either the CLSID or the Publisher ID of an event class. The subscription must also be configured with the IID that defines the set of events.

Let's say you want to create a persistent subscription for the event class I described earlier in the chapter. You can create a subscriber component using a MultiUse class in another ActiveX DLL project. However, it's important to remember that this subscriber component must implement the same interface as the event class.

When you create the ActiveX DLL project for the subscriber component, you should reference the type library from the DLL that holds the event class. This will allow you to implement the default interface used by your event class. Here's an example of a subscriber component that implements the same interface as the event class:

 Implements MyEventClass Private Sub MyEventClass_OnThisHappened(ByVal Param1 As String)     ' Implementation for event response goes here. End Sub Sub MyEventClass_OnThatHappened(ByVal Param1 As String, Param2 As Double)     ' Implementation for event response goes here. End Sub 

Once you compile this component into an ActiveX DLL, you can install it in a COM+ application and configure it as a persistent subscriber. You install a subscriber component in the same way that you install a standard component in a COM+ application. Don't install it as an event class.

One option is to install the subscriber component in the same COM+ application as the event class. However, if you want the subscriber to run in a separate process, you should install the subscriber component in another COM+ server application on the same computer.

Once you install the subscriber component, you can create a subscription for it by right-clicking the component's Subscriptions folder in the Component Services administrative tool and choosing the Subscription command from the New menu. This invokes the New Subscription Wizard. The wizard presents a list of the interfaces (IIDs) implemented by the subscriber component and asks you to select one to serve as the interface for the subscription. Next, the wizard presents a list of all the event classes on the local machine that implement the same interface. Your event class should be in this list if you've configured it properly. The last page of the wizard lets you assign a friendly name to the subscription and enable it. Note that the event system doesn't fire events to a subscription until it's been enabled.

Once you configure a component as a persistent subscriber, the COM+ event system creates an instance of it each time a publisher fires an event on the associated event class. Remember that the event system uses the subscriber component to create and destroy an object each time an event is fired. Also keep in mind that persistent subscriptions will survive a system shutdown, unlike transient subscriptions.

Creating a publisher

Once you create an event class and one or more persistent subscribers, creating a publisher application is pretty straightforward. Any application that can instantiate an event class object can fire events (subject to security restrictions). When you create a publisher application, you simply create an instance of the event class and call a method to fire an event. If you plan to run the publisher application on a different computer than the event class, you should use the COM+ Export feature to create an application proxy to install event class configuration information on the publisher application's computer. Here's a simple example of the code required in a publisher application to fire an event. As you can see, there's not much to it.

 Sub FireEventFromPublisher()     Dim MyEventClassObject As CMyEventClass     Set MyEventClassObject = New CMyEventClass     MyEventClassObject.OnThisHappened "this thing just happened"     Set MyEventClassObject = Nothing End Sub 

The publisher application fires an event by invoking a method on the event class object, but ultimately the event is forwarded to subscribers by the event system itself. The event system is responsible for looking up subscription information from the COM+ catalog and forwarding the event to each subscriber. As you'll recall, you can configure an event class to fire events to subscribers one at a time or in parallel. In either case, the publisher application blocks until all the subscribers have processed their event notifications. In other words, the event system doesn't supply asynchronous behavior by itself. In the next section, I'll explain how to combine COM+ events with QC in order to fire events from a publisher application asynchronously.

Firing events asynchronously

By default, COM+ events are fired synchronously, in serialized fashion. A publisher application must wait while all subscribers handle the event and return control to the event system. Even if you've enabled the attribute for an event class to fire its events in parallel, the publisher still blocks until every subscriber has finished processing the event.

A scalable event notification architecture requires asynchronous communication. A distributed application is often inadequate if the publisher application is forced to wait while every subscriber processes its event notifications. Furthermore, some systems might require event notifications to be sent in an asynchronous and connectionless manner.

So far, everything I've said about the COM+ Events system is based on COM and RPC as opposed to MSMQ. Fortunately, COM+ Events has been integrated with QC in order to provide event notifications with the benefits of asynchronous, connectionless communication. Both event classes and persistent subscribers can be configured to use QC instead of synchronous COM calls. For companies with server computers that go off line or experience high traffic volumes, COM+ Events might impose too many limitations unless it's used with QC.

If you want to use the COM+ Events system with QC, all the limitations of queued components become the limitations of the COM+ Events model. Your event interfaces must abide by the same restrictions as any other queueable interface. This means that all events must be defined with only ByVal parameters and without return values. It also means that publisher applications and subscribers are restricted to Windows 2000 computers.

Transient subscriptions

In this chapter, I've gone through the basic steps of creating a persistent subscriber. While persistent subscribers are more common and far easier to use than transient subscribers, I want to briefly discuss how transient subscriptions work. As you'll recall, you can configure a persistent subscriber entirely by hand. It's harder to create a transient subscriber application because you must write code to create the transient subscription at runtime. This requires manipulating the COM+ catalog by writing code against the COM+ Admin objects.

A transient subscription is like a persistent subscription in the sense that it must be configured with a specific event class and a specific IID. The transient subscriber is like a persistent subscriber because it must supply a component that implements the same interface as the event class. However, the two types of subscribers are very different with respect to object lifetime and how they're created.

Once the running subscriber application creates a transient subscription using a specific event class and a specific interface, it must register a callback object that implements this interface. This callback object provides a sink that the event system can use to send event notifications. Unlike a persistent subscriber, the event system doesn't have to create and destroy an object each time it fires an event. The event system can fire many events on a long-lived callback object.

Transient subscriptions do have some drawbacks. Unfortunately, the COM+ Events system doesn't allow you to notify a transient subscriber asynchronously. Events can be dispatched only using COM, not MSMQ. For all practical purposes, this means that transient subscribers are restricted to running in the same LAN as the server computer with the event class. Synchronous callbacks also limit scalability.

Configuring security can also be a headache when you deploy transient subscribers because the client application or a custom server-side registration object must run under the identity of an account that has administrative access permissions to write to the COM+ catalog on the computer that holds the event class.

The last drawback to a transient subscription is that it's no longer useful after the transient subscriber application or the computer with the event class shuts down. If you don't explicitly remove a transient subscription from the COM+ catalog, it's removed automatically when the system restarts.

Additional COM+ Events features

I'd like to briefly mention a few more features of the COM+ Events model. First, it supports the filtering of events, so you can be more selective about which events are sent to a subscriber. A subscription has a FilterCriteria attribute that you can set to filter out events by specific criteria on a parameter-by-parameter basis. You can get even more control by creating a custom filter object and placing it between a publisher application and an event object. This gives you the ability to filter events on a per-subscriber basis. It also lets you determine which subscribers receive their event notifications first.

For more information about COM+ Events, see "The COM+ Event Service Eases the Pain of Publishing and Subscribing to Data" by David Platt in the September 1999 edition of Microsoft Systems Journal (MSJ). You can find this article in the MSDN library. (Search on Platt.) David also provides details about QC in "Building a Store-and-Forward Mechanism with Windows 2000 Queued Components" in the June 1999 edition of MSJ. This article is also available in the MSDN library. In these articles, David unearths quite a few details that I haven't covered in this chapter. He also provides some valuable step-by-step instructions that can assist you when you're learning how to configure Visual Basic components that leverage these two COM+ services.



Programming Distributed Applications with COM+ and Microsoft Visual Basic 6.0
Programming Distributed Applications with Com and Microsoft Visual Basic 6.0 (Programming/Visual Basic)
ISBN: 1572319615
EAN: 2147483647
Year: 2000
Pages: 70
Authors: Ted Pattison

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