C# Bible - Jeff Ferguson, Brian Patterson, Jason Beres
.pdfTable 35-1: System.EnterpriseServices Classes
Class |
|
Description |
|
|
|
|
|
component. This class cannot be inherited. |
|
|
|
ServicedComponent |
|
Represents the base class of all classes using |
|
|
COM+ services. |
|
|
|
ServicedComponentException |
|
The exception that is thrown when an error is |
|
|
detected in a serviced component. |
|
|
|
SharedProperty |
|
Accesses a shared property. This class cannot |
|
|
be inherited. |
|
|
|
SharedPropertyGroup |
|
Represents a collection of shared properties. |
|
|
This class cannot be inherited. |
|
|
|
SharedPropertyGroupManager |
|
Controls access to shared property groups. |
|
|
This class cannot be inherited. |
|
|
|
SynchronizationAttribute |
|
Sets the synchronization value of the |
|
|
component. This class cannot be inherited. |
|
|
|
TransactionAttribute |
|
Specifies the type of transaction that is |
|
|
available to the attributed object. Permissible |
|
|
values are members of the TransactionOption |
|
|
enumeration. |
If you plan to write classes that run inside of COM+ services, you will be writing what is known as serviced components. Serviced components take advantage of the features in the System.EnterpriseServices namespace, and enable you to use the available enterprise features of COM+.
Understanding the ServicedComponent Class
Any class designed to take advantage of COM+ services must be derived directly from ServicedComponent or from a class that has ServicedComponent somewhere in its inheritance tree. All of the COM+ services that you use are available through setting attributes on classes that are derived from the ServicedComponent class.
The ServicedComponent class does not support any properties; however, it does support a series of public methods that can be called by class clients. Most of these methods, including Activate(), Deactivate(), and CanBePooled(), map to methods defined by COM+ interfaces. such as IObjectControl. These methods are virtual and can be overridden by derived classes to provide specific functionality.
Listing 35-1 shows a simple COM+ class written in C#. This object participates in COM+ object pooling.
Listing 35-1: Poolable COM+ Component in C#
using System.EnterpriseServices;
[ObjectPooling(5, 10)]
public class PooledClass : ServicedComponent
{
public PooledClass()
{
}
~PooledClass()
{
}
public override bool CanBePooled()
{
return true;
}
public override void Activate()
{
}
public override void Deactivate()
{
}
}
The class in Listing 35-1 uses a .NET Framework attribute called ObjectPooling to mark the PooledClass class as one that should be poolable in COM+. The ObjectPooling attribute supports several constructors. Listing 35-1 uses the constructor that accepts two integers representing the minimum and maximum pool size. The code uses values of 5 and 10, which instructs COM+ to support a minimum of five and a maximum of ten objects of this class in the COM+ object pool.
COM+ components written in C# that want to participate in COM+ object pooling must override the virtual CanBePooled() method found in the ServicedComponent base class, and must return True. A return value of False signifies that the component does not want to participate in object pooling.
Your poolable COM+ components can also override virtual ServicedComponent methods called Activate() and Deactivate(). The Activate() method is called when the object is removed from the object pool and assigned to a client, and the Deactivate() method is called when the object is released by a client and returned to the pool. You should follow the guidelines set forth by standard COM+ development and place all significant object state construction and destruction code in the Activate() and Deactivate() methods. The constructor and destructor for your class are called, but they are called only once. The constructor is called only when COM+ creates instances of your object for placement into the COM+ object pool, and the destructor is called only when COM+ destroys your object after removing it from the pool. The Activate() method differs from your constructor in that it is called every time the instance is assigned to a COM+ client. The Deactivate() method differs from your destructor in that it is called every time the instance is released from a COM+ client and returned to the COM+ object pool. If you have any code that needs to perform any initialization whenever a new client is assigned use of the object, place the code in Activate(), rather than in your class constructor. Likewise, if you have any code that needs to perform any uninitialization whenever a new client releases the object, place the code in Deactivate(), rather than in your class destructor.
Figure 35-2: COM+ class property page with object pooling information
Using Attributes for COM+ Classes
The object pooling attribute used in Listing 35-2 is but one of many .NET attributes you can use in your C# classes. The .NET Framework supports several attributes that you can use to configure COM+ settings for your C# classes. All COM+-related .NET attributes are found in the System.EnterpriseServices namespace. The following sections describe some of the other interesting COM+ service attributes.
Note For COM+ attributes in the System.EnterpriseServices namespace, an unconfigured default value refers to the value that COM+ assigns to the attribute when the attribute is omitted from your code. A configured default value refers to the value assigned to the attribute if you assign the attribute but omit a value for it.
ApplicationAccessControl
The ApplicationAccessControl attribute specifies whether security can be configured for an assembly. This attribute accepts a Boolean argument and must be True if security configuration is allowed, and False otherwise. The unconfigured default value is False, whereas the configured default value is True.
ApplicationActivation
The ApplicationActivation attribute is an assembly-level attribute that specifies whether the class should be added to a library or a server COM+ application. The attribute takes a parameter of a type of enumeration called ActivationOption. The ActivationOption enumeration supports the following values:
•Library, which specifies a COM+ library application
•Server, which specifies a COM+ server application
The unconfigured default value is Library.
ApplicationID
method call completes normally. You do not need to make an explicit call to SetComplete() for AutoComplete methods. If an AutoComplete() method throws an exception, SetAbort() is called and the transaction is rolled back.
The AutoComplete attribute must be applied at the method level, as in the following code snippet:
public class MyClass
{
[AutoComplete] public MyMethod()
{
}
}
The AutoComplete attribute does not accept any parameters. False is the default for the unconfigured default value, and True is the configured default value.
ComponentAccessControl
The ComponentAccessControl attribute enables or disables security checking on calls to class instances. The attribute accepts a Boolean as a parameter, which should be True if call-level security checking should be enabled, or False otherwise.
The ComponentAccessControl attribute must be applied at the class level, as in the following code snippet:
[ComponentAccessControl] public class MyClass
{
}
The ComponentAccessControl attribute does not accept any parameters. False is the default for the unconfigured default value, and True is the configured default value.
ConstructionEnabled
The ConstructionEnabled attribute enables COM+ object construction. The COM+ object construction mechanism enables a string to be passed as a constructor string to instantiated object instances. The attribute does not specify the string; instead, it merely enables the COM+ object construction support. The attribute accepts a Boolean as a parameter, which should be True if COM+ object construction should be enabled for the class, and False otherwise. C# classes that support object construction must implement the IObjectConstruct interface. The interface's Construct() method is called by COM+ to pass the constructor string to the object.
The ConstructionEnabled attribute must be applied at the class level, as in the following code snippet:
[ConstructionEnabled] public class MyClass
{
}
Transaction support in COM+ was one of the biggest driving forces that led to its popularity. With transaction support, you can write code that performs more that one task, but the application sees it as a single unit of work, such as updating a table in one database and deleting a record in another table in a completely different database. With transactions, you can guarantee that an all-or-nothing model applies to such scenarios. If the delete fails in the second database, the update in the first database is rolled back also.
Without transactions, data would be mismatched, and you could not write enterprise-level applications. One of the first sample applications using transaction support that Microsoft published was called ExAir. ExAir is a fictional airline company. The basic concept behind the application is a ticket agent taking reservations for flights. When a customer requests a flight, he or she must also request a type of meal, such as meat, vegetarian, or pasta. The food portion of the application attempts to insert the data into a database other than the airline seating chart database. The different database represents a distributed transaction to another company, the food supplier. If the first method contains code that inserts the ticket request into the airline's database, and a second method contains code that attempts to insert data into the food supplier's database, what would happen if the food supplier's database were down? The original information containing the flight details would be inserted into the airline's database, but when the customers showed up for the flight, they would not have a meal, because the second part of the transaction did not succeed. Clearly, this is not a desirable scenario for an enterprise application. If the food supplier is down, the ticket should not be inserted into the airline's database. This dilemma can easily be handled by wrapping the two method calls into a transaction.
Note In the ExAir example, it is not in the airline's best interests to not book a ticket just because the link to the food supplier database is down. In this situation, the solution would be to use something like Queued Components or Microsoft Message Queue.
With Message Queue services, which are located in the System. Messaging namespace, you can guarantee eventual delivery of the food request by sending it to a message queue instead of attempting to immediately write the data to the remote database. With this type of architecture, the application can always accept the orders for tickets, and the food supplier can simply pull messages out of the message queue when they are ready to process the food orders.
Understanding ACID properties
For transactions to work, they must conform to the ACID properties. ACID is an acronym for atomicity, consistency, isolation and durability. Table 35-2 describes the definitions for the ACID properties.
|
|
Table 35-2: ACID Properties |
|
|
|
Property |
|
Description |
|
|
|
Atomicity |
|
All work is atomic, or occurs as a single unit of work. |
|
|
|
Consistency |
|
All data that is used in the transaction is left in a consistent state. |
|
|
|
Isolation |
|
Each transaction is isolated from other transactions, enabling transactions |
|
|
to overwrite the data in other processes, preserving consistency. |
|
|
|
Durability |
|
After the transaction has committed, all data must be in a durable store, |
|
|
such as a database. If the transaction fails, all data used in the transaction |
|
|
|