Building COM Components


Building COM+ Components

This next section will take you through the C# code that you can use to build the features described in the previous section. There are two key factors to building COM+ components in the .NET Framework: the ServicedComponent class from which all .NET COM+ components inherit, and various custom code attributes that give the COM+ environment detailed instructions on how to regulate the behavior of components and COM+ applications.

Transactions

As mentioned earlier, transactions indicate a single, cohesive unit of work. If something goes wrong during a transaction, the assumption must be that all work performed during that transaction will be rolled back or cancelled. If everything during the transaction goes properly, the assumption must be that all work performed during the transaction will be made permanent.

The easiest way to control transactions is through the use of code attributes. The following code attributes affect transaction processing behavior for COM+ components and methods:

  • AutoCompleteAttribute When this attribute decorates a method call, the COM+ system automatically assumes that if no exception occurs during the execution of the associated method, the transaction will complete and commit successfully.

  • transactionAttribute This attribute defines information on how transaction processing should take place on a given method. Options include setting the isolation, timeout, and the value which is of type transactionOption (Disabled, NotSupported, Required, RequiresNew, Supported).

The only time you should consider using COM+ transactions is if a single method encapsulates transactional calls to multiple, disparate sources; for example, if you need to encapsulate a call to an MSMQ, a SQL database, and an OLEDB data source in a single unit of work. For this, you would use a COM+ transaction. However, if everything you need to do takes place within a single data source such as SQL Server, you're better off using native T-SQL transactions. Distributed transactions have very high overhead.

