WindowsDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


AddThis Social Bookmark Button

.NET Serviced Components
Pages: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11

COM+ Constructor String

Any COM+ configured component that implements the IObjectConstruct interface has access during construction to a construction string (discussed in Chapter 3), configured in the Component Services Explorer. Serviced components are no different. The base class, ServicedComponent, already implements the IObjectConstruct interface as a virtual method (it has only one method). Your derived serviced component can override the Construct( ) method, as shown in this code sample:

public class MyComponent :ServicedComponent
{ 
   public override void Construct(string constructString) 
   {     
      //use the string. For example:
      MessageBox.Show(constructString);      
   }
} 

If the checkbox "Enable object construction" on the component Activation tab is selected, then the Construct( ) method is called after the component's constructor, providing it with the configured construction string.

You can also enable construction string support and provide a default construction string using the ConstructionEnabled attribute:

[ConstructionEnabled(Enabled = true,Default = "My String")]
public class MyComponent :ServicedComponent
{ 
   public override void Construct(string constructString) 
   {...}
} 

The ConstructionEnabled attribute has two public properties. Enabled enables construction string support for your serviced component in the Component Services Explorer (once the component is registered) and Default provides an initial string value. When your component is registered with COM+, the registration process assigns the default string to the constructor string field on the component Activation tab. The default string has no further use after registration. New instances of your component receive as a constructor string the current value of the constructor string field. For example, if the default string is String A, when the serviced component is registered, the value of the constructor string field is set to String A. If you set it to a different value, such as String B, new instances of the component get String B as their construction string. They receive the current value, not the default value.

The ConstructionEnabled attribute has two overloaded constructors. One constructor accepts a Boolean value for the Enabled property; the default constructor sets the value of the Enabled property to true. You can also set the value of the Enabled property explicitly. As a result, the following three statements are equivalent:

[ConstructionEnabled] 
[ConstructionEnabled(true)]
[ConstructionEnabled(Enabled = true)]

COM+ Transactions

You can configure your serviced component to use the five available COM+ transaction support options by using the Transaction attribute. The Transaction attribute's constructor accepts an enum parameter of type TransactionOption, defined as:

public enum TransactionOption
{
   Disabled, 
   NotSupported, 
   Supported, 
   Required, 
   RequiresNew
}

For example, to configure your serviced component to require a transaction, use the TransactionOption.Required value:

[Transaction(TransactionOption.Required)]
public class MyComponent :ServicedComponent 
{...} 

The five enum values of TransactionOption map to the five COM+ transaction support options discussed in Chapter 4.

When you use the Transaction attribute to mark your serviced component to use transactions, you implicitly set it to use JITA and require activity-based synchronization as well.

The Transaction attribute has an overloaded default constructor, which sets the transaction support to TransactionOption.Required. As a result, the following two statements are equivalent:

[Transaction]
[Transaction(TransactionOption.Required)]

Voting on the Transaction

Not surprisingly, you use the ContextUtil class to vote on the transaction's outcome. ContextUtil has a static property of the enum type TransactionVote called MyTransactionVote. TransactionVote is defined as:

public enum TransactionVote {Abort,Commit}

Example 10-5 shows a transactional serviced component voting on its transaction outcome using ContextUtil. Note that the component still has to do all the right things that a well-designed transactional component has to do (see Chapter 4); it needs to retrieve its state from a resource manager at the beginning of the call and save it at the end. It must also deactivate itself at the end of the method to purge its state and make the vote take effect.

Example 10-5: A transactional serviced component voting on its transaction outcome using the ContextUtil MyTransactionVote property

public interface IMyInterface
{ 
   void MyMethod(long objectIdentifier);
} 
 
[Transaction]
public class MyComponent :ServicedComponent,IMyInterface
{
   public void MyMethod(long objectIdentifier)   
   {     
      try
      {
          GetState(objectIdentifier);
          DoWork(  );
          SaveState(objectIdentifier);
          ContextUtil.MyTransactionVote = TransactionVote.Commit;
       }
       catch
       {
          ContextUtil.MyTransactionVote = TransactionVote.Abort;
       }
       //Let COM+ deactivate the object once the method returns  
       finally
       {
          ContextUtil.DeactivateOnReturn = true;
       }
   }
   //helper methods 
   protected void GetState(long objectIdentifier){...}
   protected void DoWork(  ){...}
   protected void SaveState(long objectIdentifier){...}
} 

