Interoperation Between COM and Web Services

Team-Fly    

 
.NET and COM Interoperability Handbook, The
By Alan Gordon
Table of Contents
Chapter Eleven.  .NET Remoting

Interoperation Between COM+ and Web Services

If you are using any of the Windows XP family of operating systems, which includes XP Professional or Windows .NET Server, you can expose an existing COM+ application as an XML Web service by clicking a single checkbox. This effectively allows you to substitute the SOAP protocol for the DCOM protocol. Microsoft calls this feature COM+ Web services. Although this functionality exposes an XML Web service, it actually uses the .NET remoting infrastructure. The best part about this functionality is that you can use it from either a .NET client or an unmanaged client.

Exposing a COM+ Application as an XML Web Service

I'll walk through a quick example to show you how to expose a COM+ application as an COM+ Web service. I'll use an unmanaged version of the financial component that I built in Chapter 7 of The COM and COM+ Programming Primer . (I included the source code for this component in this book). A COM object diagram for this financial component is shown in Figure 11-4. The component consists of a single COM class with progID of FinancialComponent.TimeValue.1, which implements two interface: ITimeValue(the default) and ITaxCalculator.

Figure 11-4. A COM object diagram for the financial component.

graphics/11fig04.gif

You will need to create a server (out of process) COM+ application and add the financial component to it. Now perform the following steps to expose this COM+ application as an XML Web service:

  1. Right-click the COM+ application in the Component Services Explorer and select Properties from the context menu as shown in Figure 11-5.

    Figure 11-5. The Context menu for a COM+ application.

    graphics/11fig05.jpg

  2. The properties dialog appears. Select the Activation tab of this dialog as shown in Figure 11-6.

    Figure 11-6. The Activation tab of the COM+ application properties dialog.

    graphics/11fig06.jpg

  3. Click the Uses SOAP checkbox and enter "FinancialWebService" (or whatever you like) for the SOAP VRoot.

  4. Click OK.

Note

If you do not see the Uses SOAP checkbox on the Activation tab, you are probably not on a supported platform. Remember that this functionality is currently only available on Windows XP Professional and Windows .NET Server. If the Uses SOAP checkbox appears on the Activation tab, but it's disabled, check that your COM+ application is a server application and not a library application.


When you click OK, the COM+ runtime creates a new virtual directory called FinancialWebService (or whatever name you specified), and it adds the files shown in Table 11-3 to this virtual directory.

Table 11-3. The files in a SOAP VRoot

File Name

Description

web.config

This is a remoting configuration file for the VRoot. This file can be edited to tune the performance and security of the Web service.

default.disco

This allows you to use the Add Reference command in Visual Studio .NET to create a managed code proxy.

Default.aspx

This is an ASP.NET file that displays each component as a hyperlink.

The most important of these files, and the one you are most likely to edit, is the web.config file. The content of this file is shown below.

 <?xml version="1.0" encoding="utf-8"?> <configuration>   <system.runtime.remoting>     <application>       <service>         <wellknown mode="SingleCall"       type="FINANCIALCOMPONENTLib.TimeValueClass,       FINANCIALCOMPONENTLib, Version=1.0.0.0,       Culture=neutral, PublicKeyToken=a59f5f36bc9d34c0"       objectUri="Financialcomponent.TimeValue.1.soap" />         <activated       type="FINANCIALCOMPONENTLib.TimeValueClass,       FINANCIALCOMPONENTLib" />       </service>     </application>   </system.runtime.remoting> </configuration> 

The key information is contained in the service subelement. By now the contents of this file should be familiar to you. Notice that this configuration file specifies that the server supports server activation in single call mode (see the wellknown subelement beneath the service subelement). It also supports client activation (see the activated subelement beneath the service subelement). Given that the Web service supports both server and client activation, the choice of which one to use is determined by the client. You will see how to make this choice when I show you how to create a client for the COM+ Web service.

You can change the server-activated mode to Singleton by altering the web.config file as follows :

 <?xml version="1.0" encoding="utf-8"?> <configuration>   <system.runtime.remoting>     <application>       <service>  <wellknown mode="Singleton"  type="FINANCIALCOMPONENTLib.TimeValueClass,       FINANCIALCOMPONENTLib, Version=1.0.0.0,       Culture=neutral, PublicKeyToken=a59f5f36bc9d34c0"       objectUri="Financialcomponent.TimeValue.1.soap" />         <activated       type="FINANCIALCOMPONENTLib.TimeValueClass,       FINANCIALCOMPONENTLib" />       </service>     </application>   </system.runtime.remoting> </configuration> 

