Architecture of Component Services



Architecture of Component Services

In this section, you'll learn about the basic components of the COM+ architecture. You'll learn how a COM+ application is organized, how COM+ provides the component services, and how the .NET Framework interacts with COM+.

Serviced Components

One of the most important classes in the System.EnterpriseServices namespace is the ServicedComponent class. Any class that uses enterprise services must derive from the System.EnterpriseServices.ServicedComponent class. Such a class is also called a serviced component. Classes that derive from ServicedComponent must be public and concrete, and must provide a public default constructor. A basic serviced component declaration is as follows:


using System.EnterpriseServices;

namespace Exam70320

{

  public class MySampleSC : ServicedComponent

  {

    public MySampleSC() {...}

    ...

  }

}

NOTE

Non-Default Constructors COM can instantiate the .NET classes only with public default constructors via the CoCreateInstance() COM method. There is no way that COM can create an object and pass parameters for object creation at the same time. If you wish to create a .NET object in different ways from a COM client, you need to use the factory pattern (that is, by creating a separate .NET object that has methods to create the required object in different ways). Refer to the section "Creating an Interface Assembly That Works with the Client-Activated Objects" in Chapter 3, ".NET Remoting," for an example on using the factory pattern.

Configured Components You can apply declarative attributes on the serviced components that are configurable at runtime. For this reason, serviced components also can be called configured components.


The ServicedComponent class has methods but no properties or events. I have listed the important methods of this class in Figure. All these methods are protected except the DisposeObject() method that is a public static method. You can override the protected methods in a class inherited from the ServicedComponent class.

Figure Important Methods of the ServicedComponent Class

Method

Description

Activate()

Can be used to perform startup operations. It is called when an object is created or allocated from a pool.

CanBePooled()

Indicates whether the object should be pooled. It is called when an object is to be moved to the pool.

Construct()

Provides access to the construction string of the serviced component. It is called after the serviced component object is created—that is, after the constructor is executed.

Deactivate()

Can be used to perform cleanup operations. It is called when an object is about to be deactivated—that is, destroyed or moved to a pool.

DisposeObject()

Finalizes the resources used by the serviced component and removes the associated COM+ reference.

NOTE

Component Versus Class You'll often find the terms "component" and "class" used apparently interchangeably in this chapter. They refer to the same thing but there is a slight distinction. A class is a unit of development, whereas a component is a unit of deployment. A component may provide features such as versioning and security, which are not of interest to a class.


Declarative Programming Model

Unlike the conventional procedural model, the programming model for enterprise services is mostly declarative. In the procedural model, you write code to accomplish a task, whereas in the declarative model you use declarative tags that instruct the underlying platform to accomplish a task. With a serviced component, the declarative tags specify the services that the component receives, such as transactions, just-in-time activation, object pooling, and so on.

In Visual C# .NET, the declarative tags are specified by attributes. You can place attributes on certain program elements such as an assembly, a class, and methods to specify runtime information. At runtime, the attribute values can be manipulated through a mechanism called reflection. After the application is deployed, administrators can use tools such as the Component Services administrative tool to manipulate the attribute values and change the application's behavior without any need to recompile the application.

For example, consider an application that needs to support transactions. In the procedural model, a programmer has to write code to commit or abort a transaction. As opposed to this, in the declarative programming model, programmers can just mark the code with attributes that tell the runtime environment that the code requires transaction support. A simple serviced component that requires transaction support may be defined as shown here:


[Transaction(TransactionOption.Required)]

public class MySampleSC : ServicedComponent

{

   ...

}

When this code executes, all the necessary details for enabling transactions are done behind the scenes by the runtime environment.

What's really the advantage of declarative programming over the procedural programming? There are many. The three most important advantages are

  • Reduced Development Cost— Development cost is reduced because there is now less code to write and maintain.

  • Increased Reliability— Applications' reliability is increased because it is very likely that the underlying platform would have gone through more testing than an average piece of application code.

  • Increased Flexibility— Declarative code can be read and modified at runtime without any need to recompile the application. Therefore, it is easy to write programs that allow administrators to reconfigure the way an application behaves after it has been deployed.

As you progress through this chapter, you'll use several attributes that specify the runtime requirements for serviced components. I have listed important attributes of the System.EnterpriseServices namespace and their descriptions in Figure.

Figure Important Attributes of the System.EnterpriseServices Namespace

Attribute

Scope

Description

ApplicationAccessControl

Assembly

Allows you to configure the security of an application hosting the serviced component.

ApplicationActivation

Assembly

Specifies whether the serviced components are activated in the creator's process (ActivationOption.Library, the default value) or in the system's process (ActivationOption.Server).

ApplicationID

Assembly

Specifies the GUID of the COM+ application.

ApplicationName

Assembly