Related Reading

COM and .NET Component ServicesCOM and .NET Component Services
By Juval L÷wy
Table of Contents
Index
Sample Chapter
Full Description

Compare Example 10-5 to Example 4-3. A COM+ configured component uses the returned HRESULT from the DoWork( ) helper method to decide on the transaction's outcome. A serviced component, like any other managed component, does not use HRESULT return codes for error handling; it uses exceptions instead. In Example 10-5 the component catches any exception that was thrown in the try block by the DoWork( ) method and votes to abort in the catch block.

Alternatively, if you do not want to write exception-handling code, you can use the programming model shown in Example 10-6. Set the context object's consistency bit to false (vote to abort) as the first thing the method does. Then set it back to true as the last thing the method does (vote to commit). Any exception thrown in between causes the method exception to end without voting to commit.

Example 10-6: Voting on the transaction without exception handling

public interface IMyInterface
{ 
   void MyMethod(long objectIdentifier);
} 
 
[Transaction]
public class MyComponent :ServicedComponent,IMyInterface
{
   public void MyMethod(long objectIdentifier)   
   {
       //Let COM+ deactivate the object once the method returns and abort the 
       //transaction. You can use ContextUtil.SetAbort(  ) as well
       ContextUtil.DeactivateOnReturn = true;
       ContextUtil.MyTransactionVote = TransactionVote.Abort;
 
       GetState(objectIdentifier);
       DoWork(  );
       SaveState(objectIdentifier);
            
       ContextUtil.MyTransactionVote = TransactionVote.Commit;
   }
   //helper methods 
   protected void GetState(long objectIdentifier){...}
   protected void DoWork(  ){...}
   protected void SaveState(long objectIdentifier){...}
}

Example 10-6 has another advantage over Example 10-5: having the exception propagated up the call chain once the transaction is aborted. By propagating it, callers up the chain know that they can also abort their work and avoid wasting more time on a doomed transaction.

The AutoComplete Attribute

Your serviced components can take advantage of COM+ method auto-deactivation using the AutoComplete method attribute. During the registration process, the method is configured to use COM+ auto-deactivation when AutoComplete is used on a method, and the checkbox "Automatically deactivate this object when the method returns" on the method's General tab is selected. Serviced components that use the AutoComplete attribute do not need to vote explicitly on their transaction outcome. Example 10-7 shows a transactional serviced component using the AutoComplete method attribute.

Example 10-7: Using the AutoComplete method attribute

public interface IMyInterface
{ 
   void MyMethod(long objectIdentifier);
}
  
[Transaction]
public class MyComponent : ServicedComponent,IMyInterface
{
   [AutoComplete(true)]
   public void MyMethod(long objectIdentifier)   
   {
       GetState(objectIdentifier);
       DoWork(  );
       SaveState(objectIdentifier);    
   }
   //helper methods 
   protected void GetState(long objectIdentifier){...}
   protected void DoWork(  ){...}
   protected void SaveState(long objectIdentifier){...}
} 

When you configure the method to use auto-deactivation, the object's interceptor sets the done and consistency bits of the context object to true if the method did not throw an exception and the consistency bit to false if it did. As a result, the transaction is committed if no exception is thrown and aborted otherwise.

Nontransactional JITA objects can also use the AutoComplete attribute to deactivate themselves automatically on method return.

The AutoComplete attribute has an overloaded default constructor that uses true for the attribute construction. Consequently, the following two statements are equivalent:

[AutoComplete]
[AutoComplete(true)]

The AutoComplete attribute can be applied on a method as part of an interface definition:

public interface IMyInterface
{ 
   //Avoid this:
   [AutoComplete] 
   void MyMethod(long objectIdentifier);
}

However, you should avoid using the attribute this way. An interface and its methods declarations serve as a contract between a client and an object; using auto completion of methods is purely an implementation decision. For example, one implementation of the interface on one component may chose to use autocomplete and another implementation on another component may choose not to.

Pages: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11

Next Pagearrow