Running a COM+ Application As a WCF Service

Let's take a look at a scenario involving QuickReturns Ltd.'s OldHorse position-tracking system (or a custody system), as shown in Figure 10-1. OldHorse was built in the late 1990s using Visual Basic 6. Since other groups within QuickReturns Ltd. leverage OldHorse, the OldHorse development team provided COM interfaces allowing client applications to interoperate with OldHorse using COM+.

When an Asset Manager makes a trade, it's necessary that the trade information is posted to the custody system. Additionally, as you'll see later, it's necessary that the custody system checks with the Asset Manager's system for pricing and pending trade information.

QuickReturns Ltd.'s OldHorse system

Visual Basic 6 COM+ Component Sample Setup

The example we'll use is a simple Visual Basic 6 COM (ActiveX DLL) component that exposes two interfaces. The complete solution is contained in the chapter sample code's Visual Basic 6 Project folder. The following code snippets are just the method signatures representing the Visual Basic 6 COM interface. This is an illustration of a Visual Basic 6 component and should not be viewed as a Visual Basic 6 best practice.

When looking at Visual Basic 6 COM components, you'll soon see that some issues relate to how the WCF interfaces leverage type library information in regard to COM+ application components. Visual Basic 6 COM packs both the component logic and the type library information inside the COM DLL; doing so adds some attributes that prevent some interfaces from being initially wrapped in WCF COM+ integration.

Prior to working through this example, set up a virtual directory in IIS called VB6ComSample that is set for ASP.NET 2.0 and has anonymous access enabled.

The PositionManagement interface shown in Listing 10-1 provides a set of simple methods that allow the retrieval of the position for a given ticker, in addition to providing a method for updating the persisted quantity associated with a ticker.[] One element that is not shown is a constructor. COM+ objects don't offer a constructor. They can provide information in other ways, such as with an initialization method. Visual Basic 6 and COM offer several ways of providing static configuration information such as COM+ initialization strings on the configured component; however, that requires implementing IObjectConstructString in Visual Basic 6 and using the ConstructionEnable attribute in .NET. For the example code and to keep it simple, we're just showing method interfaces. The ability to provide a connection string on object construction is something that could be provided through COM+ initialization.

[] Note these are simplified interfaces for example purposes only and do not represent a proper interface definition for a fully functional custody system.

Example. PositionManagement.cls
'Simple interface that allows a nominal change in the quantity of a position
'ticker: Ticker symbol of security
'quantity: Amount (+/-) to shift existing position
'Throws an error if quantity is not sufficient to support the change (overdrawn)
Public Function UpdatePosition(ByVal Ticker As String, _
							   ByVal Quantity As Long) As Long
							...
							Public Function GetQuantity(ByVal Ticker As String) As Long
							...

The second component is the Position component. This class represents mostly a data class with read/write properties. In addition, it has two methods; one provides a retrieval of a specific position for a ticker, and the other returns a concrete Position object for a specific ticker. Listing 10-2 shows the abbreviated class, and the full class is part of the chapter code in OldHorsePositionTrackingVB6PositionManagement.

Example. Visual Basic 6 Position Class: Position.cls
Public Property Let Quantity(ByVal vData As Long)
							...
							Public Property Get Quantity() As Long
							...
							Public Property Let Ticker(ByVal vData As String)
							...
							Public Property Get Ticker() As String
							...
							Public Function GetQuantity(ByVal Ticker As String) As Long
							...
							Public Function GetPosition(ByVal Ticker As String) As Position
...

One additional aspect of the PositonManagement class is that it's configured in Visual Basic 6 to be an MTS component with a Required transaction setting. This setting is reflected in the generated WCF service inside the configuration file and is handled automatically by the COM+ Integration Wizard, which makes a call to the ComSvcConfig.exe utility. This allows flow from a WCF client to your COM+ component, ultimately being managed by the Microsoft Distributed Transaction Coordinator (MSDTC).

Once the project is built to an ActiveX DLL, it is ready to be installed and configured as a COM+ application. Briefly, for a Visual Basic 6 COM component, you follow these steps to create the OldHorse COM+ application:[]

