Web Services Integration

 

Microsoft Corporation
October 2003

Applies to
    Microsoft® ASP.NET
    Microsoft ADO.NET
    Microsoft Internet Information Services
    Microsoft Visual Basic® .NET
    Microsoft Visual Studio® .NET
    Java

Summary: Learn how to integrate Web services that use different technologies, including Java and .NET. (14 printed pages)

Contents

Introduction
Web Services in Java
Web Services in ASP.NET
Integration
Summary

Introduction

Web services are applications, available over the Internet, that provide some kind of service, either programmatic or informative, to other applications. Web services differ from Web applications in that they generally involve application-to-application communication, and are not intended to be accessed via a Web browser. Instead, clients can be written in any language that supports HTTP and SOAP. A client transmits a message or remote method call to a Web service, which processes the message and returns a response to the client. Web services do not usually have any sort of user interface built in, and it is generally up to the client to process input and display output.

Microsoft® Visual Studio® .NET includes complete support for Microsoft ASP.NET Web services in both Microsoft Visual Basic® .NET and C#. You can construct both Web services and clients quickly and easily; in many cases, only two or three lines of code are needed for a basic client. One of the main issues with Web services in the past was that services written on different platforms had trouble interacting with one another; a Java Web service, for example, was difficult to access using a Visual Basic client. However, with a few minor adjustments, ASP.NET Web services can be configured to work correctly with clients in any language, regardless of how they format their HTTP or SOAP messages.

In this white paper, we will first introduce you to Web services in both Java and Microsoft .NET by providing a quick example of a client and server in each. We will then discuss integration issues and how to overcome them in your ASP.NET applications; this final section includes a detailed discussion on the different SOAP message encoding types, which are one of the primary reasons that Web service integration can be difficult.

Web Services in Java

In this example we create a Java class that converts temperatures from Fahrenheit to Celsius and vice versa, and then deploy the class as a Web service. We'll use Apache's Tomcat Web server to host the service, and Apache's Java implementation of SOAP to send requests and responses to and from the server. As you will see, this bare bones approach is more complicated than the .NET equivalent because we are not working in a seamlessly integrated environment.

This example will use the Tomcat servlet engine as the Web service host. Our listener will be a Java servlet. The Web service code will be a simple Java class called directly from the servlet. We will use the Apache Xerces XML parser and the Apache Soap 2.2 implementation on both the client and the server.

Once again, the approach in this topic uses the raw APIs for developing SOAP applications and is somewhat time consuming. Most Java development environments offer much better support for Web services (similar to the Visual Studio .NET environment).

The Web Service Class

Our Web service consists of a single class, Temperature (shown in Listing 1), with a single method named convert(). The convert() method takes two parameters: a character value representing the units of the initial value (which must be either f or c if a valid result is to be returned) and a double representing the value to be converted. The class returns the converted temperature, or an impossible value (-999) if the units were invalid and the conversion could not be made. Ideally, we would throw an exception instead of returning an invalid value, but we'll keep it simple.

Listing 1. Temperature.java

package myservices;

public class Temperature {
   public double convert(int i, double t) {
      char u = (char)i;

      if (u == 'c') {
         double result = ((1.8*t)+32);
      }
      else if (u == 'f') {
         double result = ((t-32)/1.8);
         return result;
      }
      else result = -999;
      return result;
   }
}

After you read the Visual Basic .NET Web service example later in this white paper, you will notice that one major difference between Web services in Java and Web services in .NET is that Java Web services need not contain any indication that they are Web services at all. Whereas .NET Framework-based Web service code must contain <WebService()> tags and be built on an ASP.NET project, Java Web services can be created from any Java class regardless of whether or not it was originally designed to be a Web service.

Create and compile Temperature.java, and place Temperature.class in an accessible directory, such as TomcatInstallDir\webapps\soap\WEB-INF\classes\myservices.

Deploying the Service