Specifies the name of the COM+ application.

ApplicationQueuing

Assembly

Enables queuing support for the COM+ application.

AutoComplete

Method

Indicates whether the method should automatically notify the COM+ context about its success or failure when it completes.

ComponentAccessControl

Class

Enables security checking when the serviced component is accessed.

COMTIIntrinsics

Class

Allows passing of the context properties from the COM transaction integrator (COMTI) to the COM+ context.

ConstructionEnabled

Class

Allows the component to pass a construction string to enable object construction.

Description

Assembly

Class

Method

Interface

Specifies the description of he assembly, class, method, or interface.

EventClass

Class

Indicates that a class can participate in loosely coupled events.

EventTrackingEnabled

Class

Enables event tracking on the component.

ExceptionClass

Class

Specifies the queuing exception class.

InterfaceQueuing

Class

Interface

Enables queuing support on the specified interface or class.

JustInTimeActivation

Class

Indicates whether the serviced component supports just-in-time activation.

LoadBalancingSupported

Class

Indicates whether the serviced component supports load balancing.

MustRunInClientContext

Class

Indicates whether the serviced component must be created in the creator's context.

ObjectPooling

Class

Indicates whether the serviced component will be created in an object pool and configures the size of the pool.

PrivateComponent

Class

Specifies that a serviced component should not be visible and should not be activated outside its containing COM+ application.

SecureMethod

Assembly

Class

Method

Indicates that the methods of the serviced component should be called through an interface so that the security is applied.

SecurityRole

Assembly

Class

Interface

Indicates the security role that will have access to the serviced component.

Synchronization

Class

Specifies the synchronization support offered to the serviced component. It controls how multiple threads can execute the methods of the serviced component simultaneously.

Transaction

Class

Specifies the transaction support required by the serviced component.

COM+ Applications

A COM+ application is a group of serviced components that perform related functions. Each of these components further consists of interfaces and methods. A COM+ application is the primary unit of administration and deployment for the serviced components.

A COM+ application is always stored in a DLL file. A DLL file cannot run on its own, so a COM+ application is always configured to run in one of the following two ways:

  • Server Application— In a server application, a COM+ application runs in its own process. To enable this, COM+ provides a surrogate process (dllhost.exe) that hosts the DLL file for the COM+ application.

  • Library Application— In a library application, the COM+ application runs in the process of the client that creates it. To enable this, the components in a library application are always loaded into the process of the creator.

Now that you have two types of applications, you'll have to choose between them. Figure helps you make this decision based on various parameters.

Choosing Between a Server and Library Application

Parameter

Server Application

Library Application

Performance

Low, because communication between the objects involves marshaling across the processes or computer.

High, because the objects are locally available to the client programs and no marshaling is required.

Fault-tolerance

High, because any unhandled exception in the application affects only the dllhost.exe process that is hosting the application. A server application is therefore especially useful when you have any components that use unmanaged or unsafe code.

Low, because any unhandled exception in the application affects the client program that hosts the serviced component.

Security

High, because server applications can be more tightly secured, and you therefore can explicitly configure the process-wide security settings.

Low, because the components rely on security settingsof the client process that hosts the serviced component.

Support for component services

High, because all COM+ component services are supported when a COM+ application runs as a server application.

Low, because services such as object pooling and queued components are not supported.

COM+ Catalog

The COM+ Catalog stores the information about the COM+ applications. Each COM+ application and serviced component is uniquely identified in the COM+ Catalog by a globally unique identifier (GUID).

EXAM TIP

Server Application Versus Library Application You should know the merits and drawbacks of configuring a COM+ application to run as a server application or as a library application. Use the information in Figure to make the decision.


The other important information stored in the COM+ Catalog for a serviced component is its runtime requirements. For example, if a component requires a transaction, this information is stored in the COM+ Catalog. Later, when the component is activated, COM+ services use the catalog to determine the runtime requirements of components.

The COM+ Catalog itself is physically split between the following locations:

  • COM+ Registration Database (RegDB), which is stored in the Registration directory of the Windows installation (such as c:\windows\registration).

  • Windows Registry within a key named HKEY_CLASSES_ROOT.

However, you can access and update the catalog in an integrated way by using the Component Services administrative tool. This tool is available in the Administrative Tools section of the Windows Control Panel. This tool allows administrators to make changes to the installed COM+ application via a user interface as shown in Figure. Any changes made through the Component Services administrative tool are stored in the COM+ Catalog. You can also read or update the catalog through programs as described in the section "Registering the Serviced Component into the COM+ Catalog," later in this chapter.

3. The Component Services administrative tool enables you to manage and configure COM+ applications.

graphics/07fig03.jpg

Serviced Component Activation