The following code shows how you can manually control the commitment or rollback of a distributed COM+ transaction through the ContextUtil class, as well as how to make the transaction automatically complete (if no exception occurs) via the AutoComplete attribute:

    using System;    using System.Data;    using System.Data.SqlClient;    using System.EnterpriseServices;    namespace ServicedApplication    {      public class SampleClass : ServicedComponent      {        public SampleClass()        {        }        public void ManualTransaction( string trxData )        {          // perform some work using trxData, using manual transactions          SqlConnection conn = null;          try          {            conn = new SqlConnection(" ... your connection string here ... ");            conn.Open();            SqlCommand cmd = conn.CreateCommand();            cmd.CommandText = " .. some update .. ";            cmd.CommandType = CommandType.Text;            cmd.ExecuteNonQuery();            conn.Close();            ContextUtil.SetComplete();          }          catch (Exception ex)          {            ContextUtil.SetAbort();          }          finally          {            if ((conn != null) && (conn.State == ConnectionState.Open))            {              conn.Dispose();            }          }        }        [AutoComplete()]        public void AutoTransaction( string trxData )        {          SqlConnection conn = null;          try          {            conn = new SqlConnection(".. your connection string here ... ");            conn.Open();            SqlCommand cmd = conn.CreateCommand();            cmd.CommandText = ".. your update here ..";            cmd.ExecuteNonQuery();            conn.Close();          }          catch (Exception ex)          {            // re-throw            throw ex;          }          finally          {            if ( (conn != null) && (conn.State == ConnectionState.Open))              conn.Dispose();          }        }      }    } 

As you can see, working with transactions from within a COM+ component isn't very difficult at all. If you inherit from ServicedComponent, reference System.EnterpriseServices, and know how to use the ContextUtil class, the AutoComplete attribute, and the TRansaction attribute, you are ready to start creating COM+ components that participate in distributed transactions.

Construction Strings

The construction string is used to initialize a component during the construction phase. This is accomplished by the COM+ system calling the Construct method on the COM+ component. To implement this method, simply define it and provide an implementation for it on your class:

 protected override void Construct(string s) {   connectionString = s; } 

This code is pretty simple; all it does is override a method called Construct. This method can be invoked by COM+ if the application is configured properly. The preceding sample, assumes that a database connection string will be provided by the construction method.

Another feature of .NET serviced components is that, upon initial execution, if the assembly contains the appropriate custom code attributes, the COM+ system can automatically register the assembly as a COM+ application. For example, the following code sets two attributes on a sample class library, ServicedApplication:

 // Enterprise Services attributes [assembly: ApplicationName("Chapter 43 Sample")] [assembly: Description("Chapter 43 Serviced Component COM+ Sample")] 

These attributes allow .NET and COM+ to create this application the first time a serviced component is invoked within this assembly.

Figure 40.1 shows what the COM+ (Component Services) administration console looks like after instantiating a serviced component in the sample class library.

Figure 40.1. The Component Services administration console showing a recently auto-registered COM+ application.


Now right-click the registered application and choose the Properties option. When you click the Activation tab, you will see the place where you can define the construction string (in this case, a database connection string passed in by administrators). Figure 40.2 shows this tab.

Figure 40.2. The Activation tab of the Properties dialog on the newly registered COM+ application.


JIT Activation Sample

As you saw in the overview at the beginning of the chapter, JIT refers to just-in-time activation. JIT is possible only when object pooling is enabled, so the next section will show a sample of both JIT and object pooling.

Object Pooling

Object pooling is a scenario in which a pool of pre-instantiated objects is maintained in memory in a server application managed by COM+. Object pooling is enabled and configured on a per-object basis. This means that you can have some components in your COM+ application be pooled and some others not be pooled. When pooling is enabled and the COM+ application is configured as a Library mode application, pooled objects are pooled within the AppDomain of the client. In Server-activation applications, the pool resides on the server in the AppDomain in which the application resides.

To configure object pooling, you can use the ObjectPooling attribute on a class. The following code shows you a sample of how to use this attribute:

 [ObjectPooling(Enabled=true, MinPoolSize=1, MaxPoolSize=20, CreationTimeout=10000)] public class MyPooledObject : ServicedComponent {     public override void Activate() { } // removed from pool     public override void Deactivate() { } // returned to pool     public override bool CanBePooled() { return true; } } 

The preceding component will be created in a pool. The first time that a request is made for the component, a pool with only one object will be created. At peak volume, when the most requests for the component are being made, 20 objects will belong to the pool. If a request for the component lasts more than 10 seconds without a response, the request will fail and the client will be unable to create an instance of the object.

Shared Properties

Shared properties and shared property groups are services provided by COM+ that allow objects to share state within a given server process. One of the requirements of many types of applications written for COM+ is that they not maintain state because doing so would diminish the returns provided by object pooling, activation, and JIT. However, sometimes information needs to be shared between objects. To do this, you can actually share resources, called shared properties, within a single COM+ application.

All of this work begins with the SharedPropertyGroupManager class. The Shared Property Manager (SPM) is designed to take the headache out of sharing data between objects in a server process in a multithreaded environment. It deals with access locks, name collision issues, multithreading synchronization issues, semaphores, and much more. All you have to do is create and access the propertiesit's definitely a good trade-off.

The next sample uses two classes: SPMGetter and SPMSetter. Just as it appears, one class writes a value to a shared property and the other class reads a value from a shared property. To accomplish something like this without COM+, you would need to use complex memory-sharing APIs and implement your own thread synchronization and item-locking code. Fortunately, COM+'s SPM handles all that. Listings 40.1 and 40.2 show the two getter/setter classes that deal with the shared property. You can tell from the syntax that accessing shared properties is extremely simple.

Listing 40.1. Class That Reads the Current Value of a Shared Property
 using System; using System.EnterpriseServices; namespace ServicedApplication {   /// <summary>   /// Summary description for SPMGetter.   /// </summary>  public class SPMGetter : ServicedComponent  {     public string GetProperty()      {       SharedPropertyGroupManager spm = new SharedPropertyGroupManager();       SharedPropertyGroup spg;       PropertyLockMode plm = PropertyLockMode.Method;       PropertyReleaseMode prm = PropertyReleaseMode.Process;       bool groupExists;       bool propExists;       spg = spm.CreatePropertyGroup("SAMS",         ref plm, ref prm, out groupExists );       SharedProperty sp = spg.CreateProperty("TestProperty", out propExists );       return (string)sp.Value;     }   } } 

Listing 40.2. Class That Sets the Value of a COM+ Shared Property
 using System; using System.EnterpriseServices; namespace ServicedApplication {   /// <summary>   /// Summary description for SPMSetter.   /// </summary>   public class SPMSetter : ServicedComponent   {     public void SetProperty(string strValue)      {       SharedPropertyGroupManager spm = new SharedPropertyGroupManager();       SharedPropertyGroup spg;       PropertyLockMode plm = PropertyLockMode.Method;       PropertyReleaseMode prm = PropertyReleaseMode.Process;       bool groupExists;       bool propExists;       spg = spm.CreatePropertyGroup("SAMS", ref plm, ref prm, out groupExists );       SharedProperty sp = spg.CreateProperty("TestProperty", out propExists );       sp.Value = strValue;     }   } } 

In the code so far, all that's been done is to create two classes: one that has a method that sets a value and one that has a method that reads a value. Finally, you can write some code that will test this theory and determine whether the code reads and writes the same value. That code is listed here:

 Console.WriteLine("Setting shared property to the value 'Hello World'"); ServicedApplication.SPMSetter setter = new ServicedApplication.SPMSetter(); setter.SetProperty("Hello World"); ServicedApplication.SPMGetter getter = new ServicedApplication.SPMGetter(); Console.WriteLine("Value obtained from SPMGetter: " + getter.GetProperty()); 

As expected, this application produces the conventional hello world output. There is one caveat: This application won't work unless the COM+ components making use of the SPM are given an MTS object context. You'll learn more about contexts later in this chapter and in other COM+ reference manuals. The important thing to note here is that shared properties won't work without an MTS context. To provide a context for your components, the components must enforce sufficient security. On the Security tab of the application Properties dialog, make sure that the Perform Access Checks at the Component and Process Level radio button is checked.



    Visual C#. NET 2003 Unleashed
    Visual C#. NET 2003 Unleashed
    ISBN: 672326760
    EAN: N/A
    Year: 2003
    Pages: 316

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net