Deploying a Web service in Tomcat is actually very simple. You will need to generate a deployment descriptor and then deploy the application. The Tomcat container will automatically create a listener servlet based on your deployment descriptor (very similar to the way in which Java server pages are converted to servlets).

The deployment descriptor

A deployment descriptor is a small XML document that describes a Web service class and its available methods. The deployment descriptor shown in Listing 2 is required in order for Temperature to be deployed as an Apache SOAP Web service. Copy this listing into a new file named TempDescriptor.xml.

Listing 2. TempDescriptor.xml

<isd:service 
   xmlns:isd="http://xml.apache.org/xml-soap/deployment"
   id="urn:myserver:myservice1">
   <isd:provider type="java"
      scope="Application"
      methods="convert">
      <isd:java class="myservices.Temperature"/>
   </isd:provider>
   <!--Remove the following line breaks! -->
   <isd:faultListener>
      org.apache.soap.server.DOMFaultListener
   </isd:faultListener>
</isd:service>

You do not need to put TempDescriptor.xml in any special location, but since you will probably create a variety of Web service classes in a particular project, you may want to create a directory in which to store the deployment descriptors as well.

Note that urn:myserver:myservice1 (bold line) is an arbitrary unique string we created to represent the location of our Web service. This address will be used in client applications to locate the service once it is deployed. This string is identical to the namespace we used back in the .NET example (Listing 6).

Once we deploy our service code, along with the deployment descriptor, the Apache SOAP tools will automatically generate a servlet and associated Web application for deployment. You do not have to write any additional code.

Deploying the Web service application

Before an Apache SOAP Web service can be invoked, it must be deployed, meaning that the server must be informed of the service's existence and location. The easiest way to deploy an Apache SOAP Web service is to call ServiceManagerClient from the command line. ServiceManagerClient allows you to deploy and un-deploy services using the deployment descriptors. Open a command prompt, change to the directory in which you stored TempDescriptor.xml, and execute the command shown in Listing 3.

Listing 3. Command to deploy the Temperature Web service

C:\>java org.apache.soap.server.ServiceManagerClient 
   https://localhost:8080/soap/servlet/rpcrouter deploy TempDescriptor.xml

You can check to see whether the Web service was deployed correctly using the Apache SOAP admin tool. To do this, open a Web browser and point it to https://localhost:8080/soap, click Run, and then select List. This will display a list of currently deployed Web services. You can click the name of a Web service to see its deployment properties.

The SOAP admin tool can also be used to deploy and un-deploy Web services. Clicking the Deploy button will open an HTML form that you can fill out and submit to deploy your service. Though we do not provide instructions for the Web-based deployment tool here, you can find them in your SOAP documentation.

On the back end, the ServiceManagerClient class is creating a full Web application around the Web service descriptor and class. This Web application consists of all of the same components you would find in a WAR file you might generate for servlets or JSPs.

Creating a Client

Now that your Web service is deployed, you (or anyone else with access to your Web server) can create a client that will take advantage of it. The client accesses the Web service using the URI supplied in the deployment descriptor (urn:myserver:myservice1 in this case). We will create a simple Java client called TempClient that takes two parameters on the command line (for units and value), calls the Temperature Web service using these parameters, and outputs the results. TempClient is shown in Listing 4.

Listing 4. TempClient.java

import java.net.*;
import java.util.*;
import org.apache.soap.*;
import org.apache.soap.rpc.*;

public class TempClient {

   public static void main (String[] args) {

      //Create a new instance of the class and set variables
      TempClient client = new TempClient();
      int fromUnits = args[0].charAt(0);
      double value = Double.parseDouble(args[1]);

      //Try the soap call and handle errors and output
      try {
         double result = client.tempConvert(fromUnits,value);
         if (fromUnits == 'c') {
            System.out.println("The temperature in farenheit is: "
               + result + ".");
         }
         else if (fromUnits == 'f') {
            System.out.println("The temperature in Celsius is: "
               + result + ".");
         }
         else {
            System.out.println("Invalid units.");
         }
      } catch (SOAPException e) {}
         catch (MalformedURLException e) {}
   }

