Serviced Components in VB.NET






3.32/5 (28 votes)
Apr 14, 2003
15 min read

128981
This article explains how to develop and deploy serviced components in Visual Basic .NET. It also explains about custom attributes which is used in COM+ services.
Introduction
.NET is Microsoft's next-generation component technology. It is designed from the ground up to simplify component development and deployment, as well as to support interoperability between programming languages. Despite its innovations and modern design, .NET is essentially a component technology. Like COM, .NET provides you with the means to rapidly build binary components, and Microsoft intends for .NET to eventually succeed COM. Like COM, .NET does not provide its own component services. Instead, .NET relies on COM+ to provide it with instance management, transactions, activity-based synchronization, granular role-based security, disconnected asynchronous queued components, and loosely coupled events. The .NET namespace that contains the types necessary to use COM+ services was named System.EnterpriseServices
to reflect the pivotal role it plays in building .NET enterprise applications. A .NET component that uses COM+ services is called a serviced component to distinguish it from the standard managed components in .NET.
Developing serviced components
A .NET component that takes advantage of COM+ services needs to derive from the .NET base class ServicedComponent
. ServicedComponent
is defined in the System.EnterpriseServices
namespace. To develop a simple serviced component following steps have to be followed:
- Define a class that derives directly or indirectly from the
ServicedComponent
class. For example, the following code ensures that theMyClass
class is hosted by a COM+ application:Imports System.EnterpriseServices Public Class MyClass Inherits ServicedComponent
- Apply service attributes to the assembly, class, or method.
Imports System.EnterpriseServices <Transaction(TransactionOption.Required)> _ Public Class MyClass Inherits ServicedComponent <AutoComplete()> Public Sub DoSomething() End Sub End Class
- Deploy the serviced component application by registering its assemblies dynamically or manually.
After a serviced component is registered, clients can create instances of the component the way they create instances of any other component.
There are two ways to configure a serviced component to use COM+ services. The first is COM-like: you derive from ServicedComponent
, add the component to a COM+ application, and configure it there. The second way is to apply special attributes to the component, configuring it at the source-code level. When the component is added to a COM+ application, it is configured according to the values of those attributes. Attributes are discussed in greater detail below.
.NET allows you to apply attributes to your serviced components with great flexibility. If you do not apply your own attributes, a serviced component is configured using default COM+ settings when it is added to a COM+ application. You can apply as many attributes as you like. A few COM+ services can only be configured via the Component Services Explorer. These services are mostly deployment-specific configurations, such as persistent subscriptions to COM+ events and allocation of users to roles. In general, almost everything you can do with the Component Services Explorer can be done with attributes. It is recommended that you put as many design-level attributes as possible (such as transaction support or synchronization) in the code and use the Component Services Explorer to configure deployment-specific details.
Registering serviced components
A serviced component is hosted by a COM+ application and must be accessible to that application. For accessibility, serviced components have the following registration and configuration requirements:
- Assembly must be strong-named.
- Assembly must be registered in the Windows registry.
- Type library definitions must be registered and installed into a specific COM+ application.
- Services added programmatically must be configured in the COM+ catalog.
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.
Manual registration
To register your component manually, use the RegSvcs.exe command-line utility. 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.
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.
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>. 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 unmanaged clients (COM clients). The default type library filename is <Assembly name>.tlb--the name of the assembly with a .tlb extension.
Dynamic registration
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 Administrators 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 Administrators 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.
Programmatic 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 Sub InstallAssembly( _
ByVal assembly As String, _
ByRef application As String, _
ByRef tlb As String, _
ByVal installFlags As InstallationFlags _
)
The installation flags correspond to the various RegSvcs switches. See the MSDN Library for additional information on RegistrationHelper
.
Configuring serviced components
Specifying application name
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("MyApplication")>
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:
imports System.EnterpriseServices;
The ApplicationID attribute
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.
The Guid attribute
Instead of having the registration process generate a CLSID for your serviced component, you can specify one for it using the Guid
attribute:
imports System.EnterpriseServices;
<Guid ("260C9CC7-3B15-4155-BF9A-12CB4174A36E")> Public Class MyCls
Inherits ServicedComponent
'Code Here
End Class
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.
The ProgId attribute
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:
imports System.EnterpriseServices;
<ProgId("MyClass.Web")> Public Class MyCls
Inherits ServicedComponent
'Code Here
End Class
The ProgId
attribute is defined in the System.Runtime.InteropServices
namespace.
Application activation type
To specify the COM+ application's activation type, you can use the ApplicationActivation
assembly attributes. You can request that the application be a library or a server application:
<assembly: ApplicationActivation(ActivationOption.Server)>
or:
<assembly: ApplicationActivation(ActivationOption.Library)>
If you do not provide the ApplicationActivation
attribute, then .NET uses a library activation type by default. Note that this use differs from the COM+ default of creating a new application as a server application
The Description attribute
The Description
attribute allows you to add text to the description field on the General Properties tab of an application, component, interface, or method. After registration, the assembly-level description string becomes the content of the hosting COM+ application's description field; the class description string becomes the content of the COM+ component description field. The interface and method descriptions are mapped to the corresponding interface and method in the Component Services Explorer.
COM+ object pooling
The ObjectPooling
attribute is used to configure every aspect of your component's object pooling. The ObjectPooling
attribute enables or disables object pooling and sets the minimum or maximum pool size and object creation timeout. For example, to enable object pooling of your component's objects with a minimum pool size of 3, a maximum pool size of 10, and a creation timeout of 20 milliseconds, you would write:
<ObjectPooling(MinPoolSize=3,MaxPoolSize=10,CreationTimeout=20)>
Public Class MyClass
Inherits ServicedComponent
'Code Here
End Class
The MinPoolSize
, MaxPoolSize
, and CreationTimeout
properties are public properties of the ObjectPooling
attribute class. If you do not specify values for these properties (all or just a subset) when your component is registered, the default COM+ values are used for these properties (a minimum pool size of 0, a maximum pool size of 1,048,576, and a creation timeout of 60 seconds).
COM+ constructor string
Any COM+ configured component that implements the IObjectConstruct
interface has access during construction to a construction string, configured in the Component Services Explorer. Serviced components are no different. The base class, ServicedComponent
, already implements the IObjectConstruct
interface as a virtual method (it has only one method). Your derived serviced component can override the Construct( )
method, as shown in this code sample:
Public Class Web
Inherits ServicedComponent
Protected Overrides Sub Construct( _
ByVal constructString As String)
If Not constructString Is Nothing Then
mstrConstructionString = constructString
End If
End Class
The MinPoolSize
, MaxPoolSize
, and CreationTimeout
properties are public properties of the ObjectPooling
attribute class. If you do not specify values for these properties (all or just a subset) when your component is registered, the default COM+ values are used for these properties (a minimum pool size of 0, a maximum pool size of 1,048,576, and a creation timeout of 60 seconds).
If the checkbox "Enable object construction" on the component activation tab is selected, then the Construct( )
method is called after the component's constructor, providing it with the configured construction string.
You can also enable construction string support and provide a default construction string using the ConstructionEnabled
attribute:
<ConstructionEnabled(Enabled=true, Default = "My String")>
Public Class Web
Inherits ServicedComponent
End Class
The ConstructionEnabled
attribute has two public properties. Enabled
enables construction string support for your serviced component in the Component Services Explorer (once the component is registered) and Default
provides an initial string value. When your component is registered with COM+, the registration process assigns the default string to the constructor string field on the component activation tab. The default string has no further use after registration. New instances of your component receive as a constructor string, the current value of the constructor string field. For example, if the default string is String A, when the serviced component is registered, the value of the constructor string field is set to String A. If you set it to a different value, such as String B, new instances of the component get String B as their construction string. They receive the current value, not the default value.
COM+ transactions
You can configure your serviced component to use the five available COM+ transaction support options by using the Transaction
attribute. The Transaction
attribute's constructor accepts an enum
parameter of type TransactionOption
, which has following five values
Disabled
NotSupported
Supported
Required
RequiresNew
For example, to configure your serviced component to require a transaction, use the TransactionOption.Required
value:
<Transaction(TransactionOption.Required)> Public Class Web Inherits ServicedComponent End Class
Strong named assemblies
A strong name consists of the assembly's identity---it's simple text name, version number, and culture information (if provided)---plus a public key and a digital signature. It is generated from an assembly file (the file that contains the assembly manifest, which in turn contains the names and hashes of all of the files that make up the assembly), using the corresponding private key. Once an assembly is created, you cannot sign it with a strong name. To create a strong-named assembly, you must sign it with a strong name when you create it.
For creating a strong named assembly, you need to create a cryptographic key pair using the Strong Name tool (Sn.exe) and assign that key pair to the assembly using either a command-line compiler or the Assembly Generation tool (Al.exe). The .NET Framework SDK provides both Sn.exe and Al.exe.
To create a key pair
At the command prompt, type the following command:
sn –k <file name>
In this command, file name
is the name of the output file containing the key pair. The following example creates a key pair called sgKey.snk.
sn -k sgKey.snk
Signing an assembly with a strong name
There are two ways to sign an assembly with a strong name:
- Use the Assembly Generation tool (Al.exe) provided by the .NET Framework SDK.
- Use assembly attributes to insert the strong name information in your code. You can use either the
AssemblyKeyFile
attribute or theAssemblyKeyName
attribute, depending on where the key file to be used is located.
To create and sign an assembly with a strong name using the Assembly Generation tool
At the command prompt, type the following command:
al /out:<assembly name> <module name> /keyfile:<file name>
In this command, assembly name
is the name of the assembly to sign with a strong name, module name
is the name of the code module used to create the assembly, and file name
is the name of the container or file that contains the key pair.
The following example signs the assembly MyAssembly.dll with a strong name using the key file sgKey.snk.
al /out:MyAssembly.dll MyModule.netmodule /keyfile:sgKey.snk
To sign an assembly with a strong name using attributes
In a code module, add the AssemblyKeyFile
attribute or AssemblyKeyName
attribute specifying the name of the file or container that contains the key pair to use to sign the assembly with a strong name. The following code example uses the AssemblyKeyFile
attribute with a key file called sgKey.snk.
<Assembly:AssemblyKeyFile ("sgKey.snk")>
Installing an assembly into the Global Assembly Cache
When an assembly that uses ApplicationActivationOption
is set to server, the assembly is loaded by dllhost.exe, which most likely is not in the same directory as the client. Assemblies that use serviced components in COM+ server apps should be placed in the GAC. Assemblies that use serviced components in COM+ libraries apps may not need to be placed in the GAC (unless they are located in different directories). The only exception is when hosting with ASP.NET—assemblies should not be placed in the GAC to enable shadow copy to operate correctly. So it is better to place all serviced components inside the GAC.
There are two ways to install an assembly into the Global Assembly Cache:
- Using the Windows Installer 2.0.
This is the recommended and most common way to add assemblies to the Global Assembly Cache. The installer provides reference counting of assemblies in the Global Assembly Cache and other benefits.
- Using the Global Assembly Cache tool (Gacutil.exe).
You can use Gacutil.exe to add strong-named assemblies to the Global Assembly Cache. This tool can also be used to view the contents of the Global Assembly Cache.
To install a strong-named assembly into the Global Assembly Cache
At the command prompt, type the following command:
gacutil –i <assembly name>
In this command, assembly name
is the name of the assembly to install in the Global Assembly Cache. The following example installs an assembly with the file name hello.dll into the Global Assembly Cache.
gacutil -i hello.dll
Conclusion
This article explains how to develop and deploy serviced components in Visual Basic .NET. It also explains about custom attributes which is used in COM+ services.