Applied MicrosoftNET Framework Programming in Microsoft Visual BasicNET

Web Service Clients

Now that you ve seen Web services up close and personal, it s time to learn about Web service clients that is, applications that use, or consume, Web methods. It s easy to write Web services. Writing Web service clients is even easier, thanks to some high-level support lent by the .NET Framework class library (FCL) and a code-generator named Wsdl.exe. If you have a WSDL contract describing a Web service (or the URL of a DISCO file that points to a WSDL contract), you can be making calls to that Web service in no time.

Web Service Proxies

The key concept to grasp when writing Web service clients is that of the Web service proxy. A Web service proxy is an object that provides a local representation of a remote Web service. A proxy is instantiated in the client s own application domain, but calls to the proxy flow through the proxy and out to the Web service that the proxy represents. The Wsdl.exe utility that comes with the .NET Framework SDK (and that is integrated into Visual Studio .NET) generates Web service proxy classes from WSDL contracts. Once a proxy is created, calling the corresponding Web service is a simple matter of calling methods on the proxy, as shown here:

CalculatorWebService calc = new CalculatorWebService (); int sum = calc.Add (2, 2);

The methods in the proxy class mirror the Web methods in the Web service. If the Web service exposes Web methods named Add and Subtract, the Web service proxy also contains methods named Add and Subtract. When you call one of these methods, the proxy packages up the input parameters and invokes the Web method using the protocol encapsulated in the proxy (typically SOAP). The proxy insulates you from the low-level details of the Web service and of the protocols that it uses. It even parses the XML that comes back and makes the result available as managed types.

Using Wsdl.exe to generate a Web service proxy is simplicity itself. Suppose you want to call a Web service whose URL is http://www.wintellect.com/calc.asmx. If the Web service was written with the .NET Framework, which means you can retrieve a WSDL contract by appending a ?wsdl query string to the service URL, you can generate a proxy for the Web service like this:

wsdl http://www.wintellect.com/calc.asmx?wsdl

Or you can leave off the query string and let Wsdl.exe supply it for you:

wsdl http://www.wintellect.com/calc.asmx

If Calc.asmx wasn t written with the .NET Framework, it might not support WSDL query strings. In that case, you find the WSDL contract and pass its URL (or local path name) to Wsdl.exe. The following example assumes that the contract is stored in a local file named Calc.wsdl:

wsdl calc.wsdl

However you point it to the WSDL contract, Wsdl.exe generates a CS file containing a class that represents the Web service proxy. That s the class you instantiate to invoke the Web service s methods.

The proxy class s name comes from the service name (that is, the name attribute accompanying the service element) in the WSDL contract. For example, suppose you attribute a Web service as follows in its ASMX file:

[WebService (Name="Calculator Web Service")]

The resulting <service> tag in the WSDL contract looks like this:

<service name="Calculator Web Service">

and the resulting proxy class is named CalculatorWebService. By default, the name of the CS file that Wsdl.exe generates also derives from the service name (for example, Calculator Web Service.cs). You can override that name by passing Wsdl.exe a /out switch. The command

wsdl /out:Calc.cs http://www.wintellect.com/calc.asmx

names the output file Calc.cs regardless of the service name.

Wsdl.exe supports a number of command line switches that you can use to customize its output. For example, if you d prefer the proxy class to be written in Visual Basic .NET rather than C#, use the /language switch:

wsdl /language:vb http://www.wintellect.com/calc.asmx

If you d like Wsdl.exe to enclose the code that it generates in a namespace (which is extremely useful for preventing collisions between types defined in the generated code and types defined in your application and in the FCL), use the /namespace switch:

wsdl /namespace:Calc http://www.wintellect.com/calc.asmx

Classes generated by Wsdl.exe derive from base classes in the FCL s System.Web.Services.Protocols namespace. By default, a proxy class derives from SoapHttpClientProtocol, which enables it to invoke Web methods using SOAP over HTTP. You can change the invocation protocol with Wsdl.exe s /protocol switch. The command

wsdl /protocol:httpget http://www.wintellect.com/calc.asmx

creates a Web service proxy that derives from HttpGetClientProtocol and calls Web methods using HTTP GET commands, while the command

wsdl /protocol:httppost http://www.wintellect.com/calc.asmx

creates a proxy that derives from HttpPostClientProtocol and uses HTTP POST. Why would you want to change the protocol that a proxy uses to invoke Web methods? In the vast majority of cases, SOAP is fine. However, if the methods that you re calling are simple methods that use equally simple data types, switching to HTTP GET or POST makes calls slightly more efficient by reducing the amount of data transmitted over the wire.

Incidentally, if you use Visual Studio .NET to write Web service clients, you don t have to run Wsdl.exe manually. When you use the Add Web Reference command found in the Project menu, Visual Studio .NET runs Wsdl.exe for you and adds the proxy class to your project. Add Web Reference also speaks the language of UDDI, making it easy to search Microsoft s UDDI registry for interesting Web services.

A Simple Web Service Client