   //Method to handle the SOAP call

   public double tempConvert(int u, double t)
   throws SOAPException, MalformedURLException {

      //Create the connection to the Web service
      Call webcall = new Call();
      webcall.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);
      webcall.setTargetObjectURI("urn:myserver:myservice1");
      webcall.setMethodName("convert");

      //Add the parameters to the webcall
      Parameter fUnits = new Parameter("i", Integer.class, 
      new Integer(u), null);
      Parameter deg = new Parameter("t", Double.class, 
      new Double(t),null);
      Vector paramList = new Vector();
      paramList.addElement(fUnits);
      paramList.addElement(deg);
      webcall.setParams(paramList);

      //Make the call and wait for a response
      //If you are hosting Tomcat on a port other than 8080
      //on your local computer, change this line!
      URL url = new URL 
         ("https://localhost:8080/soap/servlet/rpcrouter");
      Response r = webcall.invoke(url,"");

      //Parse the response
      if (!r.generatedFault()) {
         Parameter result = r.getReturnValue();
         Double temp = (Double)result.getValue();
         return temp.doubleValue();
      }
      else {
         Fault f = r.getFault();
         System.out.println("An error occurred.");
         System.err.println("Fault Code: " + f.getFaultCode());
         System.err.println("Fault String: "
            + f.getFaultString());

         return (double)-999;
      }
   }
}

