Writing XML Web Service Clients


I found writing a client as easy as writing the service itself. The ASP.NET listener that funnels incoming requests to XML Web service objects accepts two different ways of packaging the incoming requests. These are HTTP POST and SOAP (support for HTTP GET has been removed from version 1.1). This is conceptually similar to an aircraft control tower speaking three dialects of English, say U.S., British, and Strine (Australian). The HTTP POST approach is present primarily for backward compatibility. New development projects will find it easier and more powerful to use SOAP, particularly when you see the prefabricated support for this protocol that Visual Studio .NET and other toolkits provide. Because of this, I’ll only discuss SOAP-based clients in this book, though I’ll leave HTTP GET (now broken in 1.1) and HTTP POST samples on the Web site.

SOAP, which stands for Simple Object Access Protocol, is an XML vocabulary that describes function calls and their parameters. A client of our sample XML Web service will format a SOAP request packet, as shown in Listing 4-3 (namespaces omitted for clarity) and send it to our XML Web service by means of an HTTP POST operation. The XML Web service will parse the packet, create the object, call the method with the specified parameters, and return a SOAP response packet, as shown in Listing 4-4. I learned the required formatting of the SOAP packets for this XML Web service by looking at the test page for this method, shown previously in Figure 4-7.

Most XML Web service clients will use SOAP for a message format.

Listing 4-3: SOAP request packet.

start example
<soap:Envelope> <soap:Body> <GetTime> <ShowSeconds>0</ShowSeconds> </GetTime> </soap:Body> </soap:Envelope>
end example

Listing 4-4: SOAP response packet.

start example
<soap:Envelope> <soap:Body> <GetTimeResponse> <GetTimeResult>9:34</GetTimeResult> </GetTimeResponse> </soap:Body> </soap:Envelope>
end example

To demonstrate that you don’t have to use .NET at all to write a SOAP- based XML Web service client, I’ve written one using Visual Basic 6. Figure 4-8 shows a screen shot of it. The sample program assembles and reads the SOAP packets using Microsoft’s COM-based XML parser, and it uses the Microsoft Internet Transfer Control (again, COM-based) to do the actual HTTP communication. The code is somewhat unwieldy, so I haven’t listed it in this book, but you will find it in the sample code on the book’s Web site. Simply by running it, you can see the client program converting the user’s input to SOAP, sending the SOAP to the server and receiving SOAP in reply, and parsing meaning from the SOAP and displaying it to the user.

XML Web service SOAP request and response packets are shown in the following figures.

click to expand
Figure 4-8: Sample application showing SOAP access to the XML Web service.

The SOAP example is quite tedious to write. It reminds me of manually writing an IDispatch client in classic COM in the sense that there’s an awful lot of boilerplate packaging that’s critical to get correct (one character off and you’re hosed) but which varies little from one method to the next. As Visual C++ provided wrapper classes that took the pain out of accessing Automation objects (many Visual Basic programmers never knew it was painful for the C++ geeks, and the rest either didn’t care or actively approved), many vendors provide tools that generate proxy wrapper classes that make writing a SOAP client for your XML Web service a trivial operation. These generators read the WSDL file that describes an XML Web service and produce a class in a high-level language containing type-safe methods for accessing the XML Web service. For example, the IBM Web Service Toolkit provides a utility that reads WSDL and produces a proxy class written in Java. The Microsoft SOAP toolkit produces COM-based proxy classes that can be used from non-.NET Microsoft code. SourceForge produces proxy classes written in Python, and SOAP::Lite produces proxy classes for Perl.

A client-side SOAP proxy class makes client applications much easier to write.

As you might imagine, .NET comes with its own tool for generating proxy wrapper classes for the use of .NET Framework programs. The command-line utility program Wsdl.exe, which comes with the .NET Framework SDK, reads the description of the XML Web service from a WSDL file and generates a proxy for accessing its methods from the language you specify. It currently supports Visual Basic, C#, J#, and JavaScript, but not C++. You can ask for proxies that use any of the supported transport protocols, but the default is SOAP.

The .NET Framework SDK provides a proxy class generator.

I’ve written a sample program that demonstrates the use of the Visual Studio proxy generator. A screen shot is shown in Figure 4-9.


Figure 4-9: Proxy generator example.

I created a standard Windows Forms project. I then right-clicked References in Solution Explorer and selected Add Web Reference from the context menu, and the Add Web Reference dialog box appeared. I entered the address of my XML Web service page, as shown in Figure 4-10. This caused the internal browser to request the page, returning its WSDL description, shown previously in Listing 4-2. I then clicked the Add Reference button, and Visual Studio ran Wsdl.exe internally, asking for a SOAP-based proxy in the language of the project, in this case, Visual Basic. Visual Studio then displayed the namespace of the proxy class in Solution Explorer. The most informative view of it is the Class View, as shown in Figure 4-11.

