COM+ Registration BasicsTo create a COM+ component, you must first start a new class library project and add a reference to the System.EnterpriseServices.dll assembly. You can then derive custom classes from the System.EnterpriseServices.ServicedComponent class. Listing 9-1 shows a basic example. Listing 9-1 A simple .NET serviced componentImports System.EnterpriseServices Public Class MyServicedClass Inherits ServicedComponent Public Function GetHello() As String Return "Hello" End Function End Class Behind the scenes, every serviced component is hosted by a COM+ application, which is really nothing more than a collection of serviced components along with COM+ configuration information. Every COM+ application is registered in the COM+ catalog. Using the administrative tools included with Windows, you can browse the COM+ catalog and modify the settings for various COM+ applications and their components. With .NET, you have the freedom to place several serviced components into a single COM+ application or separate them into multiple COM+ applications. However, it's recommended that you use a one-to-one mapping between .NET assemblies and COM+ applications, as shown in Figure 9-2. Although it is technically possible to register the serviced components in a single assembly in different COM+ applications, this adds additional versioning and registration headaches. Figure 9-2. Mapping classes to a COM+ application
To browse the COM+ catalog, select Component Services from the Administrative Tools section of Control Panel. Then burrow down to the COM+ Applications node, as shown in Figure 9-3. You'll see a list of all the currently registered COM+ applications and be able to configure them. Figure 9-3. The Component Services console
Unfortunately, the serviced component shown earlier in Listing 9-1 isn't ready to use and won't appear in the Component Services utility. Furthermore, if a .NET client attempts to create this class, it will receive an error. Before putting a serviced component to work, you need to go through a few extra registration steps, as discussed in the next few sections. Giving Your Assembly a Strong NameEvery serviced component needs a strong name that uniquely identifies your class and maps it to a component in a COM+ application. The process for generating a strong-named assembly is covered in detail in Chapter 2. Here's a quick overview of the steps you need to follow:
After you've given your assembly a strong name, you're ready to register the component. You have two registration options: dynamic registration and manual registration. Dynamic RegistrationDynamic registration, also known as "lazy registration," is a COM+ convenience that particularly shines when you test a serviced component. With dynamic registration, a serviced component is registered in the COM+ catalog as soon as it is instantiated by a .NET client. If you create a simple client and add a reference to the test component shown earlier, for instance, you can instantiate MyServicedClass as you would any other .NET object: Dim MyServicedObject As New MyServicedClass() When you instantiate the object, a slight delay will occur. If you refresh the view in the Component Services utility, you'll see a new COM+ application with an application name that matches the assembly name used for your component (in this case, TestComponent). This COM+ application contains one configured class MyServicedClass as shown in Figure 9-4. Figure 9-4. The dynamically configured MyServicedClass
If you examine the configured component in any detail, you'll notice that the GetHello method isn't listed. That's because COM is based on interfaces. If you rewrite your class as shown in Listing 9-2, the members of IHello will appear. This will also get you on the path to exposing your serviced components to legacy COM applications (in other words, unmanaged applications that don't use .NET). This integration task is beyond the scope of this book, however. Creating a compatible .NET interface isn't difficult in principle, but it does require good knowledge of COM and the mapping between COM and .NET types. You are also exposed to the traditional COM versioning nightmares, including the problems that can occur if you create a new, incompatible interface under an existing interface GUID. Listing 9-2 A .NET serviced component with an interfacePublic Interface IHello Function GetHello() As String End Interface Public Class MyServicedClass Inherits ServicedComponent Implements IHello Public Function GetHello() As String Implements IHello.GetHello Return "Hello" End Function End Class Dynamic registration might seem like the perfect solution to using COM+ in .NET, but it does suffer from a few quirks:
For these reasons, it's often recommended that you use manual registration. Manual RegistrationTo use manual registration, you use the regsvcs.exe command-line utility included with .NET. You need administrative rights to run this utility. Here's how you register TestComponent from the command line: regsvcs.exe TestComponent.dll The regsvcs.exe utility performs several tasks and informs you of any error it encounters on the way.
Here's the output you're likely to see: Microsoft (R) .NET Framework Services Installation Utility Copyright (C) Microsoft Corporation 1998-2001. All rights reserved. Installed Assembly: Assembly: C:\DistributedCode\COM+Component\bin\TestComponent.dll Application: TestComponent TypeLib: c:\DistributedCode\COM+Component\bin\TestComponent.tlb Alternatively, you can register a component programmatically by using the System.EnterpriseServices.RegistrationHelper class in a .NET application. This is a powerful but rarely used feature. In fact, the regsvcs utility uses the RegistrationHelper class behind the scenes. It's also recommended that you install serviced component assemblies into the GAC. This isn't strictly necessary for library activation mode, although it is required for server activation. The key benefit of using the GAC is location transparency you won't need to worry about which version of an assembly is registered (and which version a given client is using). COM+ and the Declarative ModelOne of the core ideas in COM+ is that a component's behavior can be configured declaratively using attributes. In other words, if you want to create a component that uses transactions or object pooling in COM+, you don't code low-level API calls directly into your component code. Instead, you use attributes to declare to the COM+ runtime that your component needs certain services. The COM+ runtime then supplies these services transparently. These types of attributes (which are conceptually similar to but different from .NET attributes) can apply to an entire component, an individual class, or even a single method and can control everything from security to instance management. In the past, these details were usually configured using the Component Services utility. You can try this out with the TestComponent application by right-clicking on the component itself or the contained MyServicedClass and then choosing Properties. Figure 9-5 shows some of the application-wide settings for TestComponent. Figure 9-5. COM+ application settings
The COM+ catalog is still a part of the .NET world because it gives developers a flexible way to configure components in a production environment without recompiling. It also allows administrators to fine-tune components to match server hardware and software resources. For example, you might use object pooling to limit an object so it never exceeds the number of available licenses. If you install more licenses, however, you won't want to recompile the component. In this case, you can just tweak the settings by using the Component Services utility. .NET extends the declarative COM+ model by allowing you to use special .NET attributes to mark up your code. These attributes replicate the settings you can configure using the Component Services utility. To configure the activation type for your COM+ application, for example, you can add an assembly-level attribute (typically to the AssemblyInfo.vb file): <Assembly: ApplicationActivation(ActivationOption.Library)> It's important to understand that this attribute is never directly executed as code. Instead, when your component is registered, all the COM+ attributes are used to configure the COM+ catalog settings. You can then override these settings by modifying them in the Component Services utility. Similarly, if you modify these attributes and recompile the component but you don't change the version number or reregister the application, the COM+ catalog settings won't be changed. Most COM+ features are exposed through class-level or method-level attributes. However, you can use a few assembly-level attributes. You can specify the COM+ application that will be registered by using the <Assembly:ApplicationName> or <Assembly:ApplicationID> attribute. The former specifies the name of a COM+ application, and the latter specifies the globally unique identifier (GUID). Without the <Assembly:ApplicationID> attribute, .NET will generate a GUID automatically. <Assembly: ApplicationName("TestComponent")> You can also specify the activation type (server or library) using the <Assembly:ApplicationActivation> attribute. <Assembly: ApplicationActivation(ActivationOption.Library)> The default activation mode, if not specified, is library. In library activation mode, the components are executed in the client's process. Remember that in this case, the client process is the process that instantiates the serviced component, which will probably be a .NET Remoting component host or an XML Web service on the same machine. Using library activation will ensure the fastest possible communication. If you use server application, all the components will be executed by dllhost.exe, the COM+ server process. You should be aware that in server activation mode, the component might not terminate when your application does, leading to "permission denied" errors when you attempt to rebuild the component and the .pdb debugging file. To put an end to this frustration, you must either wait until COM+ terminates the process (typically, after three minutes of inactivity) or shut it down manually using the Component Services utility. When using server activation, you also need to ensure that all method parameters and return values use serializable types. COM+ VersioningCOM is extremely restrictive when it comes to versioning, largely because COM components are usually shared globally on a computer. Even a small change to a component's interface can cause existing applications to break. When you create a serviced component, you will experience some of the hangover from the legacy of DLL Hell. By default, COM+ serviced components are registered in the Windows Registry using GUIDs to identify applications, components, and interfaces. When you register your serviced component, .NET generates a GUID automatically using a hash of the assembly's strong name and the version number. If you register your component again and the version number has changed, a new entry will be created in the COM+ catalog. Eventually, the clutter will build up and countless unneeded entries that reference old component versions will remain (as shown in Figure 9-6). Figure 9-6. A COM+ versioning headache
To tackle this issue, you should lock down your assembly's version number while testing. Then modify the appropriate assembly attribute in the AssemblyInfo.vb file. For example: <Assembly: AssemblyVersion("1.3.0.0")> Of course, after you fix the version number, it's up to you to ensure that you increment the version number and generate a new set of GUIDs when it really is required namely, when you're ready to distribute a component that has a different interface. Once again, this will primarily be a consideration if you're in the unenviable position of interoperating with unmanaged clients. Another option is to lock down your GUIDs by specifying them in the code using the <Assembly:Guid> attribute for the assembly and the <Guid> attribute for each class or interface. In a complex component with multiple interfaces and classes, this approach requires significantly more code. Using a COM+ ComponentNow that you have a serviced component, how can you use it? You have three basic options:
So far, we've explored how you can create and register a serviced component. The next few sections dive into the real details of COM+ programming and consider why you might want to use it. |