You can control the life cycle of client-activated object using the Lifetime subelement exactly as I showed you before. For instance, add the following bolded text to the web.config file:

 <?xml version="1.0" encoding="utf-8"?> <configuration>   <system.runtime.remoting>     <application>       <service>         <wellknown mode="SingleCall"       type="FINANCIALCOMPONENTLib.TimeValueClass,       FINANCIALCOMPONENTLib, Version=1.0.0.0,       Culture=neutral,PublicKeyToken=a59f5f36bc9d34c0"       objectUri="Financialcomponent.TimeValue.1.soap" />         <activated       type="FINANCIALCOMPONENTLib.TimeValueClass,       FINANCIALCOMPONENTLib" />       </service>  <lifetime leaseTime="45S" renewOnCallTime="45s" />  </application>   </system.runtime.remoting> </configuration> 

Adding that bolded text causes the initial lifetime of a client-activated object to be 45 seconds. The renewOnCallTime attribute specifies that the life cycle will be extended 45 seconds each time a call is made on the object.

The COM+ runtime will create the web.config, default.aspx , and default.disco files in the following physical directory: [System32]\com\ SoapVRoots\[vrootname] where [System32] is the system directory for your machine, and vrootname is the name you entered for the SOAP VRoot (FinancialWebService for this example). On my machine, the complete, physical path for the Web service is C:\WINNT\system32\com\SoapVRoots\ FinancialWebService .

Your COM+ Web service will have the following URL : [ servername ]/[vrootname]/ .

If you followed the directions spelled out earlier, the URL for the FinancialWebService should be //localhost/FinancialWebService/ .

If you navigate to this URL, you will see the page shown in Figure 11-7. This page is generated from the default.aspx and will contain one entry for each COM class that is exposed by the COM+ application or Web service. Each entry is a hyperlink to the WSDL file that corresponds to that class.

Figure 11-7. The default Web page.

graphics/11fig07.jpg

The URI for each WSDL file is //[Servername]/[vrootname]/[ProgID].soap? WSDL .

In this case, there is only one class. This has a ProgID of FinancialComponent.TimeValue.1, so the URI to retrieve the WSDL file for the Web service is //localhost/FinancialWebService/FinancialComponent.TimeValue.1? WSDL .

If you navigate to this URL using Internet Explorer, you will see the WSDL file shown in Figure 11-8.

Figure 11-8. The WSDL file for the Web service.

graphics/11fig08.jpg

Let's look at building a client for the COM+ Web service.

Building a Client for a COM+ Web Service

Now that you have exposed the COM+ application as a Web service, you can access it from managed code or unmanaged code.

CREATING A MANAGED CODE CLIENT

You can use the Web service from managed code the same way that you would use any other Web service. Simply use the Add Web Reference command in Visual Studio .NET the same way that you would use it for any other Web service. Enter the URI for the WSDL file in the Address field of the Add Web Reference as shown in Figure 11-9.

Figure 11-9. Using a COM+ Web service from a managed client.

graphics/11fig09.jpg

The generated proxy for the COM+ Web service will contain the types shown in Table 11-4.

Table 11-4. The types in a proxy for a COM+ Web service

File Name

Description

ITimeValueBinding

Maps to the ITimeValue interface.

ITaxCalculatorBinding

Maps to the ITaxCalculator interface.

TimeValueClassBinding

A class that contains all of the methods implemented by the TimeValue coclass.

TimeValueBinding

A class that maps directly to the TimeValue coclass and hence contains no methods because the TimeValue coclass only implements interfaces, it has no methods defined directly on it.

The following code shows client code that calls the COM+ Web service through the generated proxy:

 1.  private void cmdGetPayment_Click(object sender, 2.      System.EventArgs e) 3.  { 4.      double result; 5.      localhost.TimeValueClassBinding obj= 6.          new localhost.TimeValueClassBinding(); 7.      result=obj.MonthlyPayment(8.          short.Parse(txtNumMonths.Text), 9.          double.Parse(txtRate.Text), 10.         double.Parse(txtLoanAmt.Text)); 11.     lblMonthlyPayment.Text=result.ToString(); 12. } 

Lines 5 and 6 create an instance of the TimeValueClassBinding class. Lines 7 through 10 call the MonthlyPayment method, and line 11 displays the result in a text box. This code will use server activation. You will see how to use client activation shortly.

CREATING AN UNMANAGED CODE CLIENT

Windows XP Professional and Windows .NET Server contain COM monikers that make it easy to call an XML Web service from an unmanaged client application.

Note

If your client platform is something other than Windows XP Professional or .NET Server (Windows 2000), you can use the SOAP Toolkit to call an XML Web Service from unmanaged code. The SOAP toolkit is freely available at //msdn.microsoft.com/; search for SOAP Toolkit.