Visual Studio .NET uses the proxy class generator internally.

click to expand
Figure 4-10: Adding a Web reference in Visual Studio.

click to expand
Figure 4-11: Class view of the TimeService reference.

When my client wants to access the XML Web service, I simply create an object of the proxy class and call the desired method on it, as shown in Listing 4-5. Even though it’s an XML Web service call, it looks and feels as though you’re creating and using any other .NET object.

Listing 4-5: Code accessing XML Web service by means of a proxy.

start example
Private Sub Button1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles Button1.Click ’ Create proxy object Dim foo As New localhost.TimeService() ’ Call function on proxy object, which will invoke Web ’ servicevia SOAP. Place results in label for user to see. Label1.Text = foo.GetTime(CheckBox1.Checked) End Sub
end example

The proxy class file, named Reference.vb, doesn’t appear in Solution Explorer, but it lives in a project subdirectory where you can examine it. Listing 4-6 shows selected portions of the code from our time service proxy. You can see that it inherits from the base class System.Web.Services.Protocols.SoapHttpClientProtocol. From this base class it inherits a property called Url, which specifies the URL of the server to which the call is directed. This property contains a default value, which it gets from the original WSDL file, but the sample program demonstrates how you can change it at run time if you want. When the client calls the named method on the proxy, the proxy calls the generic method Invoke, which, again, it has inherited from the base class. This method creates a SOAP packet containing the method name and parameters of the desired XML Web service method and sends it to the server over HTTP. When the SOAP response packet comes back from the server, the base class parses out the return value and returns it to the proxy, which then returns it to the client. Another useful proxy property is Timeout, which is the number of milliseconds that the proxy will wait for the response from the server before throwing up its hands and returning an error.

Listing 4-6: Proxy code generated by Visual Studio.

start example
<System.Diagnostics.DebuggerStepThroughAttribute(), _ System.ComponentModel.DesignerCategoryAttribute("code"), _ System.Web.Services.WebServiceBindingAttribute(Name:="TimeServiceSoap", _ [Namespace]:="http://tempuri.org/")> _ Public Class TimeService Inherits System.Web.Services.Protocols.SoapHttpClientProtocol <System.Web.Services.Protocols.SoapDocumentMethodAttribute( _  "http://tempuri.org/GetTime", _ RequestNamespace:="http://tempuri.org/", _ ResponseNamespace:="http://tempuri.org/", _ Use:=System.Web.Services.Description.SoapBindingUse.Literal, _ ParameterStyle:= _ System.Web.Services.Protocols.SoapParameterStyle.Wrapped)> _ Public Function GetTime(ByVal ShowSeconds As Boolean) As String Dim results() As Object = _ Me.Invoke("GetTime", New Object() {ShowSeconds}) Return CType(results(0),String) End Function End Class
end example

Note that the attributes block in the function name (the characters between the angle brackets) contains information that tells the base class how to package the call, such as the names of methods. Visual Studio .NET makes extensive use of these metadata attributes as a way of passing information to the prefabricated functionality of system code. In earlier days, this would probably have been done through member variables of the base class, where it would have been difficult to differentiate immutable run-time attributes from those that can change during program execution. The new arrangement is harder to mess up, which is generally a good idea.

The Internet can be a lot of fun, but it’s almost always so crowded that you have no hope of enjoying it without a clever strategy for managing its chronic overload—sort of like Disney World. Even the simplest call to an XML Web service might take 5 or 10 seconds to complete, depending on network and server traffic, and the time can go up to anything from there. You can’t leave a user with a frozen interface for more than a second or two, if that. Accordingly, our proxy provides both synchronous and asynchronous mechanisms for calling the methods of the XML Web service. In addition to the GetTime method that we called, you’ll notice that the proxy contains methods called BeginGetTime and EndGetTime. The proxy generator creates Begin[name] and End[name] methods for each method in the XML Web service. The Begin method starts the call, hands it off to a background thread, and returns immediately. The End method harvests the result when the call is finished. You can either poll periodically to see if the operation is complete or you can be notified by a callback function. The sample program demonstrates the latter technique. This asynchronous operation isn’t limited to XML Web service proxies but instead is available to any function call in .NET. I discuss its operation in more detail in Chapter 8.

Calls from a client to an XML Web service usually want to run asynchronously.




Introducing Microsoft. NET
Introducing Microsoft .NET (Pro-Developer)
ISBN: 0735619182
EAN: 2147483647
Year: 2003
Pages: 110

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