[] We won't go into too much depth about how to create Visual Basic 6 COM+ applications. Note that these steps for COM+ applications are programmable through the COM Administration type library. However, .NET offers the RegSvcs.exe utility that provides a simple command-line interface for this.

  1. From Administrative Tools, launch Component Services.[] Then, expand the Component Services node until you are at the computer you want to configure for your COM+ application. In this example, it's the local machine, or My Computer. Select the COM+ Applications object in the console, right-click, and choose New Application, as shown in Figure 10-2.

    [] You can also get to this Microsoft Management Console (MMC) via the dcomcnfg.exe command.

    Creating a new COM+ application
  2. At this point you're presented with the COM+ Application Install Wizard. Click through the first page of the wizard. On the second page, click the Create an Empty Application button, as shown in Figure 10-3.

    Creating an empty COM+ application
  3. On the next page of the wizard, enter the name of your application, and ensure you select Library Application as the activation type (see Figure 10-4).

    OldHorse library activation
  4. Click through the last page of the wizard. At this point, you should now have a COM+ application defined in Component Services. However, this is an empty package and has no associated components.

  5. The next step is to add your compiled ActiveX DLL into the package. Do that by first selecting the Components tree from within the OldHorse COM+ application. Right-click the Components folder under the OldHorse application, and then choose New Component, as shown in Figure 10-5.

    Adding a new component to the OldHorse application
  6. This opens the COM+ Component Installation Wizard. Click Next in the wizard, and then choose Install New Component(s). Then, navigate to where your Visual Basic 6 COM component's DLL resides (if you have extracted the samples, it is located in the directory OldHorsePositionTrackingVB6PositionManagementin). Choose it, and then click Next until the wizard is dismissed.

At this point you should have a COM+ application with the components shown in Figure 10-6.

First, you'll see two components each with a single interface listed—the name manufactured by the Visual Basic 6 framework. Second, in the right pane, notice the Required transaction attribute. (You can see this view by clicking the detail view.) This attribute forces the activation of this component within a COM+ transaction—either a new transaction or an inherited transactional context from the caller.

Configured OldHorse COM+ application

COM+ Application WCF Service Wrapper

Once a COM+ application is configured, you're ready to leverage WCF's utilities for creating the necessary resources for calling a COM+ component from a WCF client. The primary utility for this is the ComSvcConfig.exe utility. This is a command-line utility that is installed with the .NET 3.0 runtime. Additionally, the SvcConfigEditor.exe utility provides a graphical interface with some additional features that help hide the complexities of the command-line ComSvcConfig.exe utility. One suggestion is to get used to the SvcConfigEditor.exe utility; it facilitates the composition of proper configuration files for WCF with configuration-time validation of many elements.

Using SvcConfigEditor.exe Utility

Before you proceed, it's important to understand some caveats related to COM+ interoperability with WCF. There are restrictions as to what COM+ interfaces can be exposed as a web service through the COM+ Integration layer. Those restrictions are listed in the SDK, but some of them are as follows:


Interfaces that pass object references as parameters

This violates a core tenet of SOA in that passing a reference across a service boundary is expensive.


Interfaces that pass types that are not compatible with the .NET Framework COM interop conversions

This is a general incompatibility issue for types that won't serialize between the interoperability layers.


Interfaces for applications that have application pooling enabled when hosted by COM+

This causes multiple listeners on the same URI moniker issues because there will be more than one application pool attempting to reserve the service endpoint address.


Interfaces from managed components that have not been added to the global assembly cache (GAC)

This is a general limitation of how COM+ hosts configured managed components. There are other means of using COM+ from managed applications (services without components[]), but they are not supported with WCF COM+ integration.

[] Services without components were introduced with COM+ 1.5. See http://msdn2.microsoft.com/en-us/library/ms172373.aspx.

The first item mentioned here is important because given that one of the core tenets of SOA is that boundaries are explicit, it would be expensive to share an interface pointer across the service boundary. Also, given that the default WCF service behavior InstanceContext mode is PerCall, this is something your SOA implementation should consider.

