Visual Studio .NET includes a wizard that makes creating a Web services client easy, using an “add a reference” metaphor that will be familiar to many programmers. To see how this is done, we’ll build a Web services client in C# for XMethods’ sample temperature service. This service provides the temperature in degrees Fahrenheit for a given U.S. zip code.
Using the Add Web Reference wizard
The Add Web Reference wizard can be invoked in several ways: You can use the Solution Explorer’s right-click context menu or use the Project>Add Web Reference menu option. Invoking the wizard presents a Web browser window, shown in Figure A.
In theory, you can use the built-in UDDI search feature to locate the Web service you want to consume, but in practice, I’ve found it difficult to locate many working services in this fashion. So I use external sources like XMethods. In this case, since you know the URL for the service definition you’ll be consuming (http://www.xmethods.net/sd/2001/TemperatureService.wsdl), you can simply type or paste it into the browser.
Once the browser downloads the definition files for the temperature service, click the Add Reference button. Visual Studio .NET will create a local proxy class based on the service’s WSDL definition to which your client application can bind. This class will be added to your project in a child namespace of your project’s namespace—in this case, you should find that a net.xmethods.www.TemperatureService class has been added to your project.
You can look over the generated code by checking out Listing A. The class view of my sample project in Figure B shows the newly created namespace hierarchy for the proxy class.
|The class view of the TemperatureService proxy class|
By default, this generated code is saved under a Web References subfolder in your project’s folder and is hidden by the Solution Explorer. You can open it manually or click the Show All Files toolbar button if you want to view or tweak it.
Understanding the generated code
The generated class inherits from System.Web.Services.Protocols.SoapHttpClientProtocol, which provides a base set of methods for consuming a Web service. The association with the actual Web service is defined by a set of attributes that decorate the main class and the proxy class’s constructor, which sets the URL for the service into the base class’s Url property. I’ve listed these attributes and their meanings in Table A.
The System.Web.Services.WebServiceBindingAttribute attribute associates the proxy class with a service by name, in this case, SQL Terms and DefinitionsSoap. This name is defined as a service port in the Web service’s WSDL definition. Visual Studio creates three methods for each of the operations defined for a given service port: two for asynchronous invocation and one for synchronous use. You can, despite the commented warnings inserted by the wizard, clean out the method versions you don’t want to use to keep things tidy.
Ports and operations? What are those?
Visual Studio uses a Web service’s WSDL definition document to build your local proxy class. Web services can offer various binding points, defined as ports in the WSDL document, to support different protocols or functionality—think of these as you would interfaces. The methods available for each Web service interface are defined as operations in WSDL. For more information on WSDL itself, see “Defining Web services in WSDL: A primer.”
You’ll notice that the synchronous proxy class method, GetTemp, also has an attribute associated with it. The System.Web.Services.Protocols.SoapDocumentMethodAttribute allows you to specify the header for the SOAP message sent by the decorated proxy message. By changing the header, you can change the way the remote service handles your message.
Using the proxy class
At this point, you have a local class that your application can use to access the methods provided by the Web service. Now it’s a simple matter of object creation and method invocation to use any of the methods provided by the service. In Listing B, I’ve placed the code for a simple console application that requests the temperature for locations typed in by the user. You can see there’s not much to it: First, the proxy class is instantiated and the user is prompted for a zip code. Then, the GetTemp method is invoked, which takes care of calling the actual remote method behind the scenes. That’s really all there is to it, at least in the case of a simple service.