Consuming a Simple XML Web Service

Writing an XML Web service is a wonderful accomplishment, but using it is even better. There are several ways to consume an XML Web service. The easiest way is to use Visual Studio and add a Web reference to the service. (Command-line purists should refer to the next section, "XML Web Services and Command-Line Tools.") The first step in this process is to create a new Web application, with a new Web Forms page. In the Solution Explorer window, right-click the project name, and choose Add Web Reference from the shortcut menu. The Add Web Reference dialog box will appear. In the Add Web Reference dialog box, you can manually enter the address of the xMl Web service or use UDDI to search for an XML Web service. This dialog box also has a link to display the XML Web services on the local Web server. Figure 10-5 shows the Add Web Reference dialog box with the Simple XML Web service selected. The documentation for Simple is shown in the left pane.

^ 0 ^ Jfcttrllt [ fflp I"■■ 10_S-l**5-rv.mfrtmi* TJ [|. ,|

Simple

It^jklrilKK

'hi tf^Refii v* zi^v-:«!: ier a fomui Ar5, -n:- ^imi rtMif m ifjiHi hlUVÜM

"■»tp hi

* liiliz'ffnfii

iBa&cinuutm

Ihifc virfc -.prali p h uilaq MtjK //Ir-ipiH-irp/ in 4L 4?WI »

Irtan* ihc )c*iL weil stfvfc* Is n-sö« wMi.

i!*£h .->J"L rn ri ifrKi iiH -i i LTw^jU- ■in C'isi fw d-»ri j;p4 smrii "z -A r^;-ji h A frcm c^+r i on <M i ilHtwV-r? l-ttpil.iiimpn.or^'ili ^ aiUJlB^r.Tl. art.

,m Ihr- trm rfrrr K> fjb^—f ■W tf-Wi aril l

•öwr ml sbtiw« b# br «»-■rwnT i-r j ii-'rr' ' r'«nebi mi >/ir ru--r!.jiair J lln . j<i ma- ■ »a Hch »pi !■ r nmrifun U^k Lib LiLt., lis | - m-r- -J (fjM %i i.Tua (ah-wr. U •tw n-ib. i -H- "«: i+ri r jiTH ip-fc:*: ar* JI >

^ u^'pljiit iwjp^i.'.i^ i'r prtln n.r ■

_ ä

Figure 10-5 : The Add Web Reference dialog box in Visual Studio .NET, pointing to the Simple XML Web service

Once you click the Add Reference button in the Add Web Reference dialog box, Solution Explorer will contain an additional node, named Web References. Figure 10-6 shows the Web References node expanded.

Solution Explorer - Chapter 10_Tsst5w[)päe5erv,., ? x r+ a

Solution 'Chapter 10 JTe5t5«if]ie5er-;.:e' (1 project)

b & iimmummimsBmm iol References ^ Web References ™ localhost

