Integration and Migration of COM+ services to WCF

 

Ganesan Krishnamurthy
Sripriya Thothadri
Infosys Technologies Ltd

 

March 28, 2007

 

Summary: Windows Communication Service (WCF) is a new generation development platform to build robust distributed and transaction based components that ensure better security, high reliability and better integration, based on the principles of service orientation. COM+ is a development model used for creating enterprise wide distributed business applications. COM+ is available in the .NET environment as managed enterprise serviced components.

This Integration and Migration of COM+ services to WCF white paper provides information on what can be expected in the process of migration of the unmanaged COM+ to WCF and various ways of migrating COM+ to WCF technology.

(21 printed pages)

 

WCF is a new messaging and communication subsystem and development platform to create robust and secure transaction based connected systems. WCF is the unification of existing distributed and communication technologies such as .NET Remoting, Enterprise Services, ASP.NET web services, WSE and MSMQ. The key advantage in using WCF is that developers use a single programming model to develop varieties of distributed applications. WCF provides a programming model that adheres to the tenets of service orientation and makes it easy to build service oriented applications. WCF enables creating services that are agnostic to the underlying transport mechanisms and implements several community-driven specifications on the web thus making WCF interoperable and extensible.

WCF supersedes existing distributed technologies and a lot of migrations from other distributed technologies such as ASP.NET web services, .NET Remoting, Serviced components to WCF can be expected. It should be noted, however, that WCF has wire level compatibility with ASMX and WSE 3.0 and so it is possible for these technologies to coexist and interoperate with WCF. In the cases of ASP.NET web services, .NET Remoting and Serviced Components, migration may not be that complex if the existing code d does not use low level extensible points such as Http Context, Sinks. The primary reason for reduced complexity of such migrations is that WCF also uses attribute based programming that is familiar to the .NET developer community. Another reason for the simplicity in migration is that all of them are managed technologies.

COM+ is a popular distributed application development environment. The ability to provide powerful enterprise services by configuration rather than hand coding them is one of the reasons that makes COM+ attractive. Using Visual Basic to write code simplifies building sophisticated COM+ business applications even more. The complexities of implementing interfaces like IUnknown, IDispatch are well hidden from developers. The advent of managed .NET framework and Enterprise Services which is a wrapper and extension over COM+ infrastructure have grabbed a share of COM+'s  limelight. Of course, certain ambiguities like Enterprise Service's dependency over COM+ infrastructure have, no doubt, influenced clients to retain their COM+ based software assets along with the new managed software assets.

Moving to WCF will be strongly determined by WCF's enterprise application features like security, reliability and transactions as compared with COM+ services especially with respect to configuration and programming. The easy and yet powerful programming style of WCF versus the complexity of understanding COM and COM+ will certainly be a big plus.

This document provides details on migration approaches for COM+ applications into WCF. While COM+ services can be configured uniformly irrespective of the language used to create the application, there are still subtle differences like thread modeling across the applications that are built either by VB or by VC++. This document does not provide details over those subtleties.

WCF overview

WCF is a service-oriented framework that enables developers to create WCF services and clients easily. Clients initiate communication. Services receive messages from clients and respond suitably. The same application can act as a service as well as client. WCF supports request-reply, one-way and duplex forms of communication.

WCF services expose their functionality via endpoints. Endpoints encapsulate the address of communication (Address), the functionality or the service contract (Contract) that is exposed and the method of communication (Binding) (The famous acronym ABC of WCF makes this easy to remember. Refer to this msdn article for more details https://msdn2.microsoft.com/en-us/library/aa480210.aspx).

Bindings hold information that is required to connect to endpoints of a WCF service. Protocols, encoding and transport elements represent the means to connect to an endpoint and bindings encapsulate this information. Protocols stand for the reliability mechanism, the security mechanism and the transaction flow settings that need to be used. The encoding information determines the encoding scheme that should be used to encode the messages. The transport information represents the transport that should be used for the communication. A binding contains the protocol, encoding and transport chosen to connect to the endpoint.

WCF provides a number of out-of-the-box bindings that can be used in various typical scenarios as is. Existing bindings can be tuned by configuring to the application's requirements and custom bindings can also be developed to exactly match the application's requirements. The protocol, encoding and transport make up the binding elements and are stacked in a specific order. This stack of binding elements is called the channel stack and comprises of the protocol channel and the transport channel, with the transport channel present at the bottom of the stack.

The protocol channel comprises of:

  • TransactionFlowBindingElement
  • ReliableSessionBindingElement
  • SecurityBindingElement
  • TextMessageEncodingBindingElement
  • BinaryMessageEncodingBindingElement
  • MTOMMessageEncodingBindingElement.

A custom encoding scheme is also possible.

The transport channel consists of the transport binding elements. The Out-of-the-box transport binding elements are:

  • NetTCPBindingElement
  • NetNamedPipeBindingElement
  • WSHttpBindingElement
  • BasicHttpBindingElement
  • NetMsmqBindingElement
  • WSDualHttpBindingElement
  • WSFederationHttpBindingElement.

Custom transport binding elements can also be created.

The system bindings come with preconfigured protocol and transport channels. For example, the NetTcpBinding uses the TCP transport channel, binary encoding and transport security protocol channels. The system bindings, as mentioned earlier, can also be customized to change the default behavior. For example the NetTcpBinding can be customized to use message security instead of the default transport security.

WCF provides a variety of services to control runtime behavior of a service. Throttling behavior, Transaction behavior and Concurrency behavior are some of the available runtime services.

The table below shows the features provided by each of the system bindings. (Note: this table is part of the WCF documentation on Windows SDK).

The table consists of the following columns:

  • Interoperability – The technology or protocol that the binding is interoperable with.
  • Security – The security mode of the binding. See Security in COM+ and WCF section of this white paper to understand security mode.
  • Session – Does the binding support sessions and what is the session support?
  • Transactions – Are transactions enabled?
  • Duplex - are duplex contracts supported?
  • Encoding – format of the message on the wire.

The default values in the table are enclosed within parentheses.

Binding

Interoperability

Security (Default)

Session (Default)

Transactions

Duplex

Encoding

BasicHttpBinding

Basic Profile 1.1

(None), Transport, Message,

None, (None)

(None)

n/a

Text, (MTOM)

WSHttpBinding

WS

Transport, (Message), Mixed

(None), Transport, Reliable Session

(None), Yes

n/a

Text, (MTOM)

WSDualHttpBinding

WS

(Message)

(Reliable Session)

(None), Yes

Yes

Text, (MTOM)

WSFederationHttpBinding

WS-Federation

(Message)

(None), Reliable Session

(None), Yes

No

Text, (MTOM)

NetTcpBinding

.NET

(Transport), Message

Reliable Session, (Transport)

(None), Yes

Yes

Binary

NetNamedPipeBinding

.NET

(Transport)

None, (Transport)

(None), Yes

Yes

Binary

NetMsmqBinding

.NET

Message, (Transport), Both

(None)

(None), Yes

No

 

NetPeerTcpBinding

Peer

(Transport)

(None)

(None)

Yes

 

MsmqIntegrationBinding

MSMQ

(Transport)

(None)

(None), Yes

n/a

 

WCF services require a host process to make them run and the services can be hosted in any managed process such as IIS, console application, Windows Services and the newly introduced Windows Process Activation (WAS) service. WCF services can also be hosted in COM+.

COM components are hosted in a COM+ application and the COM+ application provides the required services to the component. COM+ applications are either Server applications or Library applications.

Let us explore the various integration and migration approaches while transitioning from the COM+ world to the WCF world.

Different approaches to choose from

The COM+ to WCF transition can be done using the following approaches:

  • Integrating existing COM+ applications as is with WCF.
  • Migrating COM+ applications to WCF.
  • Partial integration and migration.

Any one of these three approaches can be selected while moving COM+ applications to WCF, depending on the complexity and future roadmap of the business applications. The rest of this white paper elaborates each of these approaches.

Integrating COM+ applications as is with WCF

Component Service Model Configuration tool is used to expose Com+ applications as Web services. The SDK comes with a GUI version (COM+ Integration Wizard) of this utility, which is easier to use as compared to the Command line version.

This is the easiest of all the approaches as the existing COM+ components can be easily exposed as WCF web services, through a tool supplied by WCF infrastructure, without touching the code base. However, the exposed web services will still access COM+ components internally. The exposed web services can also be customized through options provided by the WCF tool.

It is important to understand the internal representation of COM+ application in the WCF world to effectively deal with post-integration problems:

  • Components become services
  • Interfaces become service contracts
  • The methods of the interfaces become service operations

Specific interfaces or their methods can be selectively chosen to be exposed as WCF web services, when we use the WCF tool. Thus exposed WCF web services can be hosted in COM+ or IIS or hosted in-process in IIS.

However, all the interfaces cannot be exposed as web services using this approach. Given below is a list of characteristics of interfaces that are not supported:

  • Interfaces containing object references unless the object implements IPersistStreamso that the COM+ integration service can serialize and deserialize the instance.
  • Interfaces containing parameters whose data types are not compatible with the .Net Com interop.
  • Interfaces of applications that have application pooling enabled when hosted by COM+.
  • Interfaces of components marked as private.
  • COM+ infrastructure interfaces like IObjectControl.

COM+ Integration Wizard can be invoked using the Service Configuration Editor as part of the SDK. To access the COM+ Integration Wizard, click File > Integrate > COM+ Application in the Service Configuration Editor. The screen as seen in Figure 1 is displayed on selecting a COM+ application in the Service Configuration Editor:

Selecting the COM+ application in the Service Configuration Editor

Figure 1. Selecting COM+ application in the Service Configuration Editor

In Figure 1, the _CBroker interface of the CBroker component belonging to a COM+ application has been selected for integration.

The methods of the _CBroker interface that need to be exposed as a Web Service operation must be selected in the next screen. _CBroker has just one method SubmitOrder, which is displayed for selection as shown in Figure 2.

Selecting the interface and methods to be exposed

Figure 2. Selecting the interface and the methods to be exposed

 

The hosting mode is selected next. Figure 3 shows the screen for selection the hosting mode:

Selecting the hosting mode

Figure 3. Selecting the hosting mode

 

Irrespective of the selected hosting mode, the generated Web Service uses the COM+ component for any functionality. So the actual execution happens using the COM+ infrastructure.

The next screen allows selection of the communication mode that must be used. The knowledge of various communication modes supported in WCF is comes handy in making the right choice.. In this example, the TCP communication mode is selected. Figure 4 shows the screen that is displayed to select the communication mode:

Selecting the communication mode

Figure 4. Selecting the communication mode

Once the hosting mode is chosen, enter the base address of the service. Figure 5 shows the screen that is displayed to enter the base address of the service:

Providing the Service

Figure 5. Providing the service's base address

 

Click Next to view the complete configuration details for the selected service (See Figure 6).

Selected Configuration

Figure 6. The selected configuration

 

The complete service configuration details are displayed. The wizard is now ready to create the service. Figure 7 shows the final confirmation screen.

Final Confirmation

Figure 7 Final confirmation

 

Click Finish to expose the COM+ application as a WCF web service.

(If COM-hosted is selected, then App.Config file is created in Program Files%\ComPlus Applications\{appid}. For both Web-hosted and Web-hosted In-process hosting modes, a Web.config file is created in the application virtual directory. The service manifest file is created in all cases in the respective directories.)

The App.Config file created for the sample COM+ application is shown below:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name="ComServiceMexBehavior">
                    <serviceMetadata httpGetEnabled="false" />
                    <serviceDebug includeExceptionDetailInFaults="false" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <bindings>
            <netNamedPipeBinding>
                <binding name="comNonTransactionalBinding" />
                <binding name="comTransactionalBinding" transactionFlow="true" />
            </netNamedPipeBinding>
            <netTcpBinding>
                <binding name="comNonTransactionalBinding" />
                <binding name="comTransactionalBinding" transactionFlow="true" />
            </netTcpBinding>
        </bindings>
        <comContracts>
            <comContract contract="{23DF9852-7126-11D1-BDB2-00600807E871}"
              name="_CBroker" namespace="http://tempuri.org/23DF9852-7126-11D1-BDB2-
                   00600807E871" requiresSession="true">
                <exposedMethods>
                    <add exposedMethod="SubmitOrder" />
                </exposedMethods>
            </comContract>
        </comContracts>
        <services>
            <service behaviorConfiguration="ComServiceMexBehavior" name="{1B33F254-
              98EC-4B32-9AFF-FEC8AF02449C},{23DF9853-7126-11D1-BDB2-00600807E871}">
                <endpoint address="_CBroker" binding="netTcpBinding" 
                  bindingConfiguration="comTransactionalBinding"
                    contract="{23DF9852-7126-11D1-BDB2-00600807E871}" />
                <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
                <host>
                    <baseAddresses>
                        <add baseAddress="net.tcp://localhost:9000/market/service" />
                    </baseAddresses>
                </host>
            </service>
        </services>
    </system.serviceModel>
