Component Services for .NET, Part I of IV...
The topic of component services is about creating enterprise applications that need to be secure, reliable,
available, efficient and scalable.
Knowledge assumed for series: VB.NET, VS.NET, component/n-tier development, transactions.
The topic of component services is about creating enterprise applications that need to be secure, reliable, available, efficient and scalable. Component Services, aka COM+ (previously MTS), is the part of the Windows Server OS that supports these goals. The idea is that integrating your application properly with COM+ will meet these goals without you having to write any additional code to meet them yourself.
We have a problem however ... COM+, as you may surmise from the name, understands the Component Object Model (COM), not .NET. No doubt Microsoft will address this properly when it releases a new version of Component Services but in the interim we must use the features of the .NET Framework by which you may expose a .NET component as a COM component in order to utilise COM+. This series of articles is therefore concerned with both addressing the issue of exposing .NET components as a COM component as well as exploring the functionality offered by Component Services.
The intention is to provide an overview of component services theory and practicalities in four articles, as follows:
1 Introductory theory and concepts
2 Creating and consuming a serviced component
3 & 4 The services provided by COM+
Firstly, what are component services?
COM+ started life as MTS (Microsoft Transaction Server) which primarily existed to provide automatic transaction management for components, hence the name. In MTS a transaction's success or failure was dependent on the success or failure of the actions of objects, as indicated by the objects themselves. If any object indicated failure MTS ensured that all changes made by the constituent objects were rolled back so that the system was restored to its initial (consistent) state.
In addition MTS provided other services such as concurrency management and component-based security. Encouraged by the success of MTS Microsoft extended the product to include other common services that the enterprise developer might need. Thus with Windows 2000 came the first release of the extended version of MTS which Microsoft, somewhat confusingly, decided to name COM+, version 1.0. COM+ is not a new version of COM as one might think; rather it is a set of applications that provides services to COM components, extending their abilities.
The additional services supplied with COM+ included:
We'll look at these in a later article of this series.
Microsoft recently updated COM+ to v1.5, which chiefly added the capabilities to run a COM+ application as a Windows service or a Web service. COM+ v1.5 is available under Windows XP running IIS and Windows .NET Server.
System.EnterpriseServices is where you'll find the types that facilitate using COM+ services in the .NET Framework. The task we first need to accomplish is exposing our .NET components as COM components so that COM+ can interact with them, as it only knows how to deal with COM components. This task is effectively the same as exposing the .NET component so that it can be called from COM. This is achieved as follows:
Firstly, the .NET assembly must be signed using the strong name tool (sn.exe) to assign the assembly a unique identifier.
Secondly, we need to register the .NET component as a COM server (component) with the Windows registry. This assembly registration process can be achieved in several ways:
Whatever the method the process circumvents the following issue: the COM way is to store in each component's registry entry the path of the DLL that COM should use to create the component by invoking the CoCreateInstance() API. This entry is stored in the key InProcServer32. However, if the DLL is a .NET managed code library this would be no use to COM as it has no idea what to do with such a library being, as it is, an older technology than .NET. The resolution to the problem is for the assembly registration process to store a path to the mscoree.dll file in InProcServer32 instead. This DLL does know what to do with a managed DLL. Thus the additional level of abstraction addresses the issue.
Well, almost – if the registry key for each COM component is now pointing to mscoree.dll, how does mscoree.dll know which managed DLL to execute? The assembly registration process uses a further key named Assembly which stores the identity of the managed code DLL though not it's path. The CLR, within which all managed code runs, has inherent functionality to locate managed code DLLs so the path is not required. It has a pre-defined search order that includes examining the Global Assembly Cache (GAC).
When the CLR locates the assembly on behalf of mscoree.dll, mscroree.dll invokes a global method named DllGetClassObject() to create an instance of the type, also creating a COM Callable Wrapper (CCW) based on the type – a proxy between COM and .NET object as introduced in Migrating ASP Applictions to ASP.NET (http://www.dotnetjohn.com/articles/articleid74.aspx). The proxy handles the interpretation of messages between the two 'languages' the two types of object understand, facilitating successful communication.
The CCW exposes an IDispatch interface that can be used by a COM client to access the members of a managed object in 2 steps:
The above describes the creation of CCWs at runtime on the fly with COM clients using a technique called late binding to access the object. However, this isn't in keeping with the .NET approach which prefers early binding as this route is faster and supports compile time type checking.
Type libraries are the solution - .NET programmers can export their components as type libraries that are persistent CCWs that make the .NET types available to the COM clients at compile time, with the inherent benefits this brings. Again there are several ways of generated a COM type library from a .NET type:
In this section we'll introduce the basic components of the COM+ architecture and the classes that allow .NET to interact with the architecture. Note that the terms COM+, Component Services and Enterprise Services are largely synonymous.
The ServicedComponent class is a key class within the System.EnterpriseServices namespace as any class that uses enterprise services must derive from this class. Unsurprisingly the derived class is known as a serviced component. Such classes must be public and concrete.
Important methods of the ServicedComponent class include Activate(), CanBePooled(), Construct(), Deactivate() and DisposeObject(). We'll see these in action shortly.
Enterprise Services follow a declarative rather than procedural programming model. Declarative tags specify the services that a serviced component may utilise such as transactions, JIT activation, object pooling, etc.
In VB.NET the declarative tags are specified using attributes similar to those used for Web services. These attributes can be placed on programming elements such as assemblies, classes and methods to configure their runtime behaviour. Further these attribute values may be altered at runtime via the mechanism of reflection and they are also configurable via tools such as the Component Services tool without the need to recompile the application.
A COM+ application is a collection of serviced components that have been grouped together on the basis that they implement related functionality. A COM+ application is the basic unit of administration and deployment for a serviced component. COM+ applications are stored in DLL files. As DLLs file cannot not run in isolation COM+ applications run as either a server application (runs in its own process via a surrogate host dllhost.exe process) or a library application (runs in the process of the client that creates it).
What are the pros and cons of each?
Server applications offer:
Library applications offer the opposite attributes for the opposite reasons!
A COM+ catalog is the basic organisational unit for component services. It stores information about COM+ applications including:
Thus they are organisational units with the actual information split between the COM+ registration database (RegDB) and the Windows registry in the HKEY_CLASSES_ROOT key. The information is configurable as a single unit via the component services administration tool.
How do the .NET Framework and COM+ work together to activate a serviced component and enforce the declarative component services configuration? In summary:
When a client application creates a new instance of a serviced component, .NET enterprise services use the COM-based CoCreateInstance() API to request COM+ component services to instantiate an instance of the serviced component, passing the GUID of the serviced component to the API.
COM+ component services use the GUID to retrieve the runtime information of the serviced component from the COM+ catalog. The COM+ component services then check to see if the client application is running in the correct context (environment) that is compatible with the specified runtime requirements of the serviced component.
Assuming the runtime requirements of the serviced component match that of the client program the new object is created in the same context as the client program. A reference to the newly created object is returned to the client application so that it may make direct calls to the newly created object.
If the runtime requirements of the serviced component are not compatible with that of the client program, COM+ component services creates a new context that matches the runtime requirements of the client and create the serviced component object in that environment. COM+ component services then create a proxy and returns the proxy to the client program.
The client program uses the proxy to communicate with the serviced component object using the mechanism of interception that enables the proxy to do some pre and post-processing for each object and method invocation to ensure that the correct runtime policies are applied when a method call proceeds from one context to another.
The following explanation of the key concepts of Context and Interception might assist the reader's understanding.
A context is a set of properties that define a runtime environment for the serviced component. A context is created during the activation process for a serviced component that is configured to require certain automatic services. Because different serviced components objects can be configured with different attributes and have different requirements at runtime, COM+ component services use contexts to group together similar objects while separating incompatible objects. Objects having the same runtime requirements share a context, whereas those having incompatible requirements must reside in different contexts.
An object can access its context-specific properties using the ContextUtil class of the System.EnterpriseService namespace. We’ll see some of the members of this class in use in the next article of the series.
Interception is a mechanism that enables COM+ to capture calls to any object and execute its own code before passing the call to the objects. When two objects are in the same context no interception is required. When this is not the case it is important to ensure that the appropriate runtime requirements for individual contexts are satisfied. Therefore, the objects in a different context use a proxy to communicate instead of directly making calls to each other. The proxy uses interception to ensure that the runtime requirements are met. Interception is available at 2 levels:
object level: enables the proxy to perform pre and post processing operations when an object is created and destroyed. This level of interception is helpful in providing object-level services such as object construction and object pooling.
method level: enables the proxy to perform pre and post processing operations when a method is invoked on an object. This level of interception is useful in providing method-level services such as just in time activation and transactions.
Now that the majority of the background theory is out of the way for what is admittedly a complex topic, in Part II we'll introduce the practicalities of creating and consuming a serviced component in .NET and in the process re-enforce the ideas introduced above.
.NET SDK
Developing XML WebServices and Server Components with VB.NET and the .NET Framework
Mike Gunderloy
Que