In addition to the previously listed limitations, you'll soon see some limitations with Visual Basic 6 components and, specifically, how Visual Basic 6 components are implemented.

At this point, you're ready to create a WCF interoperability layer around your COM+ components. Start by launching the SvcConfigEditor.exe utility, which is located in the Microsoft SDK's Bin directory. The easiest way is to launch the CMD shell shortcut that gets installed on your Start menu under the Microsoft Windows SDK program group or from within the Visual Studio 2005 Tools menu as WCF Service Configuration Editor.

Start with no configuration file, and have the utility generate the necessary parts; this will allow you to call the OldHorse component from a WCF client.

From the menu bar of SvcConfigEditor.exe, select File Integrate COM+ Application. At this point you should see a listing of all the COM+ applications, including OldHorse, that are present on the local machine, as shown in Figure 10-7.

If you expand the OldHorse.PositionManagement node until you are able to see the list of interfaces (which will list only one), then select the _PositionManagement interface, and click Next. At this point, you should see the page shown in Figure 10-8.

COM+ Integration Wizard

_PositionManagement interface

Keep all selected, and just click Next. This presents the Hosting Mode options. Choose the web hosting in-process mode, which allows per-message activation and hosting within the IIS/WAS worker process. The other hosting options are not available for library-activated (in-process) applications and are enabled when the activation type is Server Activated (out-of-process). Ensure that the Add MEX endpoint option is enabled. This allows clients to leverage WS-Metadata Exchange to query the interface for contract and service information.

The next page of the wizard lists the IIS virtual directories on the local machine. Make sure you choose an IIS virtual directory that is configured for .NET 2.0. For this example, we've preconfigured a virtual directory called /localhost/VB6ComSample (see Figure 10-9) that is configured for ASP.NET 2.0.

Choosing an IIS virtual directory

At that point, click Next, and you're presented with the summary of options shown in Figure 10-10.

COM+ integration summary page

Click Next again, and SvcConfigEditor.exe makes a call to the ComSvcConfig.exe utility with the appropriate command-line options. This generates two files in the virtual directory. If the SvcConfigEditor.exe utility cannot find the ComSvcConfig.exe utility, you'll be presented with a message box asking you to specify where it can be located.[]

[] The ComSvcConfig.exe utility is located at %SystemRoot%Microsoft.NETFrameworkv3.0Windows Communication Foundation.

The two resources that are generated provide the WCF wrapper service resource file and a Web.config file. The WCF service file is generated with the COM ProgID as the filename. For this example, the component OldHorse.PositionManagement generates the file OldHorse.PositionManagement.svc. The contents of that file appear in Listing 10-3.

Example. OldHorse.PositionManagement.svc
<%@ServiceHost .ServiceModel.ComIntegration.
WasHostedComPlusFactory" WasHostedComP12Service=
"{f4612210-b755-4e17-87db-f82d9751d582},
{d3a08ae7-1857-409d-97aa-d86c0b366f5f}" %>

The SVC file contains a single line that points to the service factory that will provide the COM+ integration—WasHostedComPlusFactory. The second parameter, WasHostedComP12Service, provides two initialization parameters for the factory class. The first is the GUID for the COM interface as specified by the type library for the COM component. If you leverage a tool such as OleView (which comes with the Windows SDK), view the type library for OldHorse, and dump the IDL, you'll see that the supplied GUID matches the UUID of the implementation class, which is PositionManagement.

The second parameter represents the COM+ application ID, which is visible by choosing the properties of the COM+ application from the Component Services management console. So, the combination of the application ID and the CLSID (ProgID reference from COM) is a direct pointer that allows the WCF COM+ integration runtime to locate, instantiate, and service the WCF client call.

If you check the properties of the OldHorse.PositionManagement component from within Component Services, you'll see that the CLSID GUID and application GUID both match the generated GUIDs in the OldHorse.PositionManagement.svc file, as shown in Figure 10-11.

OldHorse.PositionManagement properties