Even though I'm showing you how to use these Monikers in the context of demonstrating a COM+ Web service, you can actually use these Monikers to call any XML Web service. Using these Monikers, you can call a Web service using Well Known Object (WKO) mode or Client-Activated Object (CAO) mode, assuming that the Web service supports both modes.

What Is a Moniker?

In most cases, you instantiate a COM object using the CoCreateInstance(Ex) functions. If you knew ahead of time that you would need to instantiate many objects, you might instead call CoGetClassFactory to get an IClassFactory interface pointer and then call CreateInstance on this interface pointer to create each instance quicker. In some cases, though, the process for creating a COM object is more complicated than just creating a new instance of an object. The state of an object may be stored persistently in a file or database, and you want to reconstitute the object from the information in that file or database. In this case, the activation procedure is to create the object, open the file or connect to the database, locate the data that contains the state of the object, read the state information, and then pass it to an initialization method that the object supports. If the object is an ActiveX control that resides at an Internet URL, the activation process is that the client machine should download the DLL that contains the ActiveX control to the local machine, install and register it, instantiate the object, and then load the state information for the ActiveX control from properties that appear as subelements of the Object tag on the HTML page that contains the ActiveX control. Rather than requiring developers to remember a complicated sequence of activation steps, it is much easier to encapsulate all of the logic required in these scenarios into a special activation object. Then, when you want to instantiate an object using this activation logic, you simply create an instance of the activation object and then call a method on it to instantiate the object that you want. In the COM world, these special activation objects are called Monikers.