</configuration>

 

Note: The generated configuration file also contains the netNamedPipeBinding binding since this is generated by default for Com+ hosting. The configuration file also contains the netTcpBinding element because TCP was selected as the communication mode. The end point of the service uses the netTcpBinding.

Command line Usage

ComSvcConfig.exe is used to execute the Component Service Model Tool in the command line. The generated output is same for both the command line and GUI versions.

Example:

Installing an interface as Web Service:

ComSvcConfig.exe /install /application:Market /contract:Market.CBroker, _Cbroker /hosting:complus

This command exposes the interface _CBroker of the component Market.CBroker that belongs to the COM+ application market.

Uninstalling the Web Service for an interface:

ComSvcConfig.exe /uninstall /application: Market /contract:Market.CBroker, _CBroker /hosting:complus

Running ComSvcConfig.exe with the /uninstall option removes the Web Service implementation of the interface. In the example above, the Web Service is removed for the _CBroker interface.

If required, only a few methods of an interface can be exposed by using the options shown below.

Here, only the "SubmitOrder" method of the _CBroker interface is exposed as a Web Service method:

ComSvcConfig.exe /install /application:OnlineStore Market /contract:Market.CBroker, _CBroker.(SubmitOrder) /hosting:complus

The binding cannot be specified using the command line mode which means the endpoint of the generated web service will use the default binding, NetNamedPipeBinding.

Although using the Component Service tool makes the process simple, knowledge of bindings, hosting modes and a good understanding of WCF security is required for better integration. For example, this tool exposes the given service using NetNamedPipeBinding by default, but another binding such as NetTcpBinding may be appropriate in certain cases. For Web scenarios, WSHttpBinding will be more appropriate.

Choosing an appropriate hosting mode that matches the application's usage and performance needs is important. For example, if the COM+ application must be accessed via DCOM then Com-hosted or Web-hosted hosting modes are suitable. When the web service is hosted in COM+, there is no process hop for calls from the Web Service to the COM+ application. While, if the Web Service is Web hosted then there is a process hop for calls from the Web Service to the COM+ application. This could be another consideration while selecting the hosting mode.

The security is governed by the security settings for the WCF channel, so using an appropriate secure binding is important. For example, depending on the selected hosting mode, Impersonation might be required and this should be set in both the exposed web service as well as the WCF client that will use the web service. In complex application scenarios, the security considerations may not be so simple. So, to ensure proper integration of COM+ applications with WCF a good understanding of WCF will be required.

For more details on this approach, please go through Windows SDK Help.

Migrating COM+ services to WCF

COM+ helps build enterprise level distributed applications that require scalability, security, reliability as well as transactional capabilities. COM+ provides the infrastructure for transaction management, life time management, concurrency control, security management, queuing support and a host of other services to the components. Component Services Explorer is a GUI tool provided in the COM+ environment. It is used by developers and administrators for easy configuration, deployment and monitoring of COM+ applications.

The metadata related to the components on a given server machine is present in the Catalog Library files located in the %systemroot. COM+ applications also depend on Windows registry apart from the COM+ catalog. In contrast, WCF services are managed .NET components and they do not have any dependency with Windows registry.

Since security, transaction management and reliability are the three important aspects of any enterprise level business application; this section will focus on these three aspects. However, before we delve into details, we'll understand instancing and concurrency model of COM+ and WCF services.

COM+ services depend on the one-object-per-client instancing model to work as expected. The one-object-per-client model is not enforced by COM+ and a single instance can be shared by many clients but COM+ services may not work well in such circumstances. The one object per client does not hold if Just in Time Activation (JITA) service is used along with Object pooling. In this case, the component instances can be used to serve different clients although at a give point in time there is just one client using the object. Again a reference to this object can be passed to another client but the results of this could be unexpected. So one-object-per-client is the recommended instancing model at a given point in time.