This client code is quite verbose and may, at first glance, seem overly complicated. More detailed instructions on how to use SOAP in Java can be found in Chapter 5. For now, all you need to know is that accessing a Web service using Apache SOAP follows three basic steps:

  1. Construct a Call object (webcall in the example). This object stores methods, parameters, and other information that will be used to create a SOAP request.
  2. Invoke the Call object on the location of the Web service. In our example, we use the default location for Web services hosted by a Tomcat container (http://webhost:8080/soap/servlet/rpcrouter). The port number, however, is a Tomcat setting that you can adjust in the server.xml configuration file.
  3. Process the SOAP response (a Response object).

Compile and execute TempClient.java. You should see results similar to Listing 5.

Listing 5. Output of TempClient.java

C:\WebServices\examples>java
TempClient f 32
The temperature in Celsius is: 0.

Web Services in ASP.NET

Our simple Web service is written in Visual Basic .NET, and uses HTTP and SOAP to carry messages back and forth between client and server. Unlike other Web-service capable programming environments, .NET does much of the work in the back end, meaning that you only have to write a few lines of code in order to create a working Web service.

In a .NET environment, the Web service host is Internet Information Services (IIS v5.0). The Web service listener is an ASP.NET page, and the service code can be developed in any .NET language, including Visual Basic .NET, C# or managed C++ (although C++ is not natively supported by Visual Studio .NET). The XML parser for both the clients is the Microsoft XML parser, which is part of the .NET base-class libraries although it is hidden in the functionality exposed through the Microsoft Web service classes.

To follow along with this topic, you will need to have Visual Studio .NET and the .NET Framework installed. You'll also need to ensure that IIS is up and running. You can check this by opening a browser and pointing it to https://localhost. If you get an error message, you may need to reinstall or reconfigure IIS.

Building the Service

The process of building a Web service in the .NET Framework can be divided into several components, starting with the Web Service Templates built into Visual Studio .NET.

The Web service template

To create a Web service in .NET, open Visual Studio .NET, select New Project, and then choose the ASP.NET Web Service Template. Before you click OK, type a new name in the Location text box. This box creates a new directory structure under IIS for your Web service. In this example, we will call our Web service SongService, so the location textbox should be https://localhost/SongService. Once you set the location value, Visual Studio .NET will automatically propagate the name through the rest of the class files, which makes it very difficult to change the name later.

The Web service class

When you create a new Web service, Visual Studio .NET will start at the Design window. Switch to the code view of your application (using the click here to switch to code view link).

Start by changing your service's namespace (located inside the<WebService>tag near the top of the code) to something more appropriate. For this example, we will use the namespace http://examples.org/music. Remember that the URL you use as a namespace does not need to exist as a Web site; it only needs to be a unique string to avoid conflicts with other applications. In general, however, if you have a publicly available Web service, you will want the namespace to match a globally unique name (like your Web address). The namespace will be used as a tag attached to every element in your Web service request.

The Web service code

Next we need to add the code for our Web service. The generated template code includes a commented example service that you should erase and replace with the code shown in Listing 6.

Listing 6. Visual Basic .NET code for SongService

<WebMethod()>
Public Function getArtist _
      (ByVal song As String) _
      As String
   Dim message As String
   If song = "One More Astronaut" Then
      message = "That song is by I Mother Earth. " + _
         "A great Canadian band!"
   Else If song = "Ordinary Day"
      message = "That song is by Great Big Sea. " + _
         "Gotta love their Newfoundland sound!"
   Else
      message = "I dont know that one. " + _
         "Why not try some Canadian music instead?"
   End If
   Return message
End Function

The Web service we have created takes in a string representing the name of a song, and returns a string that contains either the artist who performed the song or a message indicating that the artist was not recognized.

You may note the<WebMethod()>attribute. This attribute identifies the function as a Web service, which is critically important for the compiler. The .NET compiler will process this call and wrap it with the appropriate SOAP APIs for Web services.

Deploy and Test the Service

Deploying a .NET Framework-based Web service is automatic in Visual Studio .NET. Simply build your application and Visual Studio .NET will place the appropriate files on your Web server where they can be accessed by client applications (in fact, many files are already placed at the time you first create the new service). If you are not familiar with Visual Studio .NET, you can build your project using the Build Solution command from the Build menu.

You can test your service from inside Visual Studio .NET by selecting Start from the Debug menu. Alternatively, you can open a Web browser and navigate to https://localhost/SongService/Service1.asmx. In either case, you will see the default IIS browser interface for Web services. Select getArtist from the list of methods there (it will likely be the only method available). Using this interface, you can enter values for the getArtist method's input parameters and see what output is returned.

The IIS Web service interface also shows you the complete SOAP package for the request. This interface is an extremely useful tool for evaluating your service and solving various platform problems.

When you enter a value for song, and click Invoke, you should see a new browser window that contains an XML document with the response. The XML document is actually an HTTP GET response (the only response type supported by the Web interface) and will look something like Listing 7.

Listing 7. Web interface response to getArtist

<?xml version="1.0" encoding="utf-8" ?>
<string xmlns="http://examples.org/music">That song is by I
Mother Earth. A great Canadian band!</string>

Most client applications will use SOAP messages and not HTTP GET. We can be satisfied, however, that our Web service works and we can retrieve a valid response.

Creating a Client to Access SongService

Web service clients are most certainly not limited to Web browsers. A Web service client can be anything from a simple stand-alone application to part of a large distributed or Web-based system. In this example, we will build a simple Visual Basic .NET desktop application. With the .NET Framework, you won't need any special back-end code in order for your application to access a Web service. You do, however, need to add a Web reference to the Web service in your client application to be able to instantiate Web objects and methods.

The Windows application template

Open Visual Studio .NET and create a new Visual Basic .NET Windows Application. As with the Web service project, you should be sure to name the project before you click OK to open the template. We will call this application SongClient. You may also want to select an appropriate location for the code files. The default file location reverts to the Visual Studio Projects folder under your My Documents folder.

Add the reference

In order for a client to invoke a Web service, you have to establish a connection to the service and evaluate the service's methods. In Visual Studio .NET, these actions are performed by adding a Web reference to the Web service. Once the new application has been created, go to the Project menu and select Add Web Reference. In the Add Web Reference window, type the address of your Web service in the Address field (in this case, the address should be https://localhost/SongService/Service1.asmx). The window will display some information about the service, including links to access its documentation and WSDL contract. Make sure the service being displayed is the correct one and then click the Add Reference button to add the reference and return to the Visual Basic .NET Design window.

Building the form

Now that our application references the SongService Web service, we can take advantage of the services functionality to create a simple login window. We start by adding a text box element (txtSongName), some labels for the text boxes, a button (cmdSubmit) and a label (lblResponse) to our form.

The user types the name of a song into the field and then clicks the Who Performs This? button. The returned message will display in the label at the bottom of the form.

The button code

Double click the Who Performs This? button to access its Click method and add the bold code shown in Listing 8.

Listing 8. Button code for WelcomeService client

Private Sub cmdLogin_Click(ByVal sender as System.Object _
   ByVal e as System.EventArgs) _
      Handles cmdInvoke.Click
   Dim myService As New localhost.Service1()
   lblResponse.Text = myService.getArtist(txtSongName.Text)
End Sub

These two lines of code are all that is necessary to use SongService. Note that the object localhost is actually a reference to the location of the service. If your service where hosted on a remote system, the object name would reflect the name of the remote system. Compile and run SongClient (by pressing F5). Try typing a song name and clicking the button to see the Web service in action.

Integration

You have now seen an example of how to deploy both an Apache SOAP Web service and an ASP.NET Web service. You have also seen how a client can be constructed in each of those languages to interact with a service in the same language. This section focuses on how to construct Web services and clients in Java and in the .NET Framework that are able to interact with one another; that is, it answers the question: How can I invoke a .NET Framework-based Web service with a Java client, or how can I invoke a Java Web service with a .NET Framework-based client?

Key Differences between .NET and Java Web Services

We will start by looking at some of the ways in which the default Web service configurations in each language differ from one another. This section is divided into Problem and Solution subsections, one for each difference.

Encoding and document style

Problem

SOAP messages can have one of two encoding styles:

  • Encoded style follows the encoding rules specified in Section 7 of the SOAP specification; basically, these rules dictate the content of the SOAP <Body> element, and require that a data type be specified for each element included in a SOAP request or response message.
  • Literal style does not follow the rules in any particular specification. The content of the <Body> element must be agreed upon and implemented in both the service and client implementations. Literal-encoded SOAP messages do not necessarily specify a data type for each element, and it is usually up to the receiver to decide how each parameter should be translated into its own data types.

In addition, SOAP messages can follow one of two different document styles:

  • In RPC style SOAP Messages, the <Body> element contains a method name and parameters, and is understood to be a remote procedure call. In this case, the structure of the <Body> element follows rules laid out in Section 5 of the SOAP specification. If a Web service is an RPC service, the client knows exactly how the data in its request messages will be handled by the service.
  • In Document- or Message-style SOAP messages, the <Body> element is treated as an XML document. The structure of this document must be agreed upon by client and service. In this case, the client does not know or care how the service will handle the information it receives; the client simply sends a message structured in the agreed-upon style, and assumes that the service will know what to do with it.

The problem in this case arises because Apache SOAP and .NET Framework-based Web services, by default, use different encoding and document styles. Apache SOAP Web services are typically RPC/Encoded, and .NET Framework-based Web services are typically Document/Literal (incidentally, although RPC/Literal and Document/Encoded Web services are possible, they are very rare).

Solution

Extra work to solve this problem is really only necessary when attempting to access a .NET Framework-based Web service with a Java client. Because .NET Framework-based clients understand (and require) WSDL documents, they are able to automatically adjust themselves to send and receive RPC/Encoded messages upon creation. When attempting to access a Java Web service with a .NET Framework-based client, the only additional work required is the creation of the WSDL document itself. Apache SOAP 2.2 does not support WSDL, so you must either create the contract manually in a text editor or use third-party software to generate WSDL from the Web service class.

When working with a .NET Framework-based Web service, the easiest way to ensure compatibility with Apache SOAP clients is to replace your usual <WebMethod> or [WebMethod] attribute with a special <SoapRpcMethod> or [SoapRpcMethod] attribute. This attribute indicates that the method to follow needs to receive RPC/Encoded request messages.

In C#, a typical [SoapRpcMethod] attribute looks like Listing 9.

Listing 9. A typical SoapRpcMethod attribute

[SoapRpcMethod(Action="https://www.contoso.com/Rpc",

   RequestNamespace="https://www.contoso.com/SUB",
   ResponseNamespace="https://www.contoso.com/SUB"),
   WebMethod()]

Notice how this attribute requires that you specify a namespace for the action itself and for request and response messages. These namespaces are important, and will need to be used in the Apache SOAP client in order for interoperation to be successful.

If you do not have control over a Document/Literal .NET Framework-based Web service but you still need to create an Apache SOAP client that can communicate with it, you will need to adjust the encoding of the Call object in your Java code. An example of this technique can be found in "Real World XML Web Services," Chapter 12: Other SOAP Toolkits (interoperability).

SOAPAction HTTP header

Problem

The SOAPAction HTTP header is a special HTTP header found in SOAP request messages that contains information about the Web service being called. ASP.NET Web services require this header, and it must contain the namespace and (if applicable) the name of the method being called. If you are using a .NET Framework-based client, this header is automatically generated for you and you do not need to worry about it.

Apache SOAP Web services, however, do not require any information from the SOAPAction header. An Apache Web service will be perfectly happy receiving a message with an empty SOAPAction header (although the header itself must still be included in every SOAP message). In the example earlier in this white paper, we did not provide any SOAPAction in the Apache SOAP client we created; consequently, that client would not work with a .NET Framework-based Web service, even if the location and namespace of the service were the same.

Solution

In Apache SOAP, the Call.Invoke() method includes an additional parameter that allows you to specify the content of the SOAPAction header. In our example earlier in this white paper, we simply left this parameter (a String) blank. If you expect that your Java client will be interacting with a .NET Framework-based Web service, simply place the required information for that service in this parameter.

Typically, the SOAPAction header required by a .NET Framework-based Web service follows the form namespace#method-name. The invoke() call in Listing 10 could be used to invoke a .NET Framework-based Web service.

Listing 10. An invoke call to a .NET Framework-based Web service

Response r =
   webcall.invoke("https://localhost:8080/soap/servlet/rpcrouter",
   "https://www.contoso.com/Rpc");

Note that the service being called in Listing 10 is an RPC service; if it were a Document/Literal service, a method name would be required as well.

WSDL support

Problem

In order to add a Web Reference to a .NET Framework-based Web service client, the target Web service must have a WSDL document available. Apache SOAP 2.2 does not contain any support for WSDL.

Solution

Even though the API itself does not support WSDL, it is certainly possible to write or generate one that describes an Apache SOAP service. There are several ways to create a WSDL document for an Apache SOAP 2.2 Web service.

  • Create the WSDL manually in a text editor. This solution can be rather involved, but may be simpler if your Web service is not particularly complex. Writing a WSDL document manually requires an understanding of the WSDL grammar. An excellent tutorial can be found at W3Schools.com.
  • Download Apache AXIS, also known as Apache SOAP 3.0. Instructions for generating WSDL are included with the package.
  • Download third-party WSDL generating software; several Web service software firms have these available, but most are commercial software.

Summary

Web service integration is usually straightforward. If you are designing a Web service, you should design it so that the maximum breadth of clients can access it. If you are designing a client, you should examine the documentation for a Web service to determine how HTTP SOAP requests should be structured, and what you will receive in response. In either case, problems are more easily solved by thinking about interoperability from the beginning, rather than trying to add code later to accommodate specific cases.

© Microsoft Corporation. All rights reserved.