A Moniker is a COM component that implements the IMoniker interface. You can think of a Moniker as an object that allows you to locate and activate other objects. The business logic associated with locating and activating an object is unique to each particular type of Moniker. The most important method in the IMoniker interface is the BindToObject method, which will execute the activation logic of the Moniker and return the requested interface on the new object; this is called binding. The prototype of the BindToObject method is shown here:

 HRESULT BindToObject(IBindCtx *pbc, //Pointer to a bind context object IMoniker *pmkToLeft, // For composite monikers, a            // pointer to the moniker that                 // precedes this one REFIID riidResult, //IID of the requested interface void **ppvResult   // The requested interface pointer); 

There are a number of standard Monikers that are provided for you by COM, such as the file Moniker, which will create an object and initialize its state with the contents of a file, and you can also create your own Monikers. Most Monikers have a Create function. The COM API contains a CreateFileMoniker function for instance. However, the easiest and most flexible way to create a Moniker is using the MkParseDisplayName function. MkParseDisplayName is defined as shown here:

 HRESULT MkParseDisplayName(IBindCtx *pbc, //Pointer to a bind context object       LPCOLESTR strDisplayName, // The display name       ULONG *pEaten, // For composite monikers, a count                           // of the number of characters               // that have been eaten (used) by              // previous Monikers IMoniker **pMoniker);  // The requested Moniker 

The MkParseDisplayName function creates a Moniker using a user -friendly string called a Display Name. The general format of a Display Name is as follows:

 MonikerType:MonikerSpecificInformation 

For example, the display name for a file moniker is constructed as follows:

 File:Path 

To use the MkParseDisplayName function, you must first create a bind context using the CreateBindCtx function. You then pass this bind context to the MkParseDisplayName function to get a moniker and call the BindToObject method on this moniker to bind an object. Therefore, you could have created and bound a file Moniker using the following call to MkParseDisplayName instead of using the CreateFileMoniker function:

 HRESULT hRes;     IBindCtx *pBindCtx;     IMoniker *pMoniker;     IDispatch *pDispatch;     ULONG lEaten;     hRes=CreateBindCtx(0,&pBindCtx);     hRes=MkParseDisplayName(pBindCtx, L"file:c:\alan\filemonikertest.doc",       &lEaten,&pMoniker);     hRes=pMoniker->BindToObject(pBindCtx, NULL,IID_IDispatch,       (void **)&pDispatch); 

Microsoft has even a provided an API function called CoGetObject that encapsulates the preceding logic. CoGetObject is defined as follows:

 HRESULT CoGetObject(LPCWSTR strDisplayName,BIND_OPTS *pBindOpts,REFIID riid,void **ppv); 

CoGetObject creates a BindContext, calls MkParseDisplay, and then calls BindToObject on the Moniker to create a COM object. The following listing shows how you would use CoGet-Object to implement the same logic shown in the previous listing:

 HRESULT hRes; IDispatch *pDispatch; hRes=CoGetObject(L"c:\alan\filemonikertest.doc",NULL,     IID_IDispatch,(void **)&pDispatch); 

Notice how much simpler this code is.

You're now probably wondering how MkParseDisplayName (and hence CoGetObject) works. It's actually quite simple. When MkParseDisplayName receives a Display Name, like file:c:\alan\filemonikertest.doc, it looks beneath the HKEY_CLASSES_ROOT\ key in the registry for a key with the same name as the string to the left of the colon in the Display Name (file in this case). The CLSID for the Moniker associated with the Display Name is stored beneath a registry key with this name. Figure 11-10 shows the Registry key and the CLSID for the file Moniker.

Figure 11-10. Using a COM+ Web service from a managed client.

graphics/11fig10.jpg

MkParseDisplayName instantiates the COM class identified by this CLSID and requests the IMoniker interface. Then it creates a bind context and uses the bind context to pass the information on the right side of the colon to the BindToObject function of the Moniker. This is the additional information that the Moniker needs to do its work. Windows XP Professional and Windows .NET Server include a SOAP Moniker that allows you to bind to a COM+ Web service in much the same way that you would a COM object. Figure 11-11 shows this Moniker in the registry editor.

Figure 11-11. The SOAP Moniker.

graphics/11fig11.jpg

The following code shows how you would use the SOAP Moniker in server-activated mode to access a Web service from an unmanaged Visual Basic client:

 Set obj = GetObject("soap:wsdl=http://[server]/[vroot]/[progID].soap?WSDL") result = obj.Method(parameters...) 

Notice that I use the GetObject API method with the SOAP Moniker (see the sidebar in this chapter about Monikers). The soap: at the beginning of the display name that I pass to GetObject indicates that I am using the SOAP Moniker. [Server] is the name of the server, [vroot] is the virtual root for the Web service on that server, and [progID] is the ProgID for the COM component. The following code shows example code for the financial COM+ Web service:

 Private Sub Command1_Click()     Dim obj As Object     Dim result As Double     Set obj = GetObject("soap:wsdl=http://localhost/financialwebservice/Financialcomponent.TimeValue.1.soap?WSDL")     result = obj.MonthlyPayment(360, 5.75, 360000) End Sub 
CLIENT-ACTIVATED OBJECT (CAO) MODE

In order to use a COM+ Web service in CAO mode, you have to export the SOAP-enabled COM+ application from your server in proxy mode and then import the application into the client from which you want to access the COM+ application as an XML Web service. After you have done this, you can instantiate the application's components in the same way that you would instantiate a local object or a DCOM object, using GetObject and CoCreateInstance for instance. To export a COM+ application from your server, first make sure that you have selected the Uses SOAP checkbox on the Activation tab of the property page for your COM+ application in the Component Services Explorer (see Figure 11-6) and then perform the following steps:

  1. Right-click the COM+ application and select Export from the context menu as shown in Figure 11-12. The welcome page of the Export Wizard appears.

    Figure 11-12. Exporting a COM+ application.

    graphics/11fig12.jpg

  2. Click Next on the welcome page. The main page of the Export Wizard appears as shown in Figure 11-13.

    Figure 11-13. The Export Application Wizard.

    graphics/11fig13.jpg

  3. In the Export Wizard, enter a location where you want the MSI file (that you will run on the client) to be created and under the Export As options, select Application Proxy. Click Next.

  4. Click Finish on the last page of the Export Wizard.

You can now take the MSI file that the Export Wizard generated and run it on a remote client computer. On that computer, you can now use GetObject or CoCreateInstance to use the objects that are exposed through SOAP. For instance, the following code will work on a remote client:

 Private Sub Command1_Click()     Dim obj As Object     Dim result As Double     Set obj = CreateObject("Financialcomponent.TimeValue")     result = obj.MonthlyPayment(360, 5.75, 360000) End Sub 

If you installed the SOAP-enabled proxy on a client, the client will communicate with the Web service using SOAP; if you have not done this, it will use DCOM. This last point is an important one to emphasize . Just because you have configured a COM+ application to use SOAP does not mean you are limited only to using SOAP. You can still access the COM+ application using DCOM if you would like to. You can also use a COM+ Web service in CAO mode using the type name and assembly moniker as shown here (this is another Moniker supported by Windows XP and Windows .NET Server):

 Private Sub Command1_Click()     Dim obj As Object     Dim result As Double     Set obj = GetObject("soap:typename=Financialcomponent.TimeValue,         assembly=Financialcomponent")     result = obj.MonthlyPayment(360, 5.75, 360000) End Sub 

Remember that the main advantage of CAO activation is that you can have a stateful persistent connection to the server much like what you have with DCOM.


Team-Fly    
Top
 


. Net and COM Interoperability Handbook
The .NET and COM Interoperability Handbook (Integrated .Net)
ISBN: 013046130X
EAN: 2147483647
Year: 2002
Pages: 119
Authors: Alan Gordon

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