Concurrency in COM+ can be viewed from the traditional COM threading models and the COM+ Synchronization service. The COM threading model uses apartments as basic concurrency or synchronization units. Single-threaded apartments (STA), multi threaded apartments (MTA) and neutral threaded apartments (NTA) are the available threading models. (However, selecting a specific programming model to develop the application would restrict the available threading model. For example, the threading model of components developed in Visual Basic is STA. (Visual Basic also provides Single threaded model). In Windows 2000, the threading model is used to determine which threads can access the component instance. Concurrency is determined by Synchronization. Synchronization in COM+ happens through Activities. An Activity is a synchronization unit that contains component instances belonging to one logical chain of execution or Causality. The calls made into an Activity are serialized using the Activity lock.

The synchronization attribute, that is set in the Concurrency tab using the Component's properties page in the Component Services Explorer (see Figure 8) determines whether an object runs in activity or not. A component's Synchronization attribute can be any one of the following values:

  • Not supported
  • Required
  • Requires New
  • Supported
  • Disabled

Component Services Explorer view of component concurrency options

Figure 8. Component services explorer view of the concurrency options for a component

COM+ contexts are another important topic that should be mentioned here. Contexts contain the exact runtime environment required by components. Every component instance has a single context. The same context can be shared by multiple component instances if all of them require the same runtime features. Every context is associated with an Object Context and all component instances sharing a single context have the same Object Context. COM+ infrastructure uses interception to understand the contexts of COM+ components.

To efficiently manage the instancing or lifetime of objects, COM+ provides Just-in-time-activation (JITA) and object pooling services.

Using JITA, the server resources can be used optimally when multiple clients access the COM+ application on the server. JITA provides great scalability in scenarios where client applications hold references to objects for long durations but use these references sparingly or intermittently. JITA ensures that a component instance is created just when there is a call to its methods and that the instance is deactivated on the completion of the method call. Enabling JITA for components automatically results in Synchronization requirements. COM+ marks the Synchronization support for the component as Required. In fact COM+ disables all other Synchronization support other than Required and Requires New.

Deactivating the component instance is done by COM+ and this can happen explicitly or automatically on return from a method. The context object contains a Done bit that is used to deactivate the object. Setting the Done bit to True deactivates an object and this can be set to True programmatically by calling SetComplete method of the context object or by calling SetDeactivateOnReturn (True) of the IContextState interface. This is explicitly stating when the deactivation should happen. COM+ can also be instructed to automatically deactivate the object upon return from the method by selecting the "Automatically Deactivate this object when this method returns" check box. This is available in the Properties page of the method (See Figure 9).

 

Automatic Deactivation property for a method

Figure 9. Component services explorer showing automatic deactivation property for a method

Expensive time-consuming object creations are another bottleneck to achieving good performance and scalability of the applications and these can be overcome by object pooling. Object pooling is simply the process of maintaining a pool of component instances that can serve client requests. There is a separate pool for each object type. Object pooling can be enabled at the component level and pooling characteristics like pool size, creation time out etc can be easily configured. The threading model of components that require the object pooling service should be either "MTA" or "NTA". Components that are "Apartment" threaded cannot be pooled because of their thread affinity.

To configure object pooling for a component, select the Activation tab of the component's properties Page / screen in the Component Service Explorer (see Figure 10).

Object Pooling as seen in the Component Services Explorer

Figure 10. Object pooling for a component as seen in the Component Services Explorer

The Maximum pool size can be used to provide Throttling behavior that will restrict the number of concurrent clients to the maximum pool size value.

Having seen the instancing behavior of the COM+ service, let us understand instancing and concurrency details of WCF services. WCF provides several mechanisms to help manage the lifetime of service instances. To be more precise, in WCF, the life time of service instance is controlled through the InstanceContext object. Both InstanceContext and the service instance are independent objects.

Figure 11 illustrates the relationship between InstanceContext and the service instance:

InstanceContext and service instance

Figure 11. InstanceContext and service instance

(Figure 11 has been taken from the MSDN article "Discover Mighty Instance Management Techniques For Developing WCF APPS" by Juval Lowy

By default, the lifetime of the InstanceContext is the lifetime of the service instance. It is possible to make the lifetime of the service instance independent of the InstanceContext.

The following instancing behaviors are provided by WCF to manage InstanceContext:

  • PerCall– An InstanceContext is created for every method call from the client. The InstanceContext is deactivated when the call ends.
  • PerSession– A new InstanceContext is created for a new client session. The InstanceContext lifetime is the lifetime of the session and the instance is deactivated at the close of the session. InactivityTimeout of the binding is used to confine the lifetime if the client does not close the session indefinitely and the there is no activity from the client. PerSession is the default instancing behavior.
  • Single – A single InstanceContext handles all client requests. (NOTE: The requests will be handled in sequence if the ConcurrencyMode is not Multiple.)

 

WCF provides three Concurrency modes:

  • Single– There is just one thread executing in the instance context at any given time. Other threads are blocked until the executing thread returns.
  • Reentrant– This is like Single with the only difference being that another thread can execute in the instance context when the current thread executes outside the service boundary e.g.: calling another service.
  • Multiple– Multiple threads can execute within the instance context and the service must be thread-safe.

If thread affinity is required then UseSynchronizationContext property of the ServiceBehaviorAttribute can be set to true. This property is true by default and implies that all the calls to the service will run on the thread specified by the current synchronization context.

Having understood the instancing and concurrency behavior of COM+ and WCF, we'll explore the migration of instancing and concurrency of COM+ to WCF.

As indicated previously, in COM+ there is one object per client at any given instance of time. This is not mandatory in COM+ but everything works well if this is adhered to. By default WCF services also exhibit this behavior although this can be changed using the InstanceContext attribute.

The code snippet below illustrates a one service instance per client.

using System;
using System.Text;
using System.ServiceModel;
namespace ComplusToWcf.Market
{
    public interface IBroker
    {
        [OperationContract]
        long SubmitOrder(string customer, string product, long
                quantity, string orderStatus);
    }
    
    //Service class which implements the service interface
    
    public class BrokerService : IBroker
    {
    
        //InstanceContext has been set to PerSession to provide the 
        //same behavior as COM+ instancing where a client is 
        //associated with one COM+ activity context
        
        [OperationBehavior(
                InstanceContext = InstanceContextMode.PerSession)]
        public long SubmitOrder(string customer, string product, long
                    quantity, string orderStatus)
        {
             return 0;
        }
    }
}

The table below shows the relationship between InstanceContextMode and Concurrency mode:

 

InstanceContextMode

ConcurrencyMode

Result

PerCall

Not applicable

Since there is a separate instance servicing each method call from the client there can be a maximum of one thread executing one method given a service instance at any given time.

PerSession

Single / Reentrant

There is only one thread executing in the PerSession instance at any given time.

If the concurrency mode is "Reentrant" another thread from the same client can execute when the current thread is executing outside the service boundary.

PerSession

Multiple

Concurrent requests from the client can be serviced by the same service instance at any given time.

Single

Single / Reentrant

Only one request is served at a time by the service instance.

If "Reentrant" is the concurrency mode then another request from the same client can be serviced when the current request executes outside the service boundary.

Single

Multiple

The same service instance can serve multiple clients' multiple requests concurrently.

The synchronization service of COM+ is a good option to provide thread safety automatically to MTA components. It is recommended to mark STA components as requiring synchronization. This clearly tells the Service Control Manager (SCM) to create the component instances in the application's STA pool rather than the Host STA.

The ServiceBehaviorAttribute in WCF has a property called UseSynchronzationContextthat can be set to True when thread affinity is required. The concurrency mode and the UseSynchronizationContext can be used to support COM+ threading models and synchronization services.

Although there is nothing explicit like JITA and object pooling in WCF, it is easy for a WCF service to use JITA and object pooling with a few workarounds. We'll now explore how these important COM+ services can be produced in WCF.

JITA with automatic deactivation and explicit deactivation by manipulating the "Done" bit in COM+ can be reproduced in WCF.

JITA with automatic deactivation can be achieved by setting the value of the InstanceContextMode property of the ServiceBehaviorAttribute value to "PerCall". This implies that a new InstanceContext of the service instance is created to serve every call made by a client. The InstanceContext of the service object is destroyed at the end of the method. The clients of the service are not aware of this object creation and destruction as they hold the same proxy reference. It is wise to use JITA scheme for services that can be instantiated quickly otherwise the scalability provided by JITA is wasted. If object activation and deactivation is time consuming then creating and destroying them for each method call will result in poor performance thus affecting the scalability of the application. If a service uses JITA then it cannot hold any state between calls. If state needs to be maintained between calls then the state can be stored, for example, in a database before returning from the method and retrieved from the database at the start of the method.

The code snippet below represents how JITA with automatic deactivation can be achieved in a WCF service:

using System;
using System.Text;
using System.ServiceModel;

namespace ComplusToWcf.Market
{
    public interface IBroker
    {
        [OperationContract]
        long SubmitOrder(string customer, string product, long
                quantity, string orderStatus);
    }
    
    //Service class which implements the service interface
    
    public class BrokerService : IBroker
    {
        //InstanceContext has been set to PerCall to provide the 
        //equivalent of JITA
        [OperationBehavior(
                InstanceContext = InstanceContextMode.PerCall)]
        public long SubmitOrder(string customerID, string product, long
                    quantity, string orderStatus)
        {
            return 0;
        }
    }
}

JITA with explicit deactivation can also be achieved in WCF. For a service whose InstanceContextMode is "PerSession" there are two controls to deactivate a service instance. One is the ReleaseInstanceModeproperty of the OperationBehaviorttribute. The ReleaseInstanceMode takes the following values of the ReleaseInstanceMode enum:

  • ReleaseInstanceMode.BeforeCall – the service instance is released before the method call.
  • ReleaseInstanceMode.BeforeAndAfterCall – the service instance is released before the method begins and upon return from the method.
  • ReleaseInstanceMode.AfterCall – the service instance is released upon return from the method.

The ReleaseInstanceModeof the OperationBehaviorAttributeis available for every service operation. To draw an analogy, "Automatically Deactivate this object when this method returns" checkbox in COM+ is available on every method of the component that uses the JITA service. Using ReleaseInstanceMode.AfterCall for every method for a service with InstanceContextMode as "PerSession" is equivalent to JITA with automatic deactivation. Then again there is really no difference between this and "PerCall" instancing! But it is quite useful if this is used on just the required methods to ensure that clean up is done either before, after or before and after a method call.

The code snippet below shows setting the ReleaseInstanceMode property to "AfterCall":

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class Person : IPerson
{
    private string name;
    private int age;
    private Gender gender;
    
    #region IPerson Members
    
    [OperationBehavior(ReleaseInstanceMode = 
            ReleaseInstanceMode.AfterCall)]
    void IPerson.Add(string name, int age, Gender gender)
    {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
}

Another way to achieve explicit deactivation in WCF is using the ReleaseServiceInstance method of the InstanceContext. This is similar to calling SetDeativateOnReturn of the IContextState interface or calling SetComplete of the object context in COM+.

The code snippet below illustrates this:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class Person : IPerson
{
    private string name;
    private int age;
    private Gender gender;
    
    #region IPerson Members
    
    void IPerson.Add(string name, int age, Gender gender)
    {
        this.name = name;
        this.age = age;
        this.gender = gender;
        
        //release the service instance
        OperationContext opContext = OperationContext.Current;
        opContext.InstanceContext.ReleaseServiceInstance();
    }
}

Now we'll look at how object pooling can be supported in WCF. COM provides object pooling out-of-the-box. As seen earlier, WCF supports various instancing schemes and concurrency modes. Object pooling is not part of WCF by default. But if required, custom object pooling can be built by extending WCF through the InstanceProvider class.

Windows SDK contains a working sample of object pooling.

One of the important uses of object pooling is Throttling. By setting the maximum number of pooled objects that can be created, we are controlling the number of clients that can be served at a time. Once the maximum pool size is reached, any further requests to the component are queued. This prevents over-consumption of important resources. Throttling is provided out-of-the-box in WCF. Throttling can be achieved by using the ServiceThrottlingBehavior class in code or the serviceThrottlingBehavior element in configuration. MaxConcurrentCalls, MaxConcurrentInstances and MaxConcurrentSessions are the three available throttles.

The configuration file section shown below displays how throttling can be configured for a WCF service:

<system.serviceModel>
    <behaviors>
        <serviceBehaviors>
            <behavior name="PersonBehavior">
                <serviceThrottling maxConcurrentCalls="2"
                    maxConcurrentInstances="5"/>
                <serviceMetadata httpGetEnabled="True"/>
                <serviceDebug 
                    includeExceptionDetailInFaults="False"/>
            </behavior> 
        </serviceBehaviors>
    </behaviors>
</system.serviceModel>

Having understood instancing and concurrency, we'll move to the security aspects of COM+ and WCF.

Security

(WCF provides security at both transport level and message level). Message based security is quite powerful because the messages are secured until the call reaches the intended recipient (service). Transport based security on the other hand secures messages only during transmission. COM+, unlike WCF, provides security only at the transport layer. WCF also offers rich security options and customizations as compared to the plain, out-of-the-box security services offered by COM+. WCF provides a wholesome security package that is crucial for building highly secure, interoperable web services WS-* protocols support. COM+ in comparison offers facilities to build secure intranet distributed applications and lacks the necessary interoperability features required to build secured web applications.

In WCF, the security options can be chosen to suit the application's needs. The security mode property of the binding can be used to choose transport security or message security or both. The security modes available are:

  • None: Security is completely turned off at the transport layer and message layer. BasicHttpBinding is the only system binding that turns off security by default.
  • Transport Security: This is provided at the transport layer and hence is dependant on the transport used.
  • Message security: SOAP message security is provided and the messages are secured using one of the WS-* specifications that is WS-Security protocol.
  • TransportWithMessageCredential: The hybrid security mode that provides message security for client authentication and provides transport security for message integrity and confidentiality and server authentication.
  • Both: Authentication, integrity and confidentiality is provided at both transport and message layer. [Only NetMsmqBinding supports this security mode.]

The table below gives a quick summary of the important aspects of security management in COM+ and WCF:

Security aspect

COM+

WCF

Authentication

The authentication options available in COM+ are:

  • NTLM (NT Lan Manager)
  • Kerberos
  • SChannel– SSL 2.0, SSL 3.0, TLS 1.0, Private Communication Technology
  • SNego- Negotiates either Kerberos or NTLM.

The following are the possible authentication levels:

  • None– Security is disabled
  • Connect– Authentication occurs when connection happens
  • Call– Authentication happens for the first RPC packet of each method call.
  • Packet– Authentication happens for every RPC packet

 

Authentication involves verification of the supplied credentials. WCF provides a wide range of credential types because WCF services can serve internal customers, partners and internet customers.

The credential types in the transport security mode are:

  • None
  • Basic
  • Digest
  • NTLM
  • Windows
  • Password
  • Certificate

The credential types in the message security mode are:

  • None
  • Windows
  • Username
  • Certificate
  • IssuedToken

The service identity type can be stated explicitly and can be any one of the following:

  • Domain name service
  • Certificate
  • Certificate reference
  • RSA
  • Service Principal Name
  • User Principal Name

Data integrity and confidentiality

COM+ provides data integrity and confidentiality when data is in transit across the wire. Data security is provided by the following authentication levels:

  • Packet Integrity– A checksum is appended to every packet to verify that the data has not been tampered with.
  • Packet Privacy– Every packet is encrypted to guarantee confidentiality.

It should be noted that both these authentication levels provide authentication at the Packet level. Packet Privacy guarantees packet authentication, packet integrity and packet privacy.

All system bindings in WCF except the basic profile ensure data protection and privacy at the transport level by default. If the binding supports message security and if the security mode is message security, then the data integrity and confidentiality is also guaranteed at the message level. For message security mode, the Protection level can be configured. The following are the possible protection levels:

  • None
  • Sign
  • EncryptAndSign

Using the protection level, parts of message alone can be protected. The default is EncryptAndSign. The algorithm used for encryption can also be changed from the default one by using the AlgorithmSuite property of the binding.

Access control

COM+ offers role-based access control. Using the Component Services Explorer, developers can create custom roles for a COM+ application. Users and User groups from the Windows domain are mapped to the roles. Roles provide a convenient abstraction – separating security design from deployment. At development time, developers use roles to implement access control and at deployment, administrators at client locations map user groups and users on their Windows domain to the roles. Access control through roles can be configured at the component, interface and method levels. SecurityCallContext is used to provide finer granular access control programmatically.

WCF provides two authorization facilities – role based authorization and claims-based authorization.

Roles based authorization is not directly provided by WCF but is provided by using capabilities of .Net 2.0. The role based authorization can be carried out by:

  • PrinicipalPersmissionAttribute
  • ASP.NET membership provider
  • ASP.NET role provider
  • Authorization Manager or AzMan

WCF provides claims based authorization using the Identity model to create claims by parsing incoming messages and custom authorization schemes can be used to authorize clients based on the furnished claims.

Impersonation

The impersonation levels are:

  • Anonymous
  • Identify
  • Impersonate
  • Delegate

Impersonation is possible for the transport as well as the message security mode.

Impersonation using Transport security

The levels of impersonation possible using transport security are:

  • None
  • Anonymous
  • Identify
  • Impersonate
  • Delegate

Impersonation using message security

For impersonation to work in the message security mode, the user accessing the service needs to be traced to a valid Windows account. This is as impersonation works using the Windows token available for Kerberos and Kerberos extensions.

Auditing

COM+ provides 2 classes that can be used for auditing security:

  • SecurityCallContext
  • SecurityIdentity

SecurityCallContext contains the chain of callers starting from the original caller to the caller of the current component. The SecurityCallContext contains references to the SecurityIdentity of the original caller and the direct caller.

The SecurityIdentity can be used to log information about the caller such as the account name, authentication level etc.

Auditing is enabled by writing custom code that accesses information from the SecurityCallContext and SecurityIdentity classes and logs the information to the Windows Event Viewer or any other custom log like a database.

Auditing in WCF can happen at 2 levels:

  • Security authorization level – caller authorization
  • Message level – message is checked and the caller is authenticated

The outcome of the security check can be logged selectively i.e. either success, failure or both can be logged.

Auditing can be logged to the Windows Event Viewer. Either the application log or security log can be used. WCF provides the following entities to program auditing:

  • ServiceSecurityAuditBehavior
  • AuditLogLocation
  • MessageAuthenticationAuditLevel
  • ServiceAuthorizationAuditLevel
  • SuppressAuditFailure

Auditing can be enabled programmatically or through configuration.

The section below explores the authentication and access control aspects in detail and provides guidelines to migrate authentication and authorization of COM+ to WCF.

Authentication settings for a COM+ application are configured using the Security tab in the Component Services Explorer. The screen shot given below displays the Authentication settings available:

Authentication levels for COM+ application

Figure 12. Authentication levels for COM+ application

 

The table below describes the Authentication settings:

Authentication Level

User identity

Data Integrity

None

No authentication

No authentication

Connect

Authenticated every time the client creates a new object in the application or the client connects to an existing object in the application for the very first time.

No

Call

Authentication happens for every method call

No

Packet

Authentication happens for every packet sent by the caller.

No

PacketIntegrity

Authentication happens for every packet sent by the caller.

Checksum is appended to every packet to ensure data integrity.

PacketPrivacy

Authentication happens at the packet level.

Every packet is encrypted thus providing both data integrity and privacy.

WCF provides a wide range of authentication mechanisms because WCF services can serve internal customers, partners and the internet customers at large. The credentials available for authentication are driven by the security mode of the binding.

In the case of system bindings, if no credentials are explicitly specified then the default credential of that specific binding is used for authentication. For example, NetTcpBinding by default uses Windows credentials. So choosing the right security option other than the default ones could be required to suit the security policy of the WCF services when migrating from COM+.

In WCF, clients are authenticated based on the client credentials that are a part of the security information of the binding for a given end point.

There are two levels of client authentication:

  1. The client is authenticated just once before any message is sent to the service. All conversations after this initial authentication happen using a secure context.
  2. The client is authenticated for every message sent. This happens if there is no security context established.

The client knows the identity of the service end point and this information is present in the client's configuration (design time). At run time, before the client actually sends any message to the service, the end point identity as present in the client's configuration is matched against the service's identity. For NTLM credential type, service authentication does not happen.

So, migration of the authentication service of COM+ to WCF is straight forward and is achieved by specifying the properties of the binding used at the endpoint. In WCF, all system bindings except WSDualHttpBinding and WSFederationHttpBinding support transport based security.

The WCF equivalents of the COM+ authentication levels are given below:

Authentication level – None

This can be configured or can be programmed. The section of the configuration file given below shows using NetTcpBinding with security turned off:

<netTcpBinding>
    <binding name="NotSecuredTcpBinding">
        <security mode="None"/>
    </binding>
</netTcpBinding>

WCF provides authentication for every packet header in every method call when transport security is selected. This is equivalent to the "Packet" authentication level of COM+. "Packet" authentication is more secure than "Connect"and "Call" authentication levels. "Call" authentication level in COM+ is automatically promoted to "Packet". Thus enabling transport security mode for a binding is all that needs to be done to migrate "Connect", "Call" and "Packet" authentication levels of COM+.

The code snippet displayed below shows the usage of transport security for NetTcpBinding with Windows client credentials:

<netTcpBinding>
    <binding name="SecuredTcpBinding">
        <security mode="Transport">
            <transport clientCredentialType="Windows"/>
        </security>
    </binding>
</netTcpBinding>

When transport security is enabled, Packet privacy and integrity is guaranteed by default.

Once the client is authenticated, the access rights of the client are examined and the client's access to resources is controlled accordingly. This is authorization or access control. Having seen migration of authentication, we'll see how authorization in Com+ can be migrated to WCF. Authorization in COM+ is role based and we'll only consider role based authorization feature of WCF for migration.

The migration of role-based access control can be broken into several steps:

  1. Creating roles
  2. Enabling access control
  3. Migrating any authorization code

Step 1 – Creating roles

Roles for a COM+ application are created using the Component Services Explorer by using the Roles folder located under the application for which authorization is being configured (see Figure 13).

Roles for a COM+ application

Figure 13. Roles for a COM+ application

 

The users can be mapped to the created roles using the Component Services Explorer. Role providers and authorization modes form the core of WCF authorization. Role providers enable administration and enforcement of roles based on the authorization modes. The various authorization modes are UseWindowsGroups (default), UseAspNetRoles, Custom and None.

Asp.Net roles can be stored in a Sql Server database (different providers can be created to store them in different storages). One of the ways is to create users and roles using the roles APIs available in .Net.

Authorization Manager (AzMan) provides a user interface to create roles, define access control and at runtime performs authorization for the defined roles. AzMan can be used with Asp.Net roles to provide role-based access.

We will not go into the details of creating roles here. For more information on creating the roles "ASP.Net Role Provider" and "AzMan," see:

https://msdn2.microsoft.com/en-us/library/aa354509.aspx - for understanding ASP.Net membership and role provider.

https://msdn2.microsoft.com/en-us/library/ms998336.aspx - for understanding AzMan.

Step 2 – Enabling access checks

In COM+, access checks are enforced at the application and component level. The Component Services Explorer can be used to provide access control at these levels. The roles can be used to provide access controls to components, interfaces and methods. Consider a simple example of a Calculator component in which the Add, Subtract, Multiply and Divide methods are exposed. Add and Subtract can be performed by all users. Only Registered Users can perform Multiply while only Super Users can perform Divide. Access checks to ensure this can be configured using the Component Services Explorer (see Figure 14).

Authorization at the method level

Figure 14. Authorization at the method level

 

WCF manages role-based access using role providers. Once the roles haev been created, authorization in WCF requires a role provider to perform the authorization check, choosing the authorization mode and choosing a binding that supports the appropriate client credentials. The role providers can be specified in configuration or in code.

Typically, COM+ application developers define the roles for an application at design time. At client locations, during deployment, administrators map Windows user groups to the roles. COM+ access control is limited to Windows users for a given Windows domain. So every user that needs to access the COM+ application must be a valid Windows user.

PrinicpalPermissionAttribute in WCF can be used to provide COM+ a way to access control for the Windows domain. PrinicipalPermissionAttribute can use Windows user groups as well as custom roles to provide role based authorization. If the default authorization mode of UseWindowsGroup is used, then PrinicpalPermissionAttribute works with windows user groups. Using the Custom authorization mode, custom role providers can be developed to create custom roles over the Windows user groups to provide the equivalent role based authorization of COM+.

The code snippet below shows restricting access to the Divide operation of a WCF service to Super Users. Super Users should be a Windows user group in the domain:

  // Only allowed Super Users can perform Divide operation
  [PrincipalPermission(SecurityAction.Demand, Role = "Super Users")]
  public double Divide(double n1, double n2)
  {
        double result = n1 / n2;
      return result;
  }

The authorization mode need not be specified explicitly because UseWindowsGroup is the default authorization mode. Also, since Windows is the client credential for authentication and authorization, there is no need to explicitly state a role provider. Any binding that supports Windows credentials can be used. This is the case with all the system bindings except BasicHttpBinding. Since most COM+ application are Intranet based, using NetTcpBinding will be appropriate.

If the COM+ application requires a client certificate for authentication, this client should be mapped to a Windows user in the domain where the COM+ application is running. This is because COM+ only understands Windows users.

PrinicpalPermissionAttribute can be used in WCF to migrate the authorization behavior of such an application.

The code snippet below shows using the PrinicipalPermissionAttribute for this scenario:

  [PrincipalPermission(SecurityAction.Demand, Name = "CN=InfosysUsers; 03339863d047e74871336264765c4c9d421d6b52")]
  public double Divide(double n1, double n2)
  {
        double result = n1 / n2;
      return result;
  }

Here the client's primary identity that is formed with the subject name and the thumb print of the certificate should be the value for the Name property of the PrincipalPermissionAttribute. In the code snippet above, the subject name or common name is InfosysUsers and the thumb print is 03339863d047e74871336264765c4c9d421d6b52. This means all clients with the certificate common name InfosysUsers will be allowed to perform the Divide operation. The client certificate should be mapped to the Windows user group InfosysUsers for this to work.

True to its promise of being a complete interoperable framework, WCF supports custom roles (eg, Asp.net) roles to define roles for users that are not part of the Windows domain. This is a big advantage while selecting WCF over COM+ when creating truly distributed applications.Using Asp.Net membership provider, you can provide access to UserName/password. You would typically have one user for every client. You can then use the Asp.Net Role provider to create roles and map these users to roles thus providing the necessary authorization policy.

For WCF to use the Asp.Net roles for authorization:

First, instruct WCF to use ASP.Net roles for authorization. This can be done through coding (for self-hosted services) as well as through configuration settings.

The Web.config file section that shows using Asp.Net roles is given below:

<behaviors>
    <serviceBehaviors>
        <behavior name="CalculatorServiceBehavior" >
            <serviceAuthorization principalPermissionMode = "UseAspNetRoles" />
        </behavior>
    </serviceBehaviors>
</behaviors>

When the principalPermissionMode is UseAspNetRoles, by default the SqlRoleProvider is used as the role provider.

Second, do the authorization. PrinicipalPermissionAttribute can be used to provide access control to a service's operations using Asp.Net roles. The code snippet below shows restricting access to the Divide method to users belonging to the Asp.Net role Super Users:

  [PrincipalPermission(SecurityAction.Demand, Role = "Super Users")]
  public double Divide(double n1, double n2)
  {
        double result = n1 / n2;
      return result;
  }

Note: PrinicipalPermissionMode must be set to UseAspNetRoles for using Asp.Net roles. If this is not done, the code snippet shown above will verify if the user belongs to the Windows user group Super Users.

Third, set the client credential type for the binding to UserName as shown in the configuration file portion below:

<bindings>
    <wsHttpBinding>
        <binding name="Binding1">
            <security mode="Message">
                <message clientCredentialType="UserName"/>
            </security>
        </binding>
    </wsHttpBinding>
</bindings>

Optionally, one could use Authorization Manager as the role provider for Asp.Net roles. The portion of the web.config file shown below configures AzMan as the role provider:

<system.web>
<!--Configure AzMan role provider-->
    <roleManager enabled="true" defaultProvider="AzManRoleProvider">
        <providers>
            <add name="AzManRoleProvider"
                type="System.Web.Security.AuthorizationStoreRoleProvider, 
                    System.Web, Version=2.0.0.0, Culture=neutral, publicKeyToken=b03f5f7f11d50a3a"
                connectionStringName="AzManPolicyStoreConnectionString"
                applicationName="MembershipAndRoleProvider" />
        </providers>
    </roleManager>
</system.web >

You can use this role provider for authorization with Asp.Net roles. The portion of the web.config file below shows using the AzMan role provider to authorize the WCF service:

<behaviors>
    <serviceBehaviors>
        <behavior name="CalculatorServiceBehavior" >
            <serviceAuthorization principalPermissionMode=
                "UseAspNetRoles" roleProviderName="AzManRoleProvider" />
        </behavior>
    </serviceBehaviors>
</behaviors>

The PrinicipalPermissionAttribute can also be used with client certificates and Asp.Net role provider to provide access control to operations. In this case, the value of the name property is used and the Asp.Net Role Provider is used to check the access rights of this user.

Step 3 – Migrating authorization code

COM+ provides programmatic security over and above the declarative security. The SecurityCallContext can be used to program security in COM+. In WCF, PrinicipalPermissionMode and ServiceSecurityContext can be used to provide programmatic control. The ServiceSecurityContext class in WCF can be examined, for example, to obtain the identity of the client, to check if the client was authenticated, or to check if the client is anonymous.

Transactions

COM+ and WCF manage transactions in almost the same manner. WCF's transaction management's superiority is due to its abilities to flow transactions to and from other transaction infrastructures using WS-Atomic transactions as well as System.Transactions that was introduced in .NET Fwk 2.0. In the Windows environment, using System.Transactions results in the engagement of Microsoft Distributed Transaction Coordinator (MSDTC) only when it is absolutely necessary using Promotable transactions. WCF, as did EnterpriseServices in .Net 2.0, thus comes offers the performance incentive of promotable transactions. WCF transaction management capability also provides fine grained transaction support.

Resource managers, transaction root and the two-phase commit protocol form the core of the transaction architecture in both the technologies. The activation context plays a key role in COM+ transaction management. Every COM+ transactional object has its own activation context. The activation context object has a consistency bit which states if the object has voted to commit or abort a transaction. In WCF, TransactionScope provides transactional support to a service. The completion of a TransactionScope successfully, signals that the service has voted to commit the transaction.

In COM+ the transaction is aborted if anything goes wrong or if the consistency bit of the context object is set to False Similarly in WCF, if the transaction has not completed either automactically or explicitly or if an exception has occured, then the transaction is aborted. Resource managers are auto-enlisted in both the cases.

COM+ transactions are defined at the component level, while in WCF the transactions can be defined at operation level. For example, Transaction Timeout and Transaction Isolation Levels are defined at the component level in COM+ but in WCF they can be set at the service level. Transaction Timeout is also used to control the outcome of the transaction. If the transaction does not complete within the predefined timeout then the transaction is aborted.

In COM+, transaction characteristics of a component can be configured in the Component Services Explorer and it can have any of the following values:

  • Disabled
  • Not Supported
  • Supported
  • Required
  • Required New

Transaction support can be chosen using the Transaction support property of the component in Component Services Explorer (see Figure 15):

Transaction support for a component

Figure 15. Transaction support for a component

 

[A component's transaction requirements can also be expressed in the code as transaction attributes of the Coclass in the IDL. The attributes are TRANSACTION_REQUIRED, TRANSACTION_NOT_SUPPORTED, TRANSACTION_SUPPORTED and TRANSACTION_REQUIRES_NEW.]

The transaction isolation level can be Serialized, Any, Repeatable Read, Read Uncommitted and Read Committed.

Since COM+ transactions require the object to be destroyed when a transaction ends, JITA is automatically enabled when the COM+ component's transaction support is Supported, Required or Requires New.

[In COM+ applications, transaction can be programmatically achieved, by using specific transaction attributes and IContextState interface.]

Transaction support of a COM+ component can be specified in the IDL file using the following attributes:

  • TRANSACTION_NOT_SUPPORTED
  • TRANSACTION_SUPPORTED
  • TRANSACTION_REQUIRES_NEW

There is no attribute to disable transactions because this is usually chosen while importing Com components into COM+ and there is no need to do this programmatically.

Here is an IDL file showing a component that requires a transaction:

[
    uuid(01F91616-7AFE-4cb2-8BAF-6ED26C7532F6),
    Helpstring("Broker class"),
    TRANSACTION_REQUIRED
]
coclass CBroker
{
    [default] interface _CBroker;
};

An object can vote on the outcome of a transaction. The IContextState interface provides the following methods to vote on the transaction:

  • SetMyTransactionVote – accepts TransactionVote enumeration values, TxCommit or TxAbort.
  • GetMyTransactionVote – Returns TransactionVote enumeration values, TxCommit or TxAbort.

Here is the code snippet for setting the transaction vote:

Dim contextState As IContextState
Set contextState = GetObjectContext
contextState.SetMyTransactionVote (TxCommit)

IContextState interface also has two more methods to set and get the Done bit (used to indicate completion of a method):

  • SetDeactivateOnReturn – Sets the done bit to True or False.
  • GetDeactivateOnReturn – Gets the done bit.

Traditionally in VB, to maintain compatibility with MTS, the ObjectContext is used to vote on a transaction using the methods SetComplete and SetAbort. SetComplete sets the Done bit and sets the vote to commit. SetAbort sets the Done bit to "True" and votes the transaction to abort.

Imperative or programmatic transactional approach can also be employed if an application requires it. The System.Transactions namespace provides two classes, Transaction class and TransactionScope class. Transactions are automatically managed by the WCF infrastructure when TransactionScope class. The TransactionScope class provides a way to mark a block of code participating in a transaction without having to make transaction specific calls. Resources are auto-enlisted since they can detect the ambient transaction.. Creating a new instance of TransactionScope class creates a transaction scope. The TransactionScope constructor accepts TransactionScopeOptions enumeration values, Required, Requires New or Suppress. Calling the Complete method implies voting to commit the transaction.

Transactions in WCF can be expressed programmatically and can be configured in the configuration file for the service. WCF provides a number of features to manage transactions like controlling incoming transactions to a WCF service, choosing the transaction protocol, executing a block of code within a transaction scope, fine tuning transactions by specifying transaction timeout and isolation levels etc.

WCF provides attributes and out-of-the-box classes to manage transactions programmatically. The following sections describe the transaction management infrastructure of WCF.

Managing Incoming transactions

Incoming transactions are managed using TransactionFlowAttribute and TransactionFlow binding property of the binding used.

The TransactionFlow binding property is used to enable or disable incoming transaction flow and is available for a service end point, for a binding in particular. This is configured in the application configuration file for the service. The portion of the application configuration file containing this binding property is shown below:

<!-- Transaction flow for the binding is set to true 
    to allow incoming transaction-->
<bindings>
    <netTcpBinding>
        <binding name="transactionalTcpBinding"
              transactionFlow="true" />
    </netTcpBinding>
</bindings>

Choosing the transaction protocol

The transaction protocol for the binding can be specified in the configuration file.

Two types of transactions protocols are supported in WCF - WS-Atomic Transaction protocol and OleTransaction protocol. WS-Atomic Transaction protocol is used for interoperability with third-party transactions in heterogeneous environments (Windows and non-Windows environment). OleTransaction protocol is used for flowing transactions in the homogenous environment (Windows environment) and is the default.

OleTransaction protocol may be sufficient when we migrate COM+ applications to WCF. Depending on the future requirements of the WCF application, WS- Atomic Transaction protocol can also be used.The transaction protocol can be stated in configuration or can be set programmatically.

The portion of the configuration file shown below demonstrates how the transaction protocol property can be specified explicitly for the NetTcpBinding of a WCF service:

<bindings>
    <netTcpBinding>
        <binding name="TransactionTcpBinding"
              transactionFlow="true"
              transactionProtocol="OleTransactions">
        </binding>
    </netTcpBinding>
</bindings>

The code snippet below shows how to do the same thing programmatically:

NetTcpBinding transactionTcpBinding = new NetTcpBinding();
transactionTcpBinding.TransactionFlow = true;
transactionTcpBinding.TransactionProtocol = TransactionProtocol.OleTransactions;

Programming transactions in WCF

The TransactionFlowAttribute is specified for the operations of a service contract and states the willingness of the operation to accept incoming transactions. This attribute accepts values of the TransactionFlowOption enumeration. The values of the enumeration are: Allowed, Not Allowed and Mandatory

The code snippet below illustrates the usage of this attribute:

using System;
using System.Text;
using System.ServiceModel;

namespace ComplusToWcf.Market
{
    [ServiceContract(SessionMode = SessionMode.Required)]
    public interface IBroker
    {
    
        [OperationContract]
        [TransactionFlow(TransactionFlowOption.Allowed)]
        long SubmitOrder(string customer, string product, 
            long quantity, string orderStatus);
    }
}

The transaction characteristics of WCF applications can be customized further by using the ServiceBehaviorAttribute and OperationBehaviorAttribute.

The ServiceBehaviorAttribute contains the following transaction specific properties:

  1. TransactionAutoCompleteOnSessionClose: This property is False by default. All pending transactions are completed when the session closes normally. If the session terminates abnormally, then the transactions are aborted. Setting the value of this property to "True" mandates a session and PerSession instancing.
  2. ReleaseServiceInstanceOnTransactionComplete:  This property is true by default. The service is released or deactivated the moment the transaction completes, discarding any transaction state. A new call to the service creates a fresh instance but this process is completely transparent to the client. This property is equivalent to the JITA service of COM+. This property requires the ConcurrencyMode of the service to be Single (default).
  3. TransactionIsolationLevel: This property takes one of the IsolationLevel enumeration values which can be - Chaos, ReadCommitted, ReadUncommitted, RepeatableRead, Serializable, Snapshot and Unspecified. The default value is serialized.
  4. TransactionTimeout: This is the time within which a transaction must complete the 1st phase of the 2-phase commit protocol. If this does not happen then the transaction is aborted. The transaction timeout can also be specified in the configuration file and the lesser of the 2 values (specified at the attribute and specified in configuration) is applied for the timeout. The transaction timeout is governed by the value set by the system administrator and this value is specified as maxTimeout setting in the machine's configuration file. If the transaction timeout value specified as part of the ServiceBehaviorAttribute or in the configuration file of the service exceeds the maxTimeout setting then the timeout is adjusted to the maxTimeout property in machine.config file. The default maxTimeout is 10 minutes.

The OperationBehaviorAttribute contains the following transaction specific properties:

  1. TransactionScopeRequired: This property can either be true or false and specifies if the method executes within a transaction scope. If this property is not set for a method, then this implies that the method does not require a transaction scope. If the value of this property is false then any transaction present in the message header is not activated. If a transaction scope is required then the method executes within an existing transaction scope, if one exists. If not WCF creates a new transaction before the method is executed.
  2. TransactionAutoComplete: This property is true by default and instructs WCF to complete the transaction once the method has finished executing. If this property is false and if the service does not run within a session then an invalid operation exception is thrown at service startup. This is because TransactionAutoComplete is false and in the absence of a session there cannot be another method that can complete the transaction. If this property value is false then the transaction is completed if another later method calls SetTransactionComplete or if a method with TransactionAutoComplete = true is called. Transactions can also be completed by setting the TransactionAutoCompleteOnSessionClose property to true.

Having seen the support to transaction in both COM+ and WCF, let us focus on migrating COM+ transactions to WCF transactions.

For improved understanding, COM+ Transaction management can be split into Transaction Support and Transaction Behavior. By Transaction behavior we mean the transaction object life cycle and transaction completion.

WCF provides can be tweaked to provide a similar Transaction support as COM+. The section below lists the transaction support in COM+ and describes how the same can be achieved in WCF:

RequiresNew: This implies that the object is always created in a new transaction.

To do this, the TransactionFlowAttribute of the operation in the service contract is set to Not Allowed. The TransactionFlow binding property value is set to false. The TransactionScope property of the OperationBehavior attribute is set to true.

The code snippet below shows how the TransactionFlow can be set to Not Allowed and how to indicate that the operation runs under a transaction:

  using System;
  using System.Text;
  using System.ServiceModel;
  
  namespace ComplusToWcf.Market
  {
      public interface IBroker
      {
          [OperationContract]
          [TransactionFlow(TransactionFlowOption.NotAllowed)]
          long SubmitOrder(string customer, string product, long
              quantity, string orderStatus);
      }
      
      //Service class which implements the service interface
      public class BrokerService : IBroker
      {
          //TransactionScopeRequired property is set to true
          
          [OperationBehavior(TransactionScopeRequired = true)]
          public long SubmitOrder(string customer, string product, long
              quantity, string orderStatus)
          {
                  return 0;
          }
      }
  }

Required: Set TransactionFlowAttribute to Allowed. Set TransactionFlow binding property of the binding to true. Set TransactionScope property of OperationBehavior to true.

Supported: There is no direct equivalent in WCF. The settings for Required can be used. The method will also run within a transaction even if there is no incoming transaction, which is not the case with Supported transaction scope in COM+.

Not Supported: Set TransactionFlowAttribute to Not Allowed, TransactionFlow binding property to false and TransactionScope is false.

Disabled: Same settings as in Not Supported.

For the sake of understanding, we'll look at transaction management from the point of life time of the transaction objects and the completion of the transaction.

In COM+, transaction objects are released when a transaction ends but COM+ remembers the transaction layout till the client releases the transaction root object. Since objects have to be released at the end of the transaction, for all components that have Required, Requires New and Supported transaction support, COM+ automatically enables Just-In-Time-Activation. This means the instance is released immediately after method completion and objects have to ensure that they vote on the transaction before the method completes. For migration details, refer to the Just-In-Time-Activation section of this document.

The object can vote on the transaction by calling SetMyTransactionVote of the IContextState interface or by calling SetComplete of the IObjectContext interface. If the component has been configured to be auto-deactivated on return from the method, then COM+ uses the HRESULT returned by the method to decide the outcome of the transaction. If HRESULT is S_OK then the object has voted to commit and if the HRESULT indicates failure then the object has voted to abort the transaction. The outcome of the transaction is decided by examining the consistency bit of the context object. If the consistency bit is set to true then the object has voted to commit. By default, the consistency bit is set to true which means the transaction is automatically committed unless there is an exception or if the object explicitly votes to abort the transaction.

COM+ transaction management can be migrated to WCF easily. The code snippet below illustrates the process.

  using System;
  using System.Text;
  using System.ServiceModel;
  
  namespace ComplusToWcf.Market
  {
      public interface IBroker
      {
          [OperationContract]
          [TransactionFlow(TransactionFlowOption.Allowed)]
          long SubmitOrder(string customer, string product, long 
              quantity, string orderStatus);
      }
      
      //Service class which implements the service interface
      
      //ReleaseServiceInstanceOnTransactionComplete has been set to true
      //to provide the JITA behavior of COM+ transaction components
      
      //Note:ReleaseServiceInstanceOnTransactionComplete is true by default
      
      [ServiceBehavior(ReleaseServiceInstanceOnTransactionComplete = true)]
      public class BrokerService : IBroker
      {
          //TransactionScopeRequired property is set to true
          
          //TransactionAutoComplete has been set to true to provide auto completion
          //of the transaction when the method returns.
          
          //Note: TransactionAutoComplete is true by default
          
          [OperationBehavior(
              TransactionScopeRequired = true,
              TransactionAutoComplete = true)]
          public long SubmitOrder(string customer, string product, long
                quantity, string orderStatus)
          {
              return 0;
          }
      }
  }

In this section, we'll look at the reliability aspects of COM+ and WCF.

Queued components in COM+ ensure the reliability of applications. Reliability is guaranteed because the messages are delivered to the destination even if the source or the destination is unavailable at the time of sending the messages. Queued applications are reliable and asynchronous primarily because the client and the server are independent of each other; the communication between the client and the server does not need a constant connection.

The queued service of COM+ is built on top of MSMQ. Creating queued components in COM+ requires no extra coding effort. Queued components differ from non-queued components by way of their configuration and interface design.

The application hosting the components as well the interface that requires queuing support must be configured to enable queuing in the Component Services Explorer. The figure below shows how queuing support is turned on for an application:

Application uses the Queued Service

Figure 16. Application uses the Queued Service

COM+ automatically creates a public transaction queue on the server once the server application is configured to be queued.

All the methods of the interface must be one way in order for the interface to use the queued service. The methods should also not contain reference parameters, out parameters and they should not return a value.

See Figure 17 for an illustration showing enabling queuing for an interface using the Component Services Explorer:

Enabling queuing for an interface

Figure 17. Enabling queuing for an interface

The recorder and player play are the architecture elements of a queued component. The recording, the transfer of messages to the server queue, and replay of message to the COM+ queued component run under 3 transactions and the associated queues are transactional queues ensuring one-time delivery and durability of messages. Queued components typically have the transaction attribute set to Required or Supported. This ensures that messages are delivered to the server only if the client transaction is committed. To handle poison calls, COM+ uses the retry queues and dead letter queue.

The client to a queued component must use the recorder to send messages to the server application. This requires coding on the client side. The code snippet below shows a Visual Basic 6.0 client creating a queued server object, MyServer.MyQueuedComponent:

  Dim queuedObject As Object
  Set queuedObject = GetObject("Queue:/New:MyServer.MyQueuedComponent")

Having seen the reliability service of COM+, we'll examine the reliability provided by WCF.

WCF provides reliability in 2 ways:

  • Low latency, connected and synchronous: WCF uses WS-Reliable Messaging protocol to provide reliable sessions. Reliable sessions guarantee that messages are delivered between 2 endpoints once in the same order in which they were sent.
  • Disconnected and asynchronous: The communication between 2 endpoints happen using queues. Queues guarantee reliable transfer of messages as well as separation of the service and the client.

We'll look at how both these reliability modes can be achieved in WCF , how to migrate a queued component in COM+ to WCF and then do a quick compare of reliability in COM+ and WCF in the section below.

Reliable sessions are independent of the transport used and provide reliability at the message level rather than at the packet level as provided by TCP. A reliable session between 2 endpoints can be accomplished by using a system binding that supports reliable sessions or using a custom binding that supports reliable sessions. All system bindings that are Http based and TCP based support reliable sessions. The WSDualHttpBinding ensures reliable sessions by default.

The configuration file section shows how to enable reliable sessions for the system binding WSHttpBinding:

<bindings>
    <wsHttpBinding>
        <binding name="WSHttpReliableSessionBinding">
            <reliableSession enabled="true"/>
        </binding>
    </wsHttpBinding>
</bindings>

It is important to secure the session with a security context. Enabling message security for the binding to ensure that the session is secured is important. When using TCP as the transport, TCP ties the TCP session with the reliable session. When Http is used, the SSL session is not bound to the reliable session. This could impose security threats.

Reliable sessions are important for the following messaging scenarios:

  • SOAP intermediaries such as SOAP routers
  • Proxy intermediaries
  • Intermittent connectivity
  • Communication requiring sessions over Http

When reliability is required, but in a disconnected, asynchronous mode, using message queues is the best bet. Using queues for communication provides isolation of the service, the client and the transport. Queuing support in WCF happens using the NetMsmqBinding and MsmqIntegrationBinding.

We'll briefly look at NetMsmqBinding and MsmqIntegrationBinding.

NetMsmqBinding is used if communication is between two WCF endpoints. The NetMsmsqBinding exposes the commonly used features of Msmq and provides a simple mechanism of messaging between WCF clients and services using Msmq. The properties of the NetMsmqBinding can be manipulated to customize the queuing behavior:

  • ExactlyOnce and Durable properties of this binding fine tune the message delivery. Turning on ExactlyOnce ensures that the message is delivered just once.
  • For messages that cannot be delivered, a Dead-letter queue can be configured to store these messages. ExactlyOnce is true by default.
  • Turning on Durable property ensures that the messages are made durable on the disk. This ensures that messages survive and are delivered to the target even if MSMQ service is stopped intermittently.
  • Using NetMsmqBinding, the dead-letter queue can be created to store failed to deliver messages. The DeadLetterQueue property is used for this. The dead-letter queue can be a system created one or can be a custom one.
  • NetMsmqBinding also allows fine tuning the management of poison messages. NetMsmqBinding supports both Transport and Message based security.

When integrating with existing Msmq applications written in C, C++, Com or System.Messaging APIs, MsmqIntegrationBinding is useful. The properties of NetMsmqBinding are also supported by this binding. All parameters of the operations in the service contract should be of type MsmqMessage when using MsmqIntegrationBinding.

We'll now understand how reliability of COM+ can be migrated to WCF.

NetMsmqBinding in WCF provides the queued component service in COM+. Unlike COM+ where the message queue is automatically created, in WCF you would have to create a messaging queue for the service. The endpoint using the NetMsmqBinding should be given the Uri for the queue created for this purpose.

The contents of the configuration file below show a method of using NetMsmqBinding for the private queue MyTransactedQueue:

<services>
    <service name="ComplusToWCF.Samples.MyQueuedService">
        <endpoint
              address="net.msmq://localhost/private/MyTransactedQueue"
              binding="NetMsmqBinding"
              contract="ComplusToWCF.Samples.
        MyQueuedService.QueuedOperation" />
    </service>
</services>

<bindings>
    <wsHttpBinding>
        <binding name="WSHttpReliableSessionBinding">
            <reliableSession enabled="true"/>
        </binding>
    </wsHttpBinding>
    <netMsmqBinding>
        <binding name="NetMsmqBinding" durable="true">
            <security mode="Message"/>
        </binding>
    </netMsmqBinding>
</bindings>

The section below gives a quick comparision of reliability in COM+ and WCF.

  • COM+ provides reliability in the disconnected, asynchronous mode by way of queued components and provides packet based reliabilitydue to the inherent nature of TCP. WCF provides connection based reliability, synchronous reliable sessions and disconnected, asynchronous reliabilityusing Msmq.
  • Queued components in COM+ are only available to COM+ server applications. The client should also be a COM+ server application. This results in interoperability. Queueing in WCF on the other hand is interoperable with pure Msmq applications in C, C++ or Com.
  • Queued components in COM+ are not easily customizable. For example, there is no option of doing away with the dead-letter queue. In WCF, a host of Msmq features can be customized.

Now that we have explored the security, transaction and reliability aspects of COM+, we'll take a quick look at some of the other important aspects such Soap Service of COM+, exception handling, hosting modes and client proxy generation of both COM+ and WCF.

COM+ applications can be exposed as Xml Web Services using the Soap service. Exposing COM+ applications as Web Service can be achieved by configuring Soap activation for the application. All methods of the default interface are exposed. In .Net 1.0, there was no security enforced for the generated Xml Web Service by default. In .Net 1.1, callers are authenticated and the message is encrypted by default.

This can be configured in the Component Services Explorer using the Activation tab in the application's properties page (see Figure 18).

A COM+ application configured to exchange SOAP messages

Figure 18. A COM+ application configured to exchange SOAP messages

The generated files are placed in the \windows\system32\com\SoapVRoots\vroot directory. Vroot is the virtual directory specified in the Soap properties during configuration (market in the example here).

Since there is no control of the code behind files for the exposed web services, they cannot be converted to WCF web services. It makes sense to migrate COM+ applications into WCF services rather than convert them to Web Services in this manner.

As we've seen in the Integration of COM+ applications as is with WCF section, WCF provides the Component Service Model Tool or ComSvcConfig.exe to expose COM+ applications as WCF Web Services.

Exceptions in COM+ are unmanaged whereas in WCF all exceptions are managed exceptions. In COM+ as in Com, HRESULTS returned from methods are used to report errors. A few typical errors in COM+ applications are (Note: the list is not exhaustive):

        COMQC_E_APPLICATION_NOT_QUEUED
        COMADMIN_E_APPLICATIONEXISTS
        COMADMIN_E_AUTHENTICATIONLEVEL
        COMADMIN_E_CAN_NOT_EXPORT_APP_PROXY
        COMADMIN_E_CAN_NOT_START_APP
        COMADMIN_E_USERPASSWDNOTVALID
        COMADMIN_E_ROLE_DOES_NOT_EXIST
        COMADMIN_E_ROLEEXISTS
        E_ACCESSDENIED
        E_NOINTERFACE
        EVENT_E_ALL_SUBSCRIBERS_FAILED
        EVENT_S_NOSUBSCRIBERS

In WCF, some of the typical exceptions that will be encountered are:

        TimeoutException
        CommunicationException
        InvalidOperationException
        ArgumentNullException
        MessageSecurityException
        SecurityNegotiationException
        EndPointNotFoundException

.Net exceptions (Fault exceptions) for the expected COM+ exceptions may need to be created while migrating COM+ applications to WCF.

In this section we'll briefly understand the hosting options in COM+ and WCF.

Components can be configured as COM+ Server Applications or COM+ Library Applications. COM+ allows only in-proc components to be imported into a COM+ application. The component becomes a configured component once it has been imported into COM+.

COM+ provides 2 application activation types for this:

  • Server application
  • Library application

This is configured in the Activation tab in the Application's property using the Component Services Explorer and the screen shot for this is shown below:

Available activation modes

Figure 19. Available activation modes

Choosing the activation type is a design decision and Server application is the recommended activation type. A library application is normally chosen in exceptional cases when the application has to run in the client's process for performance reasons. Library applications have limitation in using certain COM+ services and remote access is not possible. COM+ provides a surrogate process called dllhost.exe to host server applications.

WCF services can be hosted in any managed process such as IIS, console applications, Windows Services and newly introduced Windows Process Activation (WAS) service.

This section provides details on the support provided by COM+ and WCF for generating clients.

Both COM+ and WCF provide mechanisms to generate client proxies. In COM+ client proxies can be generated as Server or Library applications.

We'll briefly explore the client proxy generation of COM+. Installing a COM+ application in a client machine can be done by selecting Export from the context menu which is displayed when a right click is performed on the application item in the Component Services Explorer. Exporting creates a .msi file that can be installed using the Windows installer on another machine. The application can be exported as a Server application or an Application Proxy.

The Server application export Com objects, their settings and the associated proxy/stub dlls to the .msi file. This is like making a copy of the COM+ application so that it can function independently on another machine. This option is available for both Server and Library applications.

The Application Proxy option exports just the type information of the components, along with the proxy/stub dlls if required to the .msi file. This option generates a proxy application and is like deploying a client on another machine in order to remotely access the server application located on a different machine. This option is not available for Library applications. The location of the server application can be configured in the Activation tab of the properties page for the proxy application.

Configuration details for exporting a COM+ application are shown in the screen shot provided below:

Export options

Figure 20. Export options

In WCF, the Service Metadata Utility tool (SvcUtil.exe) is used to generate WCF client proxies that can be used in client applications to communicate with WCF services. SvcUtil.exe is also used to generate the WSDL proxy for calling WCF services from non-WCF clients.

 

Partial Integration and Migration

This third approach can be taken to expedite the overall migration process. Complex COM+ components can remain unchanged and they can be given the Web Services face by integrating them with WCF. An example would be a COM+ pooled component. Since this requires custom coding to product the object pooling behavior, instead of migrating immediately, this component can be exposed as a Web Service (using the tool COMSvcConfig.exe tool) as a stop gap solution. (The web services that are exposed can be consumed in WCF applications).

Components that are simple and can be reproduced in WCF using straight, out-of-the box features can be migrated as WCF services.

Migrating Enterprise Services components to WCF

Prior to WCF, .Net components could use the COM+ services through Enterprise Services that provided managed wrappers for COM+ services. With WCF, .Net applications using Enterprise Services need to be migrated to WCF services which will remove any COM+ dependency.

Unlike the migration of pure COM+ applications to WCF, migrating Enterprise Services Components to WCF is simpler because they use the .Net Framework and use attribute based programming model extensively.

Conclusion

We believe that migration of COM+ applications into WCF services is an attractive option because, as we've seen, WCF is very powerful, simple and flexible framework in the service oriented world. Component based development has been very popular in the past but to keep pace with service oriented development adopting WCF will be the right move. Advantages of migration of COM+ services to WCF, as we have seen, are many. Needless to say, migration to a new technology is invariably both tedious as well as confusing until we understand the fundamentals of both the technologies thoroughly. Since evolution of any new technology, in order for it to explore new heights, as in the case of WCF, a one to one mapping with existing technologies is not possible, it is indeed quite a challenge that has to be overcome in the migration process. This white paper takes a variety of approaches that can be used when we try to integrate the existing COM+ services, as they are in WCF or migration of COM+ applications to WCF out and out.

Authors:

Ganesan Krishnamurthy is a Senior Technical Architect with Microsoft Technology Center, Infosys. He works on understanding and building expertise in .Net 3.0 technologies.

Sripriya Thothadri is an Architect with Microsoft Technology Center, Infosys. She works on the .Net Framework 3.0.

Reviewers:

Florin Lazar is a Program Manager in the Transactions Platform team at Microsoft working on transactions and distributed systems. Florin can be reached via his blog at https://blogs.msdn.com/florinlazar/ or the Transactions MSDN Forum at https://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=388&SiteID=1

Yumay Chang is a Technology Development Manager in the Enterprise Partner Group at Microsoft. She leads the partner strategy on SOA and Business Process Management and supports partner in their adoption of Microsoft technologies.