Reference.roap Simple isco Simple .(«d! Q AssemblyInfo.es

ChapterlOJTestSsinpteServKe.vsclisco Global.asax !"i|i Web.config ~l WebForml .aspw

1 Solution Explorer ^ Class Vie«

Figure 10-6 : Solution Explorer, showing the newly added Web reference to the Simple service

One bit of confusion exists with the default behavior of the Add Web Reference dialog box. Notice that the name of the Web reference in the Solution Explorer is localhost. I happened to refer to the XML Web service using a URL that contained localhost. I can almost guarantee that's not what you'd expect the Web reference to be named. If you're like me, you'll initially presume that localhost refers to the server the servi ce resides on and that Simple is the object you want to create. In reality, localhost refers to the namespace, and Simple is in fact the object you want to create. Most times, you will rename localhost something more meaningful. Therefore, I've renamed the namespace from localhost to HelloWorld, which I'll use for the rest of this example.

Tip My initial thought after I added the Web reference using the URL

localhost/Chapter10_SimpleService/Simple.asmx was, "Darn, I should've used the machine's full name in the URL, not localhost." My concern was that I wouldn't be able to test the page using the XML Web service from my workstation, Dual, because the XML Web service was on my test machine, Test933. Referring to localhost from Dual wouldn't work, however, because Dual doesn't have the XML Web service installed, nor does it have the .NET Framework. Of course, testing from Dual worked just fine. The reason, obvious in retrospect, is that the XML Web service was being resolved on the Web server, not on the client workstation. Thus, localhost was resolved properly on the server, because relative to the Web server, the xMl Web service was located on the localhost. In the real world, an XML Web service is used to expose functionality over the Internet. If you want to expose functionality that will be used on the same machine, using an XML Web service would not be very efficient, because the overhead incurred in calling an XML Web service.

Now that the Web reference has been added, I can reference the XML Web service as if it were any other class. How does this magic work? When you look at the directory on the Web server where the test page with the added Web reference is located, you'll see a new directory, named Web References. Within that directory is another directory, named HelloWorld, the name of the namespace for the Web reference. In that directory, you'll find a C# file with code similar to the code in Listing 10-2. On my system, this file is named Reference.cs.

Listing 10-2 Reference.cs, the proxy code to allow consumption of the Simple XML Web service

<autogenerated>

This code was generated by a tool. Runtime Version: 1.0.3307.0

Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. </autogenerated>

// This source code was auto-generated by Microsoft.VSDesigner, // Version 1.0.3307.0.

namespace Chapter10_TestSimpleService.HelloWorld { using System.Diagnostics; using System.Xml.Serialization; using System;

using System.Web.Services.Protocols; using System.Web.Services;

[System.Diagnostics.DebuggerStepThroughAttribute()]

[System.ComponentModel.DesignerCategoryAttribute("code")]

[System.Web.Services.WebServiceBindingAttribute(

Name="SimpleSoap", Namespace="http://tempuri.org/")] public class Simple :

System.Web.Services.Protocols.SoapHttpClientProtocol {

"http://localhost/Chapter10_SimpleService/Simple.asmx";

[System.Web.Services.Protocols.SoapDocumentMethodAttribute( "http://tempuri.org/HelloWorld", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=

System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] public string HelloWorld(string Language) { object[] results = this.Invoke("HelloWorld", new object[] {

public System.IAsyncResult BeginHelloWorld( string Language, System.AsyncCallback callback, object asyncState) { return this.BeginInvoke("HelloWorld", new object[] { Language}, callback, asyncState);

public string EndHelloWorld(System.IAsyncResult asyncResult) { object[] results = this.EndInvoke(asyncResult); return ((string)(results[0]));

Listing 10-2 is a C# file that represents a proxy class. (A proxy class acts like the real class but is really just a stand-in.) This proxy file happens to be a C# file because the test project I used to generate it is a C# project. Fortunately, there's no problem with using an XML Web service created with Visual Basic .NET inside a Web Forms page created using C#. As you can see, the code in this Simple class doesn't do any of the work of interpreting the string sent as a parameter and returning the strings based on the parameter passed in. Ignoring the complex attributes preceding the proxy class's HelloWorld function, the function itself is quite simple, as shown here:

public string HelloWorld(string Language) {

object[] results = this.Invoke("HelloWorld", new object[] {

Language});

The Invoke method is called, and the return value is an array of objects. In this example, the first element of the array of objects is returned, cast as a string. You might think the code in Listing 10-2 is a little complex (with things like Beginlnvoke, asynchronous callbacks, and so on). Programmers familiar with RPC will recognize just how compact and relatively simple the code is. There's no need to understand this code fully; however if you're interested in learning more, you can look at the System.Web.Services.Protocols.SoapHttpClientProtocol class in the MSDN documentation. This proxy class descends from SoapHttpClientProtocol. The code in Listing 10-2 is automatically generated, and as such it should not be directly modified. If the XML Web service changes, the proxy code must be regenerated. To use the Simple XML Web service, I've created apage, shown in Figure 10-7. This page initially displays "—Pick Language—" in the drop-down list box. You can select a language from the drop-down list, and the SelectedlndexChanged event handler will change the text of the label to "Hello World" in that language. What's actually happening here is that the page is posted back to the Web ser-ver and I then call the Simple XML Web service from the page. If I set the CacheDuration property of the WebMethod attribute to 600, the xMl Web service might run or the requested value might be returned from the cache. It's transparent to the consumer of the XML Web service.

J 1 r%<Vi rti^rr¥hr Hk riFbuft Ininrtri fxcJurrr p> K" ir" f-i^T'" i«n art

JsJsJ

Geiiiit Ytxih'n

Figure 10-7 : A simple test form showing the XML Web service being accessed from a Web Forms page

The TestWebService.aspx file that created the page in Figure 10-7 is shown in Listing 10-3. To make the drop-down list post back to the server, the AutoPostBack attribute is set to True. I've added <asp:ListItem> tags for the language selections, but I could just as easily have used the Add method of the DropDownList1 object in the code-behind file. Listing 10-3 TestWebService.aspx, a Web Forms page used to test the Simple XML Web service

Figure 10-7 : A simple test form showing the XML Web service being accessed from a Web Forms page

The TestWebService.aspx file that created the page in Figure 10-7 is shown in Listing 10-3. To make the drop-down list post back to the server, the AutoPostBack attribute is set to True. I've added <asp:ListItem> tags for the language selections, but I could just as easily have used the Add method of the DropDownList1 object in the code-behind file. Listing 10-3 TestWebService.aspx, a Web Forms page used to test the Simple XML Web service

Codebehind="TestWebService.aspx.cs"

AutoEventWireup="false"

Inherits="Chapter10_TestSimpleService.TestWebService" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" > <HTML> <HEAD>

<meta name="GENERATOR" content="Microsoft Visual Studio 7.0"> <meta name="CODE_LANGUAGE" content="C#" > <meta name="vs_defaultClientScript" content="JavaScript"> <meta name="vs_targetSchema"

content="http://schemas.microsoft.com/intellisense/ie5"> </HEAD> <body>

<form id="TestWebService" method="post" runat="server"> <p align="center"> <asp:DropDownList id="DropDownList1" runat="server"

AutoPostBack="True">

<asp:ListItem Value="— Pick Language —"> —Pick Language —</asp:ListItem> <asp:ListItem Value="Spanish"> Spanish</asp:ListItem> <asp:ListItem Value="Norwegian"> Norwegian</asp:ListItem> <asp:ListItem Value="German"> German</asp:ListItem> <asp:ListItem Value="English"> English</asp:ListItem> </asp:DropDownList></p> <p align="center">

<asp:Label id="Label1" runat="server"

Font-Size="Medium"

Font-Bold="True"

ForeColor="Red">

The code-behind file for TestWebService.aspx is shown in Listing 10-4. Listing 10-4 The code-behind file TestWebService.aspx.cs, used to consume the Simple XML Web service

The code-behind file for TestWebService.aspx is shown in Listing 10-4. Listing 10-4 The code-behind file TestWebService.aspx.cs, used to consume the Simple XML Web service using System; using System.Collections; using System.ComponentModel; using System.Data;

using System.Drawing;

using System.Web;

using System.Web.SessionState;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI. HtmlControls;

namespace Chapter10_TestSimpleService {

/// Summary description for WebForml. /// </summary>

public class TestWebService : System.Web.UI.Page {

protected System.Web.UI.WebControls.DropDownList DropDownListl; protected System.Web.UI.WebControls.Label Labell;

private void Page_Load(object sender, System.EventArgs e) {

// Put user code to initialize the page here.

#region Web Form Designer generated code override protected void OnInit(EventArgs e) {

// CODEGEN: This call is required by the ASP.NET // Web Form Designer.

InitalizeComponent(); base.OnInit(e);

III <summary>

III Required method for Designer support - do not modify III the contents of this method with the code editor. III <Isummary>

private void InitializeComponent() {

this.DropDownListl.SelectedIndexChanged += new System.EventHandler( this.DropDownList1_SelectedIndexChanged); this.Load += new System.EventHandler(this.Page_Load);

#endregion private void DropDownList1_SelectedIndexChanged

(object sender, System.EventArgs e) {

HelloWorld.Simple Hello; Hello=new HelloWorld.Simple();

Label1.Text=Hello.HelloWorld(DropDownList1.SelectedItem.Text);

The three lines of the DropDownList1_SelectedIndexChanged handler are deceptively simple. First, I declare an object of type Simple. Next, I create the Simple object.

Because I added the Web reference to this project, it will not try to instantiate the real Simple class, but rather, the proxy class shown in Listing 10-2. Finally, I set the Labell.Text property to the string returned from a call to the HelloWorld method. What's really happening behind the scenes is quite a bit more interesting. The proxy class is calling to the XML Web service (which could be anywhere, on any accessible server). On getting a response, the string is retrieved from the object array that is returned, and the page is then refreshed with the label set to the text from the HelloWorld method.

XML Web Services and Command-Line Tools

As mentioned, many users will prefer adding a Web reference within Visual Studio. For those interested in the details of what's actually going on, however, the WSDL command-line tool (Wsdl.exe) will generate the proxy code for you explicitly. The command-line options for WSDL are described in Table 10-2.

Table 10-2: WSDL Command-Line Help

Command or Option

Description

wsdl.exe

Utility to generate code for XML Web service clients and XML Web services using ASP.NET from WSDL contract files, XSD schemas, and .discomap discovery documents. This tool can be used in conjunction with disco.exe. wsdl.exe <options> <url or path> <url or path> ...

<url or path>

A URL or path to a WSDL contract, an XSD schema or .discomap document.

/nologo

Suppresses the banner.

/language:<language>

The language to use for the generated proxy class. Choose from 'CS', 'VB', or 'JS' or provide a fully qualified name for a class implementing

System.CodeDom.Compiler.CodeDomProvi der. The default is 'CS' (CSharp). The short form is '/l:'.

/server

Generate an abstract class for an XML Web service implementation using ASP.NET based on the contracts. The default is to generate client proxy classes.

/namespace:<namespace>

The namespace for the generated proxy or template. The default namespace is the global namespace. The short form is '/n:'.

/out:<fileName>

The filename for the generated proxy code. The default name is derived from the service name. The short form is '/o:'.

/protocol:<protocol>

Override the default protocol to implement. Choose from 'SOAP', 'HttpGet', or 'HttpPost' or a custom protocol as specified in the configuration file.

/username:<username>

/password:<password>

/domain:<domain>

The credentials to use when the connecting to a server that requires authentication. The short forms are '/u:', '/p:', and '/d:'.

/proxy:<url>

The URL of the proxy server to use for HTTP requests. The default is to use the

Table 10-2: WSDL Command-Line Help

Command or Option

Description

system proxy setting.

/proxyusername:<username>

/proxypassword:<password>

/proxydomain:<domain>

The credentials to use when the connecting to a proxy server that requires authentication. The short forms are '/pu:', '/pp:', and '/pd:'.

/appsettingurlkey:<key>

The configuration key to use in the code generation to read the default value for the Url property. The default is to not read from the config file. The short form is '/urlkey:'.

/appsettingbaseurl:<baseurl>

The base URL to use when calculating the url fragment. The appsettingurlkey option must also be specified. The url fragment is the result of calculating the relative URL from the appsettingbaseurl to the URL in the WSDL document. The short form is 'baseurl:'.

Many of these options aren't required for normal use, but you'll generally specify at least the language and the URL of the service. For example, to generate a proxy class for the Simple XML Web service, I'd use the WSDL command-line tool to create a proxy class. The command is shown here:

http://localhost/Chapter10_SimpleService/Simple.asmx /n:HelloWorld.Simple

After this command is run, you'll need to compile the resulting Visual Basic .NET source into a DLL. The minimum command to perform this operation is shown here:

C:\>vbc.exe simple.vb

/target:library

/reference:System.dll

/reference:System.Web.Services.dll

/reference:System.Xml.dll

/out:Simple.dll

Once the DLL is built, you can place it in the bin folder of the project you want to reference the XML Web service from and add the DLL to the Imports or using statements at the beginning of the code file.

Once Simple.dll is compiled, I created a virtual directory named TestCommandLineTools to test it. In the TestCommandLineTools folder, I created a bin folder and moved the Simple.dll created using the vbc command above into that folder. Finally, I created a simple page to ensure that I could access the XML Web service through the manually created DLL. That TestCommandLineTools.aspx file is shown in Listing 10-5. Listing 10-5 TestCommandLineTools.aspx, a page to test using the Simple XML Web service.code-behind file

<%@ Import Namespace="HelloWorld.Simple" %>

<script language="C#" runat=server>

public void Page_Load(object sender,EventArgs e) {

Simple Hello=new Simple(); Response.Write(Hello.HelloWorld("Spanish"));

<Iscript>

This page, when run, displays the Spanish version of "Hello World", "Hola Mundo".

This approach is markedly less convenient than using Visual Studio. On the other hand, it will work on a machine with nothing more than the .NET Framework and Notepad installed. In addition, the process must be repeated whenever a change takes place that affects the interface exposed by the XML Web service. Visual Studio .NET provides a more convenient Update Web Reference option.

Tip As of the build of the .NET Framework used to test this example, many of the command-line utilities seem to be spread around in a variety of directories, none of which appear in the path by default. If you're planning to use these command-line utilities, you should find the most commonly used utilities and add the directories they reside in to your path. Note that some utilities are in directories that include the build number, so you should be sure to change your path when you change versions.

0 0

Post a comment