Using ComSvcConfig.exe Utility

You can also use the stand-alone ComSvcConfig.exe utility to generate the required resource's COM+ application integration. The primary difference is it doesn't provide the up-front validation that the SvcConfigEditor.exe utility does for validating supported COM interfaces prior to generation. Instead, it provides that information as error messages at runtime.

Using the same COM+ application as an example, the following command generates the required resources for wrapping your COM+ application's PositionManagement interface in a WCF service and hosting inside IIS/WAS (all on a single line).

ComSvcConfig.exe /install /application:OldHorse
/contract:OldHorse.PositionManagement,_PositionManagement
/hosting:was /webdirectory:VB6ComSample /mex

In addition to the /install option listed here, there are two additional primary actions: /list and /uninstall. The /list option enumerates what WCF COM+ integration services currently exist on the local machine. The /uninstall option removes the application .svc file in addition to updating the Web.config (or application configuration) file, removing all references to the identified application and interface.

Client Proxy Generation

At this point, you're ready to create the client proxy for your WCF COM+ integration, using either the SvcUtil.exe utility or the Visual Studio 2005 Add Service Reference add-in, as described in Chapter 5. Before proceeding, ensure that the IIS website that you will be using has anonymous access enabled (accessed through the Directory Security tab in IIS Virtual Directory properties). A completed solution appears in the sample code in the VB6ComClient directory.

In this section, you'll create a simple console application. Start Visual Studio 2005, and create a new Windows console project. Once you have done this, right-click the project (or select the Project menu), and choose Add Service Reference. You can find detailed steps for generating service proxies in Chapter 4. The URI to specify for the Add Service Reference dialog box looks like Figure 10-12.

Adding a service reference to a COM+ WCF wrapper

Once you've generated the service reference, you can now provide the client code. Inside the Main method, the example code looks like Listing 10-4, which shows the completed client project's program.cs class file.

Example. WCF COM+ Integration Client
namespace VB6ComClient
{
    class Program
    {
        static void Main( string[] args )
        {
  OldHorse._PositionManagementClient proxy =
							new VB6ComClient.OldHorse._PositionManagementClient();

 int q = proxy.GetQuantity( "MSFT" );
            Console.WriteLine( "We have " + q + " of MSFT" );
            q = proxy.UpdatePosition( "MSFT", 100 );
            Console.WriteLine( "We now have " + q + " of MSFT" );
            proxy.Close();
            proxy = null;
            Console.WriteLine("Press return to end... " );
            Console.ReadLine();

        }
    }
}

As shown in Listing 10-4, you simply instantiate a proxy type using the default constructor (which reads address, binding, and contract information from the configuration file). Using the _PositionManagementClient object (which was automatically generated from SvcUtil.exe), you then make a call to the methods exposed on the interface.

Consuming the PositionManagement interface from a WCF client is done just like with any other WCF-generated proxy type. In this model, the call is handed from the client over HTTP, which is then received by the IIS/Http.sys listener framework, and finally onto the WCF framework inside the WasHostedComPlusFactory type. The WCF framework does a runtime lookup of the COM+ information, instantiates the Visual Basic 6 COM component, and services the call.

One thing to note is that given the default service InstanceContext behavior is PerCall, the WCF COM+ integration framework will service each call with a new PositionManagement object. Therefore, if you require server-side state, you must modify the service behavior. Review Chapters 3 and 6 for details about service behavior.

Visual Basic 6 COM+ Hiding Interfaces

During the generation of the WCF COM+ integration components for your OldHorse Visual Basic 6 ActiveX DLL, the Position component, while visible in the component selection page as shown in Figure 10-7 earlier in the chapter, offered no visible interfaces for use with the WCF COM+ integration. This is because Visual Basic 6 generates hidden interfaces for the type library information that is bundled with the COM DLL for nonprimitive types. Generally, when using other COM+ languages, specifically C/C++, generating the type library information, a critical aspect of COM+ programming, is done using IDL and compiled into a type library (TLB) that is then used by the implementation programmer to ensure adherence to the contract. Any interfaces that have any hidden types as parameters or return values are not available in the WCF COM+ integration framework.