At this point, you have a reasonably clear idea about how a serviced component is configured for development and deployment. What remains to be seen is how the .NET Framework and COM+ work together to activate a serviced component and enforce the configured semantics at runtime.

Activation of a serviced component can be summarized in the following steps:

  1. When a client component (such as ComponentA as shown in Figure) creates a new instance of a serviced component (such as, ComponentB), the .NET enterprise services use the COM-based CoCreateInstance() COM method to request COM+ to instantiate the serviced component. The .NET enterprise services pass a GUID of the serviced component to the CoCreateInstance() COM method.

    4. Components with similar runtime requirements may exist in a similar context.

    graphics/07fig04.gif

  2. COM+ uses the GUID to retrieve the runtime information of a serviced component from the COM+ Catalog. COM+ then checks to see whether the client component is running in the same context (that is, an environment that is compatible with the runtime requirements of the serviced component).

  3. If the runtime requirements of the serviced component match with those of the client component, then the new object is created in the same context as the client component, as shown in Figure. A reference to the newly created object is returned to the client component so that the client component can make direct calls on the newly created object.

  4. If the runtime requirements of the serviced component are not compatible with that of the client component, COM+ creates a new context that matches the client's runtime requirements and creates the serviced component in that environment as shown in Figure. The COM+ component services then create a proxy and return the proxy to the client component.

    5. Components with different runtime requirements exist in different contexts and communicate through a proxy.

    graphics/07fig05.gif

  5. When the objects are in different context, they communicate with each other by using a proxy. In case of cross-context calls, the proxy uses a mechanism known as interception that enables the proxy to do some pre-processing 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 concept of context and interception is the key to understanding the activation process.

Context

A context is a set of runtime properties that defines the execution environment for a serviced component. A context is created during the activation process for a serviced component based on how the serviced component is configured.

COM+ uses context to group the like-minded objects while separating the incompatible objects. Objects having the same runtime requirements share a context (refer to Figure), whereas those having incompatible runtime requirements must reside in different contexts, as shown earlier in Figure.

An object can access its context-specific properties by using the ContextUtil class of the System.EnterpriseServices namespace. The ContextUtil class provides static methods and properties as listed in Figure. You will use several of these properties throughout this chapter.

Figure Important Members of the ContextUtil Class

Member

Type

Description

DeactivateOnReturn

Property

Indicates whether the object should be deactivated when the object's method returns.

DisableCommit()

Method

Indicates the COM+ context to vote for aborting the current transaction. This method does not deactivate the object when the object's method returns.

EnableCommit()

Method

Indicates the COM+ context to vote for committing the current transaction. This method does not deactivate the object when the object's method returns.

IsCallerInRole()

Method

Determines whether the caller is in a specified role.

IsInTransactional

Property

Indicates whether the current COM+ context is transactional.

IsSecurityEnabled

Property

Indicates whether the current COM+ context has role-based security enabled.

MyTransactionVote

Property

Specifies the COM+ context transaction vote—abort or commit.

Transaction

Property

Represents the current COM+ transaction object.

SetAbort()

Method

Indicates the COM+ context to vote for aborting the current transaction. This method also deactivates the object when the object's method returns.

SetComplete()

Method

Indicates the COM+ context to vote for committing the current transaction. This method also deactivates the object when the object's method returns.

Interception

Interception is a mechanism that allows COM+ to capture calls to any object and execute its own code before passing the call to the object. For example, a component in the COM+ Catalog may specify that only users authenticated with the Supervisors security role are allowed to call a method named ApproveOrder(). In this case, COM+ intercepts the call to the ApproveOrder() method and forwards or rejects the call to the object based on the identity of the user.

When two objects are in the same context, no interception is required because the objects have the same runtime requirements. However, when the objects reside in different contexts, it is important to ensure that appropriate runtime requirements for individual contexts are satisfied. Therefore, the objects in a different context use a proxy to communicate rather than make direct calls to each other. The proxy uses interception to ensure that the runtime requirements are met. Interception is available at two levels:

  • Object level— This level of interception allows the proxy to perform pre-processing 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— This level of interception allows the proxy to perform pre-processing 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.

REVIEW BREAK

  • Classes that should use COM+ component services must derive from the System.EnterpriseServices.ServicedComponent class.

  • To use the COM+ services in your program, you need not write a lot of code. Instead, you use declarative attributes to specify whether a class should receive particular services.

  • The declarative attributes applied to a class are stored in the COM+ Catalog as part of the assembly registration process. At runtime, COM+ can read the COM+ Catalog to determine what services a component should receive and to provide those services.

  • COM+ uses interception to provide various runtime services. Interception is a mechanism that allows COM+ to capture calls to any object and execute its own code before passing the call to the object.

  • COM+ creates different contexts for the objects that have different runtime requirements. A proxy is used to provide interception services between the objects in different contexts.