Section 16.3. Creating the Client Manually

16.3. Creating the Client Manually

Occasionally, using web references in VS2005, does not meet your requirements. This could be due to specific deployment issues, such as language requirements for the proxy class, specification of the proxy class namespace, use of a non-default protocol, login or other security concerns, or any number of special circumstances. Using the command line tools, with their many optional switches and arguments, will often let you fine tune your application's deployment and usability.

This section will review the different ways you can take control of the process of creating and using the proxy, allowing your consuming app to talk to the web service as though they were on the same machine.

16.3.1. Creating the Consumer Web Page Content

Before proceeding with the steps of creating the proxy, it would be helpful to have a consumer application, in this case a web page, to use.

To demonstrate this and to provide a proxy class with a little more meat for analysis, we will work with the StockTickerComplete web service developed in the previous chapter, listed in its entirety in Example 15-18.

If you don't have a virtual directory for that web service on your machine, create one now called StockTicker . You can then see the test page for this web service by entering the following URL in a browser:

 http://localhost/StockTicker/service.asmx 

In VS2005, create a new web site called StockTickerConsumer . This web site will have several text boxes for entering the stock symbol of the firm. It will then return either the firm name, stock price, or stock history. It also has a text box for setting the name of the stock exchange. The web page in Design view will look something like Figure 16-4.

Figure 16-4. StockTickerConsumer Design view

The complete source code for the content file is listed in Example 16-4. This content provides only the minimum user input necessary to allow demonstration of the principles. There are four textboxes, with the following names : txtFirmNameStockSymbol , txtPriceStockSymbol , txtStockExchange , and txtHistoryStockSymbol . The first two have their AutoPostBack property set to TRue . Therefore, as soon as the value in those text boxes changes, it will fire the TextChanged event, which will cause the designated event handler to execute. Each event handler makes a call to the relevant proxy method and displays the returned value in a label next to the text box.

Example 16-4. default.aspx for StockTickerConsumer
 <%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs"    Inherits="_Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server">     <title>StockTickerConsumer</title> </head> <body>     <form id="form1" runat="server">     <div>       <h1>StockTicker Web Service Consumer</h1>       <br/>       Firm Name:&nbsp;&nbsp;&nbsp;       <asp:textBox id="txtFirmNameStockSymbol" runat="server"          OnTextChanged="txtFirmNameStockSymbol_TextChanged"          width="120"          text="Enter stock symbol."          AutoPostBack="true" />       &nbsp;&nbsp;&nbsp;       <asp:label id="lblFirmName" runat="server"/>       <br/>       Stock Price:&nbsp;&nbsp;&nbsp;       <asp:textBox id="txtPriceStockSymbol" runat="server"          OnTextChanged="txtPriceStockSymbol_TextChanged"          width="120"          text="Enter stock symbol."        AutoPostBack="true"/>       &nbsp;&nbsp;&nbsp;       <asp:label id="lblStockPrice" runat="server"/>       <br/>       StockExchange:&nbsp;&nbsp;&nbsp;       <asp:textBox id="txtStockExchange" runat="server"          width="120" />       &nbsp;&nbsp;&nbsp;       <asp:button id="btnStockExchangeSet" runat="server"          text="Set"          onClick="btnStockExchangeSet_Click" />       &nbsp;&nbsp;&nbsp;       <asp:button id="btnStockExchangeGet" runat="server"          text="Get"          onClick="btnStockExchangeGet_Click" />       <br/>       Stock History:&nbsp;&nbsp;&nbsp;       <asp:textBox id="txtHistoryStockSymbol" runat="server"          width="120"          text="Enter stock symbol." />       &nbsp;&nbsp;&nbsp;       <asp:button id="btnGetHistory" runat="server"          text="Get History"          onClick="btnGetHistory_Click" />       <br/>       <asp:Panel id="pnlHistory" runat="Server" visible="false">          <br/>          &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;          Stock Name:&nbsp;&nbsp;&nbsp;          <asp:label id="lblHistoryStockName" runat="server"/>          <br/>          &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;          Stock Price:&nbsp;&nbsp;&nbsp;          <asp:label id="lblHistoryStockPrice" runat="server"/>          <br/>          &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;          Transaction 1:&nbsp;&nbsp;&nbsp;          <asp:label id="lblHistoryDate1" runat="server"/>          &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;          <asp:label id="lblHistoryPrice1" runat="server"/>          <br/>          &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;          Transaction 2:&nbsp;&nbsp;&nbsp;          <asp:label id="lblHistoryDate2" runat="server"/>          &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;          <asp:label id="lblHistoryPrice2" runat="server"/>       </asp:Panel>     </div>     </form> </body> </html> 