Want to write a client for Calc.asmx? Here are the steps:

  1. Use Wsdl.exe to create a proxy class for Calc.asmx. If you installed Calc.asmx in wwwroot, the proper command is

    wsdl http://localhost/calc.asmx

    Wsdl.exe responds by creating a file named Calculator Web Service.cs.

  2. Create a new text file named CalcClient.cs and enter the code in Figure 11-9.

  3. Compile the CS files into a console application with the following command:

    csc CalcClient.cs "Calculator Web Service.cs"

  4. Run CalcClient.exe.

    CalcClient.exe instantiates a Web service proxy and calls the service s Add method. The resulting output proves beyond the shadow of a doubt that Calc.asmx is smart enough to add 2 and 2 (Figure 11-10).

    CalcClient.cs

    using System; class MyApp { public static void Main () { CalculatorWebService calc = new CalculatorWebService (); int sum = calc.Add (2, 2); Console.WriteLine ("2 + 2 = " + sum); } } Figure 11-9

    Console client for Calc.asmx.

    Figure 11-10

    Output from CalcClient.exe.

Avoiding Hard-Coded Service URLs

Look through a CS file generated by Wsdl.exe, and you ll see the Web service proxy class as well as the methods that wrap the Web service s Web methods. You ll also see that the Web service s URL is hardcoded into the CS file in the proxy s class constructor. Here s an example:

public CalculatorWebService() { this.Url = "http://www.wintellect.com/calc.asmx"; }

If the Web service moves, you ll have to modify the CS file and regenerate the proxy.

To avoid having to update code when a Web service s URL changes, you can use Wsdl.exe s /appsettingurlkey (abbreviated /urlkey) switch. The command

wsdl /urlkey:CalcUrl http://www.wintellect.com/calc.asmx

produces the following class constructor:

public CalculatorWebService() { string urlSetting = System.Configuration.ConfigurationSettings.AppSettings["CalcUrl"]; if ((urlSetting != null)) { this.Url = urlSetting; } else { this.Url = "http://www.wintellect.com/calc.asmx"; } }

Now you can assign a value to CalcUrl in the appSettings section of a local Web.config file, like so:

<configuration> <appSettings> <add key="CalcUrl" value="http://www.wintellect.com/calc.asmx" /> </appSettings> </configuration>

If the URL changes, you can update the proxy simply by editing Web.config. No code changes are required.

Asynchronous Method Calls

Something else you ll notice if you open a CS file generated by Wsdl.exe is that the proxy class contains asynchronous as well as synchronous wrappers around the Web service s methods. The former can be used to invoke Web methods asynchronously. An asynchronous call returns immediately, no matter how long the Web service requires to process the call. To retrieve the results from an asynchronous call, you make a separate call later on.

Here s an example using Calc.asmx s Add method that demonstrates how to invoke a Web method asynchronously. The client calls the proxy s BeginAdd method to initiate an asynchronous call and then goes off to attend to other business. Later it returns to finish the call by calling EndAdd:

CalculatorWebService calc = new CalculatorWebService (); IAsyncResult res = calc.BeginAdd (2, 2, null, null); . . . int sum = calc.EndAdd (res);

If the call hasn t completed when EndAdd is called, EndAdd blocks until it does. If desired, a client can use the IsCompleted property of the IAsyncResult interface returned by BeginAdd to determine whether the call has completed and avoid calling EndAdd prematurely:

IAsyncResult res = calc.BeginAdd (2, 2, null, null); . . . if (res.IsCompleted) { int sum = calc.EndAdd (res); } else { // Try again later }

Another option is to ask to be notified when an asynchronous call returns by providing a reference to an AsyncCallback delegate wrapping a callback method. In the next example, EndAdd won t block because it isn t called until the client is certain the method call has returned:

AsyncCallback cb = new AsyncCallback (AddCompleted); IAsyncResult res = calc.BeginAdd (2, 2, cb, null); . . . public void AddCompleted (IAsyncResult res) { int sum = calc.EndAdd (res); }

Whatever approach you decide on, the proxy s asynchronous method call support is extraordinarily useful for calling methods that take a long time to complete. Add isn t a very realistic example because it s such a simple method, but the principle is valid nonetheless.

Web Service Clients and Proxy Servers

If a client invokes methods on a Web service from behind a proxy server, the Web service proxy needs to know the address of the proxy server. You can provide that address in two ways. The first option is to pass Wsdl.exe a /proxy switch specifying the proxy server s URL:

wsdl /proxy:http://myproxy http://www.wintellect.com/calc.asmx

Option number two is to programmatically initialize the Web service proxy s Proxy property (which it inherits from HttpWebClientProtocol) with a reference to a WebProxy object (System.Net.WebProxy) identifying the proxy server:

CalculatorWebService calc = new CalculatorWebService (); calc.Proxy = new WebProxy (http://myproxy, true); int sum = calc.Add (2, 2);

The true passed to WebProxy s constructor bypasses the proxy server for local addresses. Pass false instead to route all requests through the proxy server.

Категории