So, if you have an investment in Visual Basic 6 COM+ components, you may need to consider alternate methods of generation of type library information. Please see the sidebar "Visual Basic 6 COM and Contract-First Programming."

VISUAL BASIC 6 COM AND CONTRACT-FIRST PROGRAMMING

When COM was introduced, it provided a capable component architecture that permitted developers to leverage binary compatibility and reuse components across solutions. With this came the complexity of COM (reference tracking especially) and the language of COM itself. A core component of COM definitions are buried inside the type library for each COM component. C/C++ programmers are used to seeing IDL, which describes the COM interfaces of implementation components.

Visual Basic programmers are generally not accustomed to working with IDL. This is because Visual Basic 6 hides the inner workings of COM. However, it is possible to take a contract-first approach in working with Visual Basic 6 and COM.

Generally, you can find good references on the Internet, and the following link provides examples and shows how to provide a contract-first approach to Visual Basic 6 COM development: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncomg/html/msdn_vbscriptcom.asp.


For the OldHorse Visual Basic 6 COM implementation, the reason the WCF COM+ Integration Wizard ignores the Position interface is because of the method GetPosition that returns a Position object. Visual Basic 6 has hidden the internally generated _Position (note the underscore) interface from consumers of the type library; therefore, it's not possible to create a type of _Position by a caller—generally that's up to the COM component.

Using OleView.exe (which comes with the Windows SDK), if you dump the IDL and inspect the _Position interface, you can see it's marked with a hidden attribute (see Listing 10-5).

Example. OldHorse Visual Basic 6 COM Position IDL
[
  odl,
  uuid(7E22753A-CD1B-4620-A952-E3CDFD456431),
  version(1.0),
  hidden,
  dual,
  nonextensible,
  oleautomation
]
interface _Position : IDispatch {
     [id(0x68030001), propput] HRESULT Quantity([in] long );
    [id(0x68030001), propget] HRESULT Quantity([out, retval] long* );
    [id(0x68030000), propput] HRESULT Ticker([in] BSTR );
    [id(0x68030000), propget] HRESULT Ticker([out, retval] BSTR* );
    [id(0x60030002)] HRESULT GetQuantity(
                    [in] BSTR Ticker,
                    [out, retval] long* );
    [id(0x60030003)] HRESULT GetPosition(
                    [in] BSTR Ticker,
                    [out, retval] _Position** );
};

USING OLEVIEW.EXE

OleView.exe is the COM/OLE viewer utility that helps you view COM interfaces and type libraries registered on a machine.

To view the OldHorse type library information, open OleView.exe, and then navigate into the Type Libraries folder. In that folder you should see the OldHorse (Ver 1.0) type library registration. Initially, in the right pane you'll see the type library information as stored in the registry under the HKCRTypeLib{GUID} where the GUID is the type library's UUID.

At this point, to view the IDL, double-click the entry OldHorse (Ver 1.0) in the left pane; this opens another window showing you the detailed interface information on the left pane along with the IDL in the right pane.


[
  uuid(E17BC5E8-0378-4775-88DE-BADB73C57F03),
  version(1.0)
]
coclass Position {
  [default] interface _Position;
};

Through the IDL you can see why the WCF COM+ Integration Wizard did not display this interface and how you use interface names when you are using the ComSvcConfig.exe utility. You don't actually use the class names as declared inside the Visual Basic 6 class files; you use the generated interface names that Visual Basic 6 provides (prefixed with an underscore, _).

So, again, if you require access to the Position object through the WCF service boundary, you have a couple of work-arounds (there may be more):

  • Remediate Visual Basic 6 to leverage contract-first COM+ development (see the sidebar "Visual Basic 6 COM and Contract-First Programming").

  • Provide a .NET wrapper that interacts directly with Visual Basic 6 COM components and exposes .NET types on the service boundary.

.NET Enterprise Services and COM+ Components