The txtStockExchange text box does nothing when the value in the text box changes. However, it has two buttons associated with it. The Set button sets an application variable with the contents of the txtStockExchange text box, and the Get button fills the txtStockExchange text box with the contents of the application variable.

The txtHistoryStockSymbol text box also does nothing when the value in the text box changes. It has the btnGetHistory button associated with it. When that button is clicked, the btnGetHistory_Click event handler is called. This method demonstrates how to retrieve class member variables from within the web service class.

The code-behind file with the event handlers and other code will be developed shortly.

16.3.2. Creating the Proxy

As described in the previous chapter, and shown schematically in Figures 15-1 and 15-3, a web service is consumed by a client application by use of a proxy . A proxy is a substitute, or local stand-in, for the web service. Once the proxy is created and registered with the consuming application, method calls can be made against the web service. In actuality, those method calls will be made against the local proxy. It will seem to the consuming application that the web service is local to the application.

There are two ways to generate the proxy. The first way, demonstrated previously, is to allow VS2005 to create the proxy and register it with the consuming application with the single step of adding a web reference to the consuming app. The advantage to this method is that it requires little work.

The second way (described next) is to generate the source code manually for the proxy class and compile that into the proxy DLL. The advantages to this method are the following:

  • You do not need to use VS2005.

  • The command-line approach offers more flexibility and features over VS2005.

16.3.2.1. Manually generating the proxy class source code

To create the source code for the proxy class, you use a command-line utility called wsdl.exe . This utility takes a .wsdl file as input. The .wsdl file can be stored locally, having been previously created using the command-line utility, or it can be generated on the fly from the web service file itself. The following two command lines will yield the same result, assuming that the local .wsdl file came from the remote .asmx file:

 wsdl MyWebService.WSDL     wsdl http://www.SomeVirtualDirectory/SomeWebService.asmx?wsdl 

For this, and any other ASP.NET command-line utilities, it is easiest to use the command prompt provided as part of the .NET installation, since this command prompt has the PATH environment variable set to include the location of all the command line utilities. To open this command prompt, go to Start All Programs Microsoft Visual Studio 2005 Visual Studio Tools Visual Studio 2005 Command Prompt.


Alternatively, the WSDL utility can take a .discomap file (described earlier in the "Discovery" section) created by the disco utility as input.

This source code will later be compiled into the proxy class, which a consuming application can get a reference to.

To generate the proxy class source code for this web service, enter the following command at a VS2005 command prompt after navigating to the c:\ websites \StockTickerConsumer folder (created in the previous section where the consumer web page was developed):

 wsdl http://localhost/StockTicker/service.asmx?wsdl 

The output from the WSDL utility is a source code file containing the proxy class, which can be compiled into a library, or dll , file. The default language for this output source is C#. To change the language of the output file, use the /language: parameter, or /l: for short. Valid values for the language parameter are CS , VB , or JS , for C#, VB2005, and JScript.NET, respectively. So, to force the output to be VB2005, you would use a command line similar to this:

 wsdl /l:VB http://localhost/StockTicker/service.asmx?wsdl 

By default, the first component of the output filename is based on the input file as follows . If the WebService attribute in the web service class has a Name property, the output file will have that name. If not, the output name will have the name of the web service class. Every output filename has an extension corresponding to the language.

