To add the serviced components in your assembly to a COM+ application, you need to register that assembly with COM+. You can perform that registration in three ways:
Manually, using a command line utility called
RegSvcs.exe
.
Dynamically, by having the client program register your assembly automatically.
Programmatically, by writing code that does the registration for you using a utility class provided by .NET.
Regardless of the technique you use, the registration process adds your serviced components to a COM+ application and configures them according to the default COM+ settings or according to their attributes (if present in the code). If the assembly contains incompatible attributes, the incompatibility is detected during registration and the registration is aborted. Future versions of the .NET compilers may detect incompatibilities during compilation time.
You
can provide .NET with an assembly
attribute, specifying the name of the COM+ application you would like
your components to be part of, by using the
ApplicationName
assembly attribute:
[assembly: ApplicationName("MyApp")]
If you do not provide an application name, .NET uses the assembly
name. The ApplicationName
attribute (and the rest
of the serviced components attributes) is defined in the
System.EnterpriseServices
namespace. You must add this namespace to
your project references and reference that namespace in your assembly
information file:
using System.EnterpriseServices;
Before exploring the three registration options, you need to understand the relationship between an assembly’s version and COM+ components.
Every managed client of your assembly is built against the particular version of the assembly that contains your components, whether they are serviced or regular managed components. .NET zealously enforces version compatibility between the client’s assembly and any other assembly it uses. The assembly’s version is the product of its version number (major and minor numbers, such as 3.11) and the build and revision numbers. The version number is provided by the developer as an assembly attribute, and the build or revision numbers can be generated by the compiler—or the developer can provide them himself.
The semantics of the version and build or revision numbers tell .NET whether two particular assembly versions are compatible with each other, and which of the two assemblies is the latest. Assemblies are compatible if the version number is the same. The default is that different build and revision numbers do not indicate incompatibility, but a difference in either major or minor number indicates incompatibility. A client’s manifest contains the version of each assembly it uses. At runtime, .NET loads for the client the latest compatible assemblies to use, and latest is defined using the build and revision numbers.
All this is fine while everything is under tight control of the .NET runtime. But how would .NET guarantee compatibility between the assembly’s version and the configuration of the serviced components in the COM+ Catalog? The answer is via the COM+ component’s ID.
The first time a serviced component is added to a COM+ application, the registration process generates a CLSID for it, based on a hash of the class definition and its assembly’s version and strong name. Subsequent registration of the same assembly with an incompatible version is considered a new registration for that serviced component, and the component is given a new CLSID.
This way, the serviced component’s CLSID serves as its configuration settings version number. Existing managed clients do not interfere with one another because each gets to use the assembly version it was compiled with. Each managed client also uses a particular set of configuration parameters for the serviced components, captured with a different CLSID. When a managed client creates a serviced component, the .NET runtime creates for it a component from an assembly with a compatible version and applies the COM+ configuration of the matching CLSID.
To
register
your component manually, use the
RegSvcs.exe
command-line utility. (In the
future, Visual Studio.NET will probably allow you to invoke RegSvcs
from the visual environment itself.) RegSvcs accepts as a parameter
the name of the file containing your assembly’s metadata. In a
single DLL assembly, that file is simply the assembly file. If you do
not specify as an assembly attribute the name of the COM+ application
that should host your components, RegSvcs must be told that name
explicitly as a command-line parameter, using the
/appname:
switch.
For example, if your single DLL assembly resides in
MyAssembly.dll
and you wish to add the serviced
components in that assembly to the MyApp COM+ application, you would
use RegSvcs in this manner:
RegSvcs.exe /appname:MyApp MyAssembly.dll
The command-line application name is ignored if the assembly contains an application name.
In any case, you must create that COM+ application in the Component
Services Explorer beforehand; otherwise, the previous command line
will fail. You can instruct RegSvcs to create the application for you
using the /c
switch:
RegSvcs.exe /c MyApp MyAssembly.dll
Or if the name is specified in the assembly:
RegSvcs.exe /c MyAssembly.dll
When using the /c
switch, RegSvcs creates a COM+
application, names it accordingly, and adds the serviced components
to it. If the Catalog already contains an application with that name,
the registration fails.
You can also ask RegSvcs to try to find a COM+ application with that
name and, if none is found, create one. This is done using the
/fc
switch:
RegSvcs.exe /fc MyApp MyAssembly.dll
Or if the name is specified in the assembly:
RegSvcs.exe /fc MyAssembly.dll
If you don’t specify a COM+ application name, either in the assembly or as a command-line parameter, RegSvcs uses the assembly name for the application name. If your assembly is called MyAssembly, RegSvcs adds the components to the MyAssembly COM+ application. This behavior is the same for all the command-line switches.
By default, RegSvcs does not override the existing COM+ application
(and its components) settings. If that assembly version is already
registered with that COM+ application, then RegSvcs does nothing. If
that version is not registered yet, it adds the new version and
assigns new CLSIDs. Reconfiguring an existing version is done
explicitly using the /reconfig
switch:
RegSvcs.exe /reconfig /fc MyApp MyAssembly.dll
The /reconfig
switch causes RegSvcs to reapply any
application, component, interface, and method attributes found in the
assembly to the existing version and use the COM+ default settings
for the rest, thus reversing any changes you made using the Component
Services Explorer.
When RegSvcs adds a serviced component to the
COM+ Catalog, it must
give it a class-ID (CLSID) and a prog-ID. RegSvcs creates a GUID for
every component (based on the assembly’s version and the class
definition) and names it
<
Namespace
>
.<
Component
name
>
. For example,
when you add the serviced component in Example 10-1
to the COM+ Catalog, RegSvcs names it
MyNamespace.MyComponent
. You can also
specify the CLSID and the prog-ID of your serviced components using
attributes.
In addition to adding the
serviced components in the assembly to a COM+ application, RegSvcs
creates a type library. This library contains interface and CoClass
definitions to be used by nonmanaged clients (COM clients). The
default type library filename is
<
Assembly name
>
.tlb—the
name of the assembly with a .tlb extension.
When a managed client creates a serviced component, the .NET runtime resolves which assembly version to use for that client. Next, the runtime verifies that the required version is registered with COM+. If it is not registered, the runtime installs it automatically. This process is called dynamic registration. As with RegSvcs, if the assembly contains an application name, then that name is used; if it does not, then the assembly’s name is used for the COM+ application’s name.
Note that only .NET clients can rely on having dynamic registration done when they instantiate a .NET serviced component. For COM clients, you must use the RegSvcs utility. Another limitation of dynamic registration is that serviced components in the assembly are configured according to the attributes in the assembly and the COM+ defaults. If you require configuring some services (such as events subscriptions) using the Component Services Explorer for your application to function properly, you must use RegSvcs to register your components and provide the additional configuration using the Component Services Explorer. Only then can clients use your serviced components. As a result, dynamic registration is only useful for serviced components that contain all the service configurations they need in their code through the use of attributes. Finally, dynamic registration requires that the user invoking the call that triggers dynamic registration be a member of the Windows 2000 Administrator group. It has this requirement because dynamic registration makes changes to the COM+ Catalog; if the user invoking it is not a member of the Windows 2000 Administrator group, dynamic registration will fail.
In general, you should use RegSvcs and the Component Services Explorer rather than relying on dynamic registration. If you want to rely on dynamic registration of your serviced components, you should increment the version number of your assembly every time you make a change to one of the components’ attributes, to ensure that you trigger dynamic registration.
Both
RegSvcs
and dynamic registration use a .NET
class called
RegistrationHelper
to perform the registration.
RegistrationHelper
implements the
IRegistrationHelper
interface, whose methods are used to
register and unregister assemblies. For example, the
InstallAssembly( )
method registers the specified assembly in the specified COM+
application (or the application specified in the assembly). This
method is defined as:
public void InstallAssembly(string assembly, ref string application, ref string tlb, InstallationFlags installFlags );
The installation flags correspond to the various RegSvcs switches.
See the MSDN Library for additional information on
RegistrationHelper
. You can use
RegistrationHelper
yourself as part of your
installation program; for more information, see Section 10.14 later in this chapter.
Every COM+ application has a GUID identifying it called the application ID. You can provide an assembly attribute specifying the application ID in addition to the application name:
[assembly: ApplicationID("8BE192FA-57D0-49a0-8608-6829A314EEBE")]
Unlike the application name, the application ID is guaranteed to be
unique, and you can use it alongside the application name. Once an
application ID is specified, all searches for the application during
registration are done using the application ID only, and the
application name is only useful as a human-readable form of the
application identity. Using application ID comes in handy when
deploying the assembly in foreign markets—you can provide a
command-line localized application name for every market while using
the same application ID for your administration needs internally. The
ApplicationID
attribute is defined in the
System.EnterpriseServices
namespace.
Instead of having the registration process
generate a CLSID for your serviced component, you can specify one for
it using the Guid
attribute:
using System.Runtime.InteropServices; [Guid("260C9CC7-3B15-4155-BF9A-12CB4174A36E")] public class MyComponent :ServicedComponent,IMyInterface {...}
The Guid
attribute is defined in the
System.Runtime.InteropServices
namespace.
When you specify a class ID, subsequent registrations of the assembly don’t generate a new CLSID for the component, regardless of the version of the assembly being registered. Registrations always reconfigure the same component in the COM+ Catalog. Specifying a class ID is useful during development, when you have multiple cycles of code-test-fix. Without it, every invocation by the test client triggers a dynamic registration—you very quickly clutter the COM+ application with dozens of components, when you actually only use the latest one.
Instead
of having the registration process
generate a name for your serviced component (namespace plus component
name), you can specify one for it using the ProgID
attribute:
using System.Runtime.InteropServices; [ProgId("My Serviced Component")] public class MyComponent :ServicedComponent,IMyInterface {...}
The ProgId
attribute is defined in the
System.Runtime.InteropServices
namespace.