For another example, we've included a simple .NET 2.0 class library that represents the OldHorse2 COM+ application but written in .NET 2.0 using Enterprise Services and serviced components.

This solution file is located as part of the Chapter 10 projects:

OldHorsePositionTrackingDotNetOldHorse2Sln

Prior to stepping through this example, set up a virtual directory inside IIS called DotNetComSample that is configured as ASP.NET 2.0 and has anonymous access enabled. The script CreateVirtualDirs.bat will create the IIS virtual directories and set the .NET runtime to 2.0 for the sites.

The solution also contains a couple of batch files (reg.bat and unreg.bat) that handle the GAC installation and COM+ application configuration. These batch files use the GacUtil.exe utility and the RegSvcs.exe utility that handles GAC and COM+ registration. As listed in the SDK requirements, a .NET component that is also a serviced component (COM+) must be registered in the GAC, which requires it to have a strong name.

The implementation of OldHorse2 is a mirror image of the Visual Basic 6 COM example, except it uses attributes from the Enterprise Services namespaces. Additionally, the Guid attribute is applied to ensure you leverage a consistent CLSID and APPID instead of relying on the framework to regenerate each time.

For the OldHorse2 project, Listing 10-6 shows the PositionManagement class. The code provides the sample simple interface as the Visual Basic 6 version along with Transaction attributes and AutoComplete attributes for transaction management.

Example. OldHorse2 PositionManagement.cs
using System;
using System.EnterpriseServices;
using System.Runtime.InteropServices;

namespace OldHorse2
{

    [Guid( "3B26F4CA-E839-4ab6-86D4-AADB0A8AADA5" )]
    public interface IPositionManagement
    {
        long UpdatePosition( string ticker, long quantity );
        long GetQuantity( string ticker );
    }

    [Guid( "08F01AD6-F3EB-4f41-A73A-270AA942881A" )]
    [Transaction(TransactionOption.Required)]
							 public class PositionManagement : ServicedComponent, IPositionManagement
   {
        public PositionManagement() {}

        #region IPositionManagement Members

        [AutoComplete]
       public long UpdatePosition( string ticker, long quantity )
        {
            IPosition pos = new Position();
            pos = pos.GetPosition( ticker );
            pos.Quantity += quantity;
            return pos.Quantity;
        }

 [AutoComplete]
        public long GetQuantity( string ticker )
        {
            IPosition pos = new Position();
            pos = pos.GetPosition( ticker );
            return pos.Quantity;
        }

        #endregion
    }
}

As you can see in the code in Listing 10-6, we've specifically provided the interface IPositionManagement that is implemented in the class PositionManagement, which also inherits from ServicedComponent. Additionally, the class has the TransactionOption.Required setting with each method having the AutoComplete attribute from Enterprise Services. This will ensure that each instance and call through the PositionManagement type takes place within a COM+ transaction.

In the same project, we've also defined the Position class. Listing 10-7 shows its contents. Notice that we've followed the same approach of providing a specific interface and corresponding implementation class.

Example. OldHorse2 Position.cs
using System;
using System.Runtime.InteropServices;
using System.EnterpriseServices;

namespace OldHorse2
{
    [Guid( "D428B97A-13C8-4591-8AC3-5E8622A8C8BE" )]
    public interface IPosition
    {
        long Quantity
        { get; set; }

        string Ticker
        { get; set; }

        long GetQuantity( string ticker );
        IPosition GetPosition( string ticker );
    }

[Guid( "02FD3A3B-CFCE-4298-8766-438C596002B4" )]
    public class Position : ServicedComponent, IPosition
    {
        ...
        #region IPosition Members
        public long Quantity
        ...
        public string Ticker
        ...
        public long GetQuantity( string ticker )
        ...
        public IPosition GetPosition( string ticker )
        ...
    }
}

Once the project is compiled to a managed assembly, it's necessary to register it in the GAC using the GacUtil.exe utility that comes with the .NET 2.0 Framework. The command to register is as follows:

gacutil /i bindebugOldHorse2.dll

