Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

C# ПІДРУЧНИКИ / c# / Hungry Minds - C# Bible

.pdf
Скачиваний:
226
Добавлен:
12.02.2016
Размер:
4.21 Mб
Скачать

Table 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.

Registering Classes with COM+

Your C# classes that are designed for use in a COM+ application must follow the same basic rules as C# classes that are designed for use by classic COM clients. Chapter 34 describes how C# is used to build COM components. Like COM components written in C#, COM+ components written in C# must be compiled into a DLL-based assembly, and must have a strong name (which requires that the assembly have a public-key pair and version information). Like COM components, this information can be specified for COM+ components through attributes specified in your C# source code.

You can install your classes into a COM+ application using a command-line tool called regsvcs that ships with the .NET Framework. This command-line tool registers all public classes found in a DLL-based assembly with COM+, and performs all the registration necessary to make the classes visible as COM+ classes.

Listing 35-2 is a slight modification to Listing 35-1. It contains the attributes necessary to prepare the generated assembly to support a strong name.

Listing 35-2: Poolable COM+ Object with Strong Name Attributes

using System.Reflection;

using System.EnterpriseServices;

[assembly:AssemblyKeyFile("keyfile.snk")] [assembly:AssemblyVersion("1.0.*")] [ObjectPooling(5, 10)]

public class PooledClass : ServicedComponent

{

public PooledClass()

{

}

~PooledClass()

{

}

public override bool CanBePooled()

{

return true;

}

public override void Activate()

{

}

public override void Deactivate()

{

}

}

You can expose this class as a COM+ class with just a few command-line tools. First, generate a new key pair for the strong name of the assembly with the standard sn commandline tool:

sn –k keyfile.snk

Then compile the code into a DLL-based assembly:

csc /target:library Listing35-2.cs

After the assembly is generated, you can use the regsvcs tool to register the assembly with COM+:

regsvcs /appname:Listing28-2App Listing35-2.dll

Tip The .NET/COM+ interop infrastructure supports COM+ applications based on assemblies in the global assembly cache. If multiple clients use your code, you might want to install your assembly in the global assembly cache before registering it with COM+.

The /appname argument to the regsvcs tool specifies the COM+ application name created to house the public classes found in the assembly. If a COM+ application already exists with the given name when regsvcs runs, the classes are added to the preexisting application.

Figure 35-1 shows the COM+ Explorer running with the assembly generated from the code in Listing 35-2 registered with COM+. The PooledClass is automatically detected by the registration process and added to the COM+ application.

Figure 35-1: COM+ Explorer with a registered .NET assembly

Launch the COM+ Explorer by performing the following steps:

1.Click the Windows Explorer Start button. The Start menu appears.

2.Choose Programs Administrative Tools. The icons for applications in the Administrative Tools program group appear.

3.Select Component Services. The COM+ Explorer appears.

Figure 35-2 shows the COM+ property sheet for the PooledClass class. Note that the object pooling information specified in the attributes in Listing 35-2 are automatically detected by the registration process and added to the COM+ application.

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

The ApplicationID attribute can be used to specify the GUID to be assigned to the COM+ application created to hold the COM+ class. The GUID is specified using its string representation, which is supplied to the attribute's constructor.

The ApplicationID attribute must be applied at the assembly level, as in the following code snippet:

[assembly:ApplicationID("{E3868E19-486E-9F13-FC8443113731}")] public class MyClass

{

}

The attribute takes a string as a parameter that describes the application's GUID.

ApplicationName

You use the ApplicationName attribute to specify the name to be assigned to the COM+ application created to hold the COM+ class. You supply the name to the attribute's constructor. If you specify this attribute in your code, you will not need the /appname argument to the regsvcs command-line tool.

The ApplicationName attribute must be applied at the assembly level, as in the following code snippet:

[assembly:ApplicationName("MyName")] public class MyClass

{

}

The attribute takes a string as a parameter that describes the application name, and the default value is the assembly name for an unconfigured default value.

ApplicationQueuing

You use the ApplicationQueuing attribute to specify that the class should be configured as a COM+ queued component. The attribute does not accept any parameters.

The ApplicationQueuing attribute must be applied at the assembly level, as in the following code snippet:

[assembly:ApplicationQueuing] public class MyClass

{

}

The attribute does not accept any parameters.

AutoComplete

The AutoComplete attribute can be applied to methods in a COM+ class. Calls to methods marked as AutoComplete methods are automatically followed by a call to SetComplete() by the .NET Framework if the method call is made within the scope of a transaction and the

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

{

}

The ConstructionEnabled attribute does not accept any parameters. False is the default for the unconfigured default value, and True is the configured default value.

JustInTimeActivation

The JustInTimeActivation attribute enables or disables just-in-time (JIT) activation for a class. The attribute accepts a Boolean as a parameter, which should be True if JIT activation should be enabled for the class, and False otherwise. JIT activation must always be enabled for objects that participate in transactions.

The JustInTimeActivation attribute must be applied at the class level, as in the following code snippet:

[JustInTimeActivation] public class MyClass

{

}

The JustInTimeActivation attribute does not accept any parameters. False is the default for the unconfigured default value, and True is the configured default value.

LoadBalancingSupported

The LoadBalancingSupported attribute enables or disables load-balancing support for a class. The attribute accepts a Boolean as a parameter, which should be True if load-balancing support should be enabled for the class, and False otherwise.

The LoadBalancingSupported attribute must be applied at the class level, as in the following code snippet:

[LoadBalancingSupported] public class MyClass

{

}

The LoadBalancingSupported attribute does not accept any parameters. False is the default for the unconfigured default value, and True is the configured default value.

SecurityRole

The SecurityRole attribute specifies a security role. This attribute can be applied to a class, a method, or an entire assembly. The constructor takes a string as an argument, and the string must specify the name of the role that callers should be a member of, as shown in the following code snippet:

[assembly:SecurityRole("MySecurityRole")] public class MyClass

{

}

Processing Transactions

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

 

 

 

 

 

Table 35-2: ACID Properties

 

 

 

Property

 

Description

 

 

 

 

 

must be rolled back. Durability guarantees that the data survives

 

 

unnatural events, such as power outages or hurricanes.

 

 

 

Writing transactional components

The Transaction attribute specifies a transaction support level that should be available for this object. The attribute accepts as a parameter a value from an enumeration in the System.EnterpriseServices namespace called TransactionOption, which supports any of the following values:

Disabled, which specifies that the object should ignore any transaction in the current context

NotSupported, which specifies that the object should create the component in a context with no governing transaction

Required, which specifies that the object should share a transaction if one exists, or create a new transaction if necessary

RequiresNew, which specifies that the object should create the component with a new transaction, regardless of the state of the current context

Supported, which specifies that the object should share a transaction if one exists

The Transaction attribute must be applied at the class level, as in the following code snippet:

[Transaction(TransactionOption.Supported)] public class MyClass

{

}

The attribute accepts a single parameter naming a value from the TransactionOption enumeration and describing the transaction level that the class design supports. The attribute can also be used without parameters, as in the following code snippet:

[Transaction] public class MyClass

{

}

Specifying the Transaction attribute without specifying a parameter sets the class's transaction support level to Required.

Listing 35-3 shows the complete code for the ExAir scenario. There are two methods, each accessing different resources; and because they are wrapped in a transaction, you are guaranteed the following: the processing of the order occurs as a single unit of work; the process is isolated from other orders that may be occurring; the order data is left in a consistent state; and once the order commits, it is in a durable data store.

Listing 35-3: Transactional Database Example

namespace TransactionSupport

{

Соседние файлы в папке c#