For example, the code-behind file which contains the WebService class for the web service used here, c:\websites\StockTickerComplete\service.cs , has the following WebService attribute and class definition:

 [WebService(Description = "A stock ticker using C#.",                Name = "StockTicker",                Namespace = "www.LibertyAssociates.com")]     .     .     .     public class Service : System.Web.Services.WebService     { 

Running the WSDL utility against this WebService class, the output filename would be StockTicker.cs . However, if the Name property is removed from the WebService attribute, then the output name will be Service.cs . By default the output file will be in the current directory of the command prompt.

You can specify both the output filename and location by using the /out: parameter, or /o: for short. For example, the following command line will force the output file to use VB2005, have the name test.vb , and be located in the bin directory below the current directory:

 wsdl /l:VB /o:bin\test.vb          http://localhost/StockTicker/service.asmx?wsdl 

Table 16-1 shows some of the other switches available to the WSDL utility.

Table 16-1. WSDL utility switches

Parameter

Description

/language

The language for the output proxy class source file. Valid values are CS , VB , JS , VJS , or CPP . The default is CS .

/nologo

Suppress the Microsoft banner.

/namespace:<namespace>

Specify the namespace for the generated proxy. The default is the global namespace.

/protocol:<protocol>

Specify the protocol to implement. Valid values are HttpGet , HttpPost , SOAP , or SOAP12 (corresponding to SOAP Version 1.2). The default is SOAP .

/username:<username>/ password:<password>/domain: <domain>

Credentials to use when connecting to a server that requires authentication.


For a complete list of parameters for wsdl.exe , enter the following from the command line:

 wsdl /? 

16.3.2.2. Proxy class details

Compare selected sections of the original web service class source file, StockTickerComplete\App_Code\service.cs , reproduced here in Example 16-5, with the selected sections of the "manually" generated source code for the proxy class, StockTicker.cs , shown in Example 16-6. (Though you do not actually write any of the code in Example 16-6, it is manually generated in the sense that you run the WSDL utility manually rather than letting VS2005 to it for you.)

Example 16-5. Selected sections of the web service StockTickerComplete\App_Code\ service.cs
 using System.Web; using System.Web.Services; using System.Web.Services.Protocols; using System;                         //  necesary for String class using System.EnterpriseServices;      // necessary for transactions using System.Collections;             //  necssary for ArrayLists using System.Data;                    //  necessary for DataSet using System.Data.SqlClient;          //  necessary for DataSet [WebService(Description = "A stock ticker using C#.",            Name = "StockTicker",            Namespace = "www.LibertyAssociates.com")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1,                    EmitConformanceClaims = true)] [WebServiceBinding(Name = "OverloadedGetValue",                    ConformsTo = WsiProfiles.BasicProfile1_1,                    EmitConformanceClaims = true)] public class Service : System.Web.Services.WebService {    //  Construct and fill an array of stock symbols and prices.    //  Note: the stock prices are as of 5/1/05.    string[,] stocks =       {          {"MSFT","Microsoft","25.30"},          {"DELL","Dell Computers","34.83"},          {"HPQ","Hewlett Packard","20.47"},          {"YHOO","Yahoo!","34.50"},          {"GE","General Electric","36.20"},          {"IBM","International Business Machine","76.38"},          {"GM","General Motors","26.68"},          {"F","Ford Motor Company","9.11"}       };    [WebMethod(Description =                  "Returns the stock price for the input stock symbol.")]    public double GetPrice(string StockSymbol)    //  Given a stock symbol, return the price.    {       //  Iterate through the array, looking for the symbol.       for (int i = 0; i < stocks.GetLength(0); i++)       {          //  Do a case-insensitive string compare.          if (String.Compare(StockSymbol, stocks[i, 0], true) == 0)             return Convert.ToDouble(stocks[i, 2]);       }       return 0;    }    [WebMethod(Description="Returns stock history for " +                "the stock symbol specified.")]    public Stock GetHistory(string StockSymbol)    {       Stock stock = new Stock(  );       //  Iterate through the array, looking for the symbol.       for (int i = 0; i < stocks.GetLength(0); i++)       {          //  Do a case-insensitive string compare.          if (String.Compare(StockSymbol, stocks[i,0], true) == 0)          {             stock.StockSymbol = StockSymbol;             stock.StockName = stocks[i,1];             stock.Price = Convert.ToDouble(stocks[i,2]);             //  Populate the StockHistory data.             stock.History[0] = new StockHistory(  );             stock.History[0].TradeDate = Convert.ToDateTime("5/1/2005");             stock.History[0].Price = Convert.ToDouble(23.25);             stock.History[1] = new StockHistory(  );             stock.History[1].TradeDate = Convert.ToDateTime("6/1/2005");             stock.History[1].Price = Convert.ToDouble(28.75);             return stock;          }       }       stock.StockSymbol = StockSymbol;       stock.StockName = "Stock not found.";       return stock;    } }   //  close for class Service public class Stock {    public string StockSymbol;    public string StockName;    public double Price;    public StockHistory[] History =          new StockHistory[2]; } public class StockHistory {    public DateTime TradeDate;    public double Price; } 

Example 16-6. Selected sections of Proxy class source code file StockTicker.cs
 //----------------------------------------------------------------------- // <auto-generated> //   This code was generated by a tool. //   Runtime Version:2.0.50215.44 // //   Changes to this file may cause incorrect behavior and will be lost if //   the code is regenerated. // </auto-generated> //----------------------------------------------------------------------- using System; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Web.Services; using System.Web.Services.Protocols; using System.Xml.Serialization; // // This source code was auto-generated by wsdl, Version=2.0.50215.44. // . . . /// <remarks/> [System.Diagnostics.DebuggerStepThroughAttribute(  )] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Web.Services.WebServiceBindingAttribute(Name="StockTickerSoap",         Namespace="www.LibertyAssociates.com")] [System.Xml.Serialization.XmlIncludeAttribute(typeof(object[]))]  public partial class StockTickerSoap :    System.Web.Services.Protocols.SoapHttpClientProtocol {  private System.Threading.SendOrPostCallback         GetHistoryOperationCompleted;     /// <remarks/>  public StockTickerSoap(  ) {         this.Url = "http://localhost/stockticker/service.asmx";     }  /// <remarks/>     public event GetHistoryCompletedEventHandler GetHistoryCompleted; . . .     [System.Web.Services.Protocols.SoapDocumentMethodAttribute(             "www.LibertyAssociates.com/GetHistory",             RequestNamespace="www.LibertyAssociates.com",             ResponseNamespace="www.LibertyAssociates.com",             Use=System.Web.Services.Description.SoapBindingUse.Literal,             ParameterStyle=                 System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]  public Stock GetHistory(string StockSymbol) {  object[] results = this.Invoke("GetHistory", new object[] {                     StockSymbol});         return ((Stock)(results[0]));     }     /// <remarks/>  public System.IAsyncResult BeginGetHistory(string StockSymbol,         System.AsyncCallback callback, object asyncState) {  return this.BeginInvoke("GetHistory", new object[] {                     StockSymbol}, callback, asyncState);     }     /// <remarks/>  public Stock EndGetHistory(System.IAsyncResult asyncResult) {  object[] results = this.EndInvoke(asyncResult);         return ((Stock)(results[0]));     }     /// <remarks/>  public void GetHistoryAsync(string StockSymbol) {  this.GetHistoryAsync(StockSymbol, null);     }     /// <remarks/>  public void GetHistoryAsync(string StockSymbol, object userState) {  if ((this.GetHistoryOperationCompleted == null)) {             this.GetHistoryOperationCompleted =                 new System.Threading.SendOrPostCallback(                     this.OnGetHistoryOperationCompleted);         }         this.InvokeAsync("GetHistory", new object[] {                     StockSymbol}, this.GetHistoryOperationCompleted,                         userState);     }     private void OnGetHistoryOperationCompleted(object arg) {         if ((this.GetHistoryCompleted != null)) {             System.Web.Services.Protocols.InvokeCompletedEventArgs                 invokeArgs =                  ((System.Web.Services.Protocols.InvokeCompletedEventArgs)                    (arg));             this.GetHistoryCompleted(this,                 new GetHistoryCompletedEventArgs(                 invokeArgs.Results, invokeArgs.Error,                 invokeArgs.Cancelled, invokeArgs.UserState));         }     }     /// <remarks/>     public new void CancelAsync(object userState) {         base.CancelAsync(userState);     } } /// <remarks/> public delegate void GetHistoryCompletedEventHandler(object sender,         GetHistoryCompletedEventArgs e); /// <remarks/> [System.SerializableAttribute(  )] [System.Xml.Serialization.XmlTypeAttribute(Namespace=     "www.LibertyAssociates.com")]  public partial class StockHistory {  private System.DateTime tradeDateField;     private double priceField;     /// <remarks/>     public System.DateTime TradeDate {         get {             return this.tradeDateField;         }         set {             this.tradeDateField = value;         }     }     /// <remarks/>     public double Price {         get {             return this.priceField;         }         set {             this.priceField = value;         }     } } /// <remarks/> [System.SerializableAttribute(  )] [System.Xml.Serialization.XmlTypeAttribute(       Namespace="www.LibertyAssociates.com")]  public partial class Stock {  private string stockSymbolField;     private string stockNameField;     private double priceField;     private StockHistory[] historyField;     /// <remarks/>     public string StockSymbol {         get {             return this.stockSymbolField;         }         set {             this.stockSymbolField = value;         }     }     /// <remarks/>     public string StockName {         get {             return this.stockNameField;         }         set {             this.stockNameField = value;         }     }     /// <remarks/>     public double Price {         get {             return this.priceField;         }         set {             this.priceField = value;         }     }     /// <remarks/>     public StockHistory[] History {         get {             return this.historyField;         }         set {             this.historyField = value;         }     } } 

There is no need to understand fully all the nuances of the proxy class source code file. Several points are worth noting:

  • The namespaces referenced with the using statements at the beginning of the web service class in Example 16-5 and the proxy class in Example 16-6 differ . This is because the proxy class is not actually using System.Data . It is merely taking the call to the method that will ultimately use System.Data , wrapping it in the proper protocol (SOAP in this case), and passing it over the Internet to the web service. Therefore, the only namespaces actually needed by the proxy class are those necessary for interacting with a web service, serializing the data into an XML data stream, and sending and receiving those XML packages.

  • The StockTickerSoap class in the proxy, which corresponds to the Service class in the web service, inherits from SoapHttpClientProtocol rather than from WebService . This inherited class provides the methods for the proxy to talk to the web service using the SOAP protocol. Notice how the class in the proxy is named based on the Name property of the WebService attribute ( StockTicker ) in the web service class, rather than the actual class name ( Service ).

  • Immediately following the StockTickerSoap class declaration in the generated proxy is a constructor , which is a public method with the same name as the class. In the constructor, the URL of the web service is specified.

    A constructor is the method in a class that is invoked when the class is first instantiated . The constructor is used to initialize the class and put it into a valid state. If a class does not have a constructor, the CLR will create one by default.


  • All the classes created in the web service class, including Stock and StockHistory , have equivalents in the proxy class.

  • Though the original web service class file has the public method GetHistory , the proxy class has that method plus several additional, related , public methods: BeginGetHistory and EndGetHistory , GetHistoryAsync (two overloaded forms), and OnGetHistoryOperationCompleted . In fact, every web method in the original web service class has the same method in the proxy class, plus these others, one for Begin... , one for End... , one or more for ...Async , and one for On...Completed . These additional methods are used to implement asynchronous processing.

Normal method calls are synchronous . In other words, the calling application halts all further processing until the called method returns. If this takes a long time, either because of a slow or intermittent Internet connection (not that that ever happens, of course) or because the method is inherently time-consuming (such as a lengthy database query), then the application will appear to hang and wait.

On the other hand, if the method call is made asynchronously, then the Begin method call is sent out, and processing can continue. When the results come back, the corresponding End method call receives the results. Asynchronous method calls will be demonstrated later in this chapter.

16.3.3. Compiling the Proxy Class

The output of the WSDL utility is a class source code file for the proxy. This source code then must be compiled into a class which can be instantiated in your code. There are two ways to do this: you can let the .NET Framework do it for you, or you can do it manually from the command line. You will see how both ways work in this section.

16.3.3.1. Automatic compilation in the App_Code folder

To let the .NET Framework compile the class for you, create a folder under the application root called App_Code . This is a special folder name in ASP.NET. Any source code in that folder will automatically be compiled and made available to the application at design time and at runtime.

To see this in action, create an App_Code folder under the StockTickerConsumer directory and copy the previously created StockTicker.cs proxy source file to that folder. Now you can instantiate a new StockTicker object in your code.

However, as you saw in the proxy class source code excerpted in Example 16-6, the StockTicker class has been renamed in the proxy class to StockTickerSoap . So, to instantiate a StockTicker object in the consuming application, add the following line of code inside the Page class:

 StockTickerSoap proxy = new StockTickerSoap(  ); 

Now you can call any of the public methods from the StockTickerSoap (previously called StockTicker ) class, as in the following highlighted line of code:

 protected void txtFirmNameStockSymbol_TextChanged(object sender,                                                   EventArgs e)     {  lblFirmName.Text = proxy.GetName(txtFirmNameStockSymbol.Text);  } 

16.3.3.2. Manual compilation

You can take full manual control over the compilation process by compiling the proxy class with the appropriate command-line compiler (do not put in line breaks):

 csc /out:bin\StockTickerProxy.dll /t:library         /r:system.dll,system.web.dll,system.web.services.dll         StockTicker.cs 

Be certain no extraneous spaces are in the comma-separated list of DLLs.

The C# compiler does not require explicit references to all the assemblies used in the proxy class, such as System.Data.dll., since a configuration file is located in the .NET Framework program directory, called csc.rsp , which contains the list of default references for the C# compiler.


The result of this command will be a compiled assembly called StockTickerProxy.dll in a folder called bin immediately under the application root. Any assembly files located in this folder will automatically be made available to the application at design time and at runtime.

With the compiled assembly in the bin folder, you can instantiate and use the proxy class the same way as if the proxy source was placed in the App_Code folder, described above.

Putting the compiled output in the bin folder is not required. It can go anywhere you want. However, if it is in the bin folder, then there is no need to create a reference to the assembly in the application. Adding such a reference will be described in the next section.

Creating and compiling the proxy file manually requires several steps, all performed at a command prompt. Further, several of those steps involve a fair amount of typing of parameters, with lots of places to make mistakes. Finally, when all is done, you probably need to move or copy the resulting . dll file to a different directory.

This entire process can be automated somewhat by creating a batch file , which are text files that contain one or more command-line operations. The batch file, which has an extension of .bat , can be executed from the command line, and all the operations within the file are executed one after the other as though they were manually entered at the command line.

Back in the days of DOS, batch files were used extensively. It is possible to make them fairly sophisticated, with replaceable parameters, conditional processing, and other programmatic niceties. For our purposes, a simple batch file will do.

Example 16-7 shows the contents of a batch file that changes to the correct current directory, runs the WSDL utility, compiles the resulting source code, and copies the resulting DLL from one bin directory to another.

Example 16-7. StockTickerProxy.bat
 e: cd \websites\StockTickerConsumer rem   Generate the proxy class source file wsdl http://localhost/StockTicker/service.asmx?wsdl rem  Compile the proxy class source file csc /out:bin\StockTickerProxy.dll /t:library     /r:system.dll,system.web.dll,system.web.services.dll     StockTicker.cs rem  Copy the dll copy bin\StockTickerProxy.dll      c:\inetpub\wwwroot\WebServiceConsumer\bin 

The first line in the batch file makes drive E the current drive. The next line changes the current directory. Blank lines are ignored. Lines beginning with rem are comments and are also ignored, though the contents are displayed on the screen as the file is processed . After the WSDL utility is run and the resulting file is compiled, it is copied . This last command is equivalent to the following:

 copy e:\websites\StockTickerConsumer\bin\StockTickerProxy.dll          c:\inetpub\wwwroot\WebServiceConsumer\bin 

Be careful of inadvertent line breaks. A line break in a batch file is the equivalent of hitting the Enter key on the keyboard.

16.3.4. Finishing the Consumer App

There are three ways to make the proxy class available to the consuming application:

  • Place the source code for the proxy class in the App_Code folder.

  • Place the compiled assembly in the bin folder.

  • Place the compiled assembly in an arbitrary location and add a reference to that assembly.

The first two techniques have been covered. To implement the third technique, adding a reference to an arbitrary assembly, click on the Website Add Reference... menu item or right-click on the project file in the Solution Explorer and select Add Reference....You will get the Add Reference dialog box. The assemblies listed on the .NET tab are those which have been installed to the Global Assembly Cache, or GAC. (Assemblies and the GAC will be covered in Chapter 19.) Click on the Browse tab to get the dialog box shown in Figure 16-5, where you can browse for the .dll file to reference.

Figure 16-5. Add Reference dialog box

With the proxy class either compiled in the bin folder, the source in the App_Code folder, or a reference added, you can code the code-behind file to complete the StockTickerConsumer web page. The complete source code for the code-behind file is listed in Example 16-8 to go along with the content file listed previously in Example 16-4. All the references to the proxy are highlighted.

Example 16-8. default.aspx.cs for StockTickerConsumer
 using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; public partial class _Default : System.Web.UI.Page {  StockTickerSoap proxy = new StockTickerSoap(  );  protected void Page_Load(object sender, EventArgs e)    {    }    protected void txtFirmNameStockSymbol_TextChanged(object sender,                                                      EventArgs e)    {       lblFirmName.Text =  proxy.GetName  (txtFirmNameStockSymbol.Text);    }    protected void txtPriceStockSymbol_TextChanged(object sender,                                                   EventArgs e)    {       lblStockPrice.Text = "$ " +          Convert.ToString(  proxy.GetPrice  (txtPriceStockSymbol.Text));    }    protected void btnStockExchangeSet_Click(object sender, EventArgs e)    {  proxy.SetStockExchange  (txtStockExchange.Text);    }    protected void btnStockExchangeGet_Click(object sender, EventArgs e)    {       txtStockExchange.Text =  proxy.GetStockExchange  (  );    }    protected void btnGetHistory_Click(object sender, EventArgs e)    {       Stock theStock =  proxy.GetHistory  (txtHistoryStockSymbol.Text);       string StockName = theStock.StockName;       double StockPrice = theStock.Price;       DateTime TradeDate1 = theStock.History[0].TradeDate;       double Price1 = theStock.History[0].Price;       DateTime TradeDate2 = theStock.History[1].TradeDate;       double Price2 = theStock.History[1].Price;       //  Display the results.       pnlHistory.Visible = true;       lblHistoryStockName.Text = StockName;       lblHistoryStockPrice.Text = "$ " + Convert.ToString(StockPrice);       lblHistoryDate1.Text = TradeDate1.ToString("d");       lblHistoryPrice1.Text = "$ " + Convert.ToString(Price1);       lblHistoryDate2.Text = TradeDate2.ToString("d");       lblHistoryPrice2.Text = "$ " + Convert.ToString(Price2);    } } 

The first line of code inside the class instantiates the web service class that was recently compiled (or placed in the App_Code directory). By instantiating the proxy here, the proxy variable can be used in any of the code that consumes the web service.

If you try to code against the proxy before you have provided the proxy class to VS2005, either as a web reference, a reference, compiled in the bin folder, or the source code in the App_Code folder, then any references to the proxy will be underlined by the editor as syntax errors.

To retrieve the Stock member variables, you must first instantiate the Stock class. Looking back at Example 15-15 in the previous chapter, you will recall that the GetHistory web method returns an object of type Stock . The Stock object is instantiated here in the event handler with the following line of code:

 Stock theStock = proxy.GetHistory(txtHistoryStockSymbol.Text); 

Once the class is instantiated, it is a simple matter to assign its member variables to local variables in the event handler using dot notation :

 string StockName = theStock.StockName; 

Accessing the array variables contained in the StockHistory class contained within the Stock class is similar:

 DateTime TradeDate1 = theStock.History[0].TradeDate; 

Recall that array indices are zero-based .

To repeat a point made in the previous chapter, when the web service example was first created, a real-world application would not store this type of history data in an array, nor would it display the history data in fixed variables as shown here. More likely, you would have the data in a collection or a dataset and display the data in some sort of data-bound control, as described in Chapter 9.


To display the history, several labels contained within an ASP.NET Panel control are used. The panel is used to control the labels' visibility. When the page is originally designed, the panel has its Visibility property set to false . When it is time to display the results in the Button event handler, the panel then has its Visibility property set to true , which makes all the labels contained within the panel visible.

The important point to understand here is that calls to the web service are made instead to the proxy as though the web service were a local DLL or component. When your code makes a method call to the proxy DLL, it has no idea that the call is being satisfied over the Internet by a web service. The proxy hides all the complex stuff required to package the method call up as a SOAP message, send it out over the wire using the proper protocol (typically HTTP), receive the SOAP message response, and return that back to your calling program as though the Internet was never involved.

When the StockTickerConsumer web page is run and some values inserted into the text boxes, you will see something like that shown in Figure 16-6.



Programming ASP. NET
Programming ASP.NET 3.5
ISBN: 0596529562
EAN: 2147483647
Year: 2003
Pages: 173

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