Once it's registered in the GAC, you can then install it in COM+. .NET offers a useful command-line utility that does all the work for you. The following command creates the COM+ application along with registering the .NET assembly's components:

regsvcs bindebugOldHorse2.dll

You can attribute the assembly with Enterprise Services types that control the COM+ registration, shown in Listing 10-8; therefore, you don't have to build the application first and install the components through the wizard. If you want to script this outside of .NET or for non-.NET components, you could leverage the COM+ administrative interfaces for controlling COM+ applications.

Example. OldHorse2 Assembly Attributes for COM+
[assembly: ComVisible( true )]
[assembly: Guid( "c41f4ee8-3475-47b6-b381-5e7774e4287d" )]
[assembly: ApplicationName("OldHorse2")]
[assembly: ApplicationActivation(ActivationOption.Library)]
[assembly: ApplicationAccessControl(false)]

These commands are best executed from the Windows SDK command or Visual Studio 2005 command prompt—located under the Tools folder for the Windows SDK and Visual Studio 2005 by selecting Start All Programs. Additionally, the commands are contained in the batch files previously mentioned. Once registered, you should now see in Component Services the OldHorse2 application, as shown in Figure 10-13.

OldHorse2 .NET COM+ registration

Now, using OleView.exe (from the Windows SDK), refer to the IDL that is generated by the .NET Framework. The full IDL files are located as part of the Chapter 10 code in the OldHorsePositionTracking directory. Listing 10-9 shows the IDL listing.

Example. OldHorse2 .NET IDL
[
  odl,
  uuid(D428B97A-13C8-4591-8AC3-5E8622A8C8BE),
  version(1.0),
  dual,
  oleautomation,
  custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, OldHorse2.IPosition)

]
interface IPosition : IDispatch {
...

[
  odl,
  uuid(3B26F4CA-E839-4AB6-86D4-AADB0A8AADA5),
  version(1.0),
  dual,
  oleautomation,
  custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, OldHorse2.IPositionManagement)

]
interface IPositionManagement : IDispatch {
...

The code has been abbreviated here, but you can see that the declared interfaces IPosition and IPositionManagement both do not have the hidden attribute. Therefore, you should have a different experience when you run the WCF COM+ Integration Wizard, as shown in Figure 10-14.

Start the SvcConfigEditor.exe utility, and access the COM+ integration feature. You now see the OldHorse2 application along with both the IPosition and IPositionManagement interfaces available for integration.

OldHorse2 WCF COM+ Integration Wizard

Select the IPositionManagement interface, and click Next. You now see that both methods, as with the Visual Basic 6 COM component, appear (see Figure 10-15).

OldHorse2.PositionManagement interface methods

Click Next two times, and then click Finish. At this point you'll have two resources generated in the virtual directory root—a Web.config file along with the service host file called OldHorse2.PositionManagement.svc.

Client Proxy Generation

Once again, create a Visual Studio 2005 console application, and choose Add Service Reference to add to the project using the following URI shown in Figure 10-16.

Adding a service reference to the project

In the completed solution, Listing 10-10 shows the code that performs the same call that the Visual Basic 6 COM client performed. The only difference is the type name no longer is prefixed with an underscore (_). This is because when authoring components in .NET, you have control over the interface names, where in Visual Basic 6 it's left up to the Visual Basic 6 framework, hidden from normal levels of control. Other than that, there's no discernable difference from the consumer side, as shown in Listing 10-10.

Example. OldHorse2 Position Management Client
namespace DotNetComClient
{
    class Program
    {
        static void Main( string[] args )
        {

            OldHorse2.PositionManagementClient();
							            OldHorse2.PositionManagementClient proxy =
							            new OldHorse2.PositionManagementClient();
            long q = proxy.GetQuantity("MSFT");
            Console.WriteLine( "We have " + q + " of MSFT" );
            q = proxy.UpdatePosition( "MSFT", 100 );
            Console.WriteLine( "We now have " + q + " of MSFT" );
            proxy.Close();
            proxy = null;
            Console.WriteLine( "Press return to end... " );
            Console.ReadLine();

        }
    }
}

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset