Consuming Web Services

for RuBoard

Now that we have created several XML Web services, let's take a look at how to consume them. As mentioned earlier, XML Web services can be consumed by any client that is capable of making a request over HTTP and parsing out the returned XML. The .NET framework is capable of working in this fashion, but it also has tools for creating something called a Web service proxy that greatly simplifies access to a Web service. You can create a Web service proxy in two ways. If you are using Visual Studio .NET, you can add what is called a Web Reference by pointing Visual Studio .NET to the URL of the Web service. If you are not using Visual Studio .NET, you can use a tool called Web Service Description Language Tool (wsdl.exe) to create the Web service proxy.

Let's take a look at wsdl.exe first. At a minimum, the utility requires a path to a Web service or to the WSDL that describes the Web service ”hence the name of the utility. Given this, it will generate the proxy class. This class has the same method signatures as the Web service and hides the implementation details so that calling the Web service is transparent. If we run wsdl.exe against the SimpleDataSet example with the following command line:

 Wsdl http://localhost/book/webservices/simpledataset/dataset.asmx /language:cs 

We get back a new file named after the class contained within the dataset.asmx file, datasetsample.cs. This file is shown in Listing 6.12.

Listing 6.12 A Proxy Class (datasetsample.cs) for SimpleDataSet Generated with the WSDL Tool
 //------------------------------------------------------------------------------ // <autogenerated> //     This code was generated by a tool. //     Runtime Version: 1.0.2914.16 // //     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 wsdl, Version=1.0.2914.16. // using System.Diagnostics; using System.Xml.Serialization; using System; using System.Web.Services.Protocols; using System.Web.Services; [System.Web.Services.WebServiceBindingAttribute(Name="DataSetSampleSoap", Namespace="http://tempuri.org/")] public class DataSetSample : System.Web.Services.Protocols.SoapHttpClientProtocol {     [System.Diagnostics.DebuggerStepThroughAttribute()]     public DataSetSample() {         this.Url = "http://localhost/book/webservices/csharp/simpledataset/dataset.asmx";     }     [System.Diagnostics.DebuggerStepThroughAttribute()]     [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/ Simple", Use=System.Web.Services.Description.SoapBindingUse.Literal, Parameter-Style=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]     public System.Data.DataSet Simple() {         object[] results = this.Invoke("Simple", new object[0]);         return ((System.Data.DataSet)(results[0]));     }     [System.Diagnostics.DebuggerStepThroughAttribute()]     public System.IAsyncResult BeginSimple(System.AsyncCallback callback, object asyncState) {         return this.BeginInvoke("Simple", new object[0], callback, asyncState);     }     [System.Diagnostics.DebuggerStepThroughAttribute()]     public System.Data.DataSet EndSimple(System.IAsyncResult asyncResult) {         object[] results = this.EndInvoke(asyncResult);         return ((System.Data.DataSet)(results[0]));     } } 

This new proxy class can then be included in a project to encapsulate access to the Web service. If we want to use it in a Windows forms project, we can include it in our project. We then use it by creating a new instance of the Web service object as though it is a local object instead of a remote one. Listing 6.13 shows a Windows form with a data grid on it, which retrieves the DataSet from SimpleDataSet and binds it to a form.

Listing 6.13 A Form That Is Bound to the SimpleDataSet Web Service
 using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data; namespace SimpleFormsClient {     public class Form1 : System.Windows.Forms.Form     {         private System.Windows.Forms.DataGrid dataGrid1;         private System.ComponentModel.Container components = null;         public Form1()         {             //             // Required for Windows Form Designer support             //             InitializeComponent();         }         protected override void Dispose( bool disposing )         {             if( disposing )             {                 if (components != null)                 {                     components.Dispose();                 }             }             base.Dispose( disposing );         }         #region Windows Form Designer generated code         /// <summary>         /// Required method for Designer support - do not modify         /// the contents of this method with the code editor.         /// </summary>         private void InitializeComponent()         {             this.dataGrid1 = new System.Windows.Forms.DataGrid();             ((System.ComponentModel.ISupportInitialize)(this.dataGrid1)) .BeginInit();             this.SuspendLayout();             //             // dataGrid1             //             this.dataGrid1.DataMember = "";             this.dataGrid1.Dock = System.Windows.Forms.DockStyle.Fill;             this.dataGrid1.Name = "dataGrid1";             this.dataGrid1.Size = new System.Drawing.Size(504, 389);             this.dataGrid1.TabIndex = 0;             //             // Form1             //             this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);             this.ClientSize = new System.Drawing.Size(504, 389);             this.Controls.AddRange(new System.Windows.Forms.Control[] {                                                                           this. dataGrid1});             this.Name = "Form1";             this.Text = "Form1";             this.Load += new System.EventHandler(this.Form1_Load);             ((System.ComponentModel.ISupportInitialize)(this.dataGrid1)).EndInit();             this.ResumeLayout(false);         }         #endregion         [STAThread]         static void Main()         {             Application.Run(new Form1());         }         private void Form1_Load(object sender, System.EventArgs e)         {             DataSetSample dss = new DataSetSample();             dataGrid1.DataMember = "Orders";             dataGrid1.DataSource = dss.Simple();         }     } } 

The important stuff is in the last few lines. I have added three lines of code that do all the work to the form load. The first lines get a new instance of the Web service proxy class. Then, calling the WebMethod on the new class is as simple as the last line: dss.Simple() . That's it. The .NET framework hides all the hard stuff, making calling remote Web methods on a Web service as easy as calling methods on local classes. Figure 6.9 shows the resulting form.

Figure 6.9. A Windows form showing the result of calling the SimpleDataSet Web service.

graphics/06fig09.jpg

SoapHttpClientProtocol

This is the class from which the Web proxies generated by WSDL and Visual Studio .NET derive.

Of course, you aren't limited to calling XML Web services from Windows forms. It is just as easy to call a Web service from a Web form. This time around, I am going to include a Web reference in a Visual Studio .NET Web form project. I do this by pointing the Add Web Reference dialog box to the URL where the XML Web services resides. The dialog box will automatically find the WSDL and allow me to add the reference. Visual Studio .NET will then create the proxy class for me, eliminating the need for wsdl.exe. Visual Studio .NET names the proxy slightly differently than when you create it with wsdl.exe. The biggest difference is that it creates a namespace that is set to the hostname.domainname combination of the Web service that you created it from. Listing 6.14 shows the proxy that was created by Visual Studio.NET.

Listing 6.14 The Proxy Created for SimpleDataSet by Visual Studio .NET
 //------------------------------------------------------------------------------ // <autogenerated> //     This code was generated by a tool. //     Runtime Version: 1.0.2914.16 // //     Changes to this file may cause incorrect behavior and will be lost if //     the code is regenerated. // </autogenerated> //------------------------------------------------------------------------------ namespace SimpleDataSetWebClient.localhost {     using System.Diagnostics;     using System.Xml.Serialization;     using System;     using System.Web.Services.Protocols;     using System.Web.Services;     [System.Web.Services.WebServiceBindingAttribute(Name="DataSetSampleSoap",  Namespace="http://tempuri.org/")]     public class DataSetSample : System.Web.Services.Protocols. SoapHttpClientProtocol {         [System.Diagnostics.DebuggerStepThroughAttribute()]         public DataSetSample() {             this.Url = "http://localhost/book/webservices/csharp/simpledataset/dataset.asmx";         }         [System.Diagnostics.DebuggerStepThroughAttribute()]         [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http:// tempuri.org/Simple", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]         public System.Data.DataSet Simple() {             object[] results = this.Invoke("Simple", new object[0]);             return ((System.Data.DataSet)(results[0]));         }         [System.Diagnostics.DebuggerStepThroughAttribute()]         public System.IAsyncResult BeginSimple(System.AsyncCallback callback, object asyncState) {             return this.BeginInvoke("Simple", new object[0], callback, asyncState);         }         [System.Diagnostics.DebuggerStepThroughAttribute()]         public System.Data.DataSet EndSimple(System.IAsyncResult asyncResult) {             object[] results = this.EndInvoke(asyncResult);             return ((System.Data.DataSet)(results[0]));         }     } } 

When using a Web form to create this object, we have to use slightly different syntax, which in this case is localhost.DataSetSample . The namespace is fixed, even if you change the location that you use to access the Web service. If you right-click the localhost reference in Visual Studio .NET, you can rename the localhost, which will change the namespace. If you want to change the location that is used to access the Web service, you can use the URL property of the proxy class. This property expects a fully qualified reference to the .ASMX file that matches the proxy class. The Web form client for SimpleDataSet shown in Listing 6.15 uses the URL property to change the location.

Listing 6.15 A Web Form Client for SimpleDataSet
 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 SimpleDataSetWebClient {     public class WebForm1 : System.Web.UI.Page     {         protected System.Web.UI.WebControls.DataGrid DataGrid1;         public WebForm1()         {             Page.Init += new System.EventHandler(Page_Init);         }         private void Page_Load(object sender, System.EventArgs e)         {             localhost.DataSetSample dss = new localhost.DataSetSample();             dss.Url = "http://localhost/book/webservices/csharp/SimpleDataSet/DataSet.asmx";             // Indicate which table in the dataset should be bound to             DataGrid1.DataMember = "Orders";             // Get the dataset and set it to the source             DataGrid1.DataSource = dss.Simple();             // Force the binding to happen             DataGrid1.DataBind();         }         private void Page_Init(object sender, EventArgs e)         {             InitializeComponent();         }         #region Web Form Designer generated code         /// <summary>         /// Required method for Designer support - do not modify         /// the contents of this method with the code editor.         /// </summary>         private void InitializeComponent()         {             this.Load += new System.EventHandler(this.Page_Load);         }         #endregion     } } 

Again, the interesting lines are the ones in Page_Load. The first line creates a new instance of the proxy class using the localhost namespace. The next line changes the URL from the initial one used to create the proxy to the one that will be used in the "production" environment. Then the datagrid binding syntax binds the returned dataset directly to the grid. The last line calls DataBind() to tell the framework that it is now time to perform the binding.

Asynchronous Clients

XML Web services are a convenient way to access services over the Internet. The Internet itself can introduce some uncertainties in calling your XML Web services, however. The latencies involved in transiting data from point A to point B on the Internet change on an hourly basis, if not second to second. You don't want to have your application block or appear to be sluggish because you are retrieving information from a Web service over the Internet. The solution is to call the Web service in an asynchronous fashion. This enables you to fire off the request to a Web service and then continue doing other work. When the Web service request returns, you can retrieve the data and display it to the user .

Asynchronous access is more useful in a Windows form type of application where you can go ahead and make the form available to the user immediately. When the data becomes available, just update it in the already displayed form. The Web service proxy again does the majority of the heavy lifting . In addition to creating mirrors of all the Web methods for the Web service, it creates a Begin<methodname> and End<methodname> method for each Web method.

In the proxy for the SimpleDataSet Web service shown in Listing 6.13, you will see, in addition to the Simple() method, a BeginSimple and EndSimple method. These are already set up to work with the IAsyncResult interface. When the Begin method is called, it expects to be passed, in addition to any arguments the Web method requires, the address of a callback method. A callback method is just a method that is called when the operation completes. Optionally, you can stick any object into the AsyncState parameter and retrieve it later in the callback. This is useful to get a handle on the Web service so that you don't have to store a reference to it in a global variable. You will need this reference to call the End method so that you can retrieve the results from the Web service. Listing 6.16 shows a Web form that calls a new Web service, NorthwindOrder, that utilizes this methodology.

Listing 6.16 A Windows Form That Calls the New NorthwindOrder Web Service Asynchronously
 using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data; namespace NorthwindFormsClient {     /// <summary>     /// Summary description for Form1.     /// </summary>     public class Form1 : System.Windows.Forms.Form     {         public delegate void SetData(IAsyncResult ar);         private System.Windows.Forms.DataGrid dataGrid1;         /// <summary>         /// Required designer variable.         /// </summary>         private System.ComponentModel.Container components = null;         public Form1()         {             //             // Required for Windows Form Designer support             //             InitializeComponent();             //             // TODO: Add any constructor code after InitializeComponent call             //         }         /// <summary>         /// Clean up any resources being used.         /// </summary>         protected override void Dispose( bool disposing )         {             if( disposing )             {                 if (components != null)                 {                     components.Dispose();                 }             }             base.Dispose( disposing );         }         #region Windows Form Designer generated code         /// <summary>         /// Required method for Designer support - do not modify         /// the contents of this method with the code editor.         /// </summary>         private void InitializeComponent()         {             this.dataGrid1 = new System.Windows.Forms.DataGrid();             ((System.ComponentModel.ISupportInitialize)(this.dataGrid1)). BeginInit();             this.SuspendLayout();             //             // dataGrid1             //             this.dataGrid1.DataMember = "";             this.dataGrid1.Dock = System.Windows.Forms.DockStyle.Fill;             this.dataGrid1.HeaderForeColor = System.Drawing.SystemColors.\ ControlText;             this.dataGrid1.Name = "dataGrid1";             this.dataGrid1.Size = new System.Drawing.Size(552, 429);             this.dataGrid1.TabIndex = 0;             //             // Form1             //             this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);             this.ClientSize = new System.Drawing.Size(552, 429);             this.Controls.AddRange(new System.Windows.Forms.Control[] {                                                                           this. dataGrid1});             this.Name = "Form1";             this.Text = "Form1";             this.Load += new System.EventHandler(this.Form1_Load);             ((System.ComponentModel.ISupportInitialize)(this.dataGrid1)).EndInit();             this.ResumeLayout(false);         }         #endregion         /// <summary>         /// The main entry point for the application.         /// </summary>         [STAThread]         static void Main()         {             Application.Run(new Form1());         }         private void Form1_Load(object sender, System.EventArgs e)         {             localhost.Orders oOrders = new localhost.Orders();             // Create the callback to pass to the asynchronous invocation             AsyncCallback wscb = new AsyncCallback(this.WebServiceCallback);             //  Call the web method asynchronously passing in the callback and the service itself             oOrders.BeginGetAllOrders(wscb, oOrders);         }         public void WebServiceCallback(IAsyncResult ar)         {             // When this callback executes we are on a different thread than the grid             // Windows Forms is single threaded so we need to call invoke to cross threads             SetData dlg = new SetData(SetDataInGrid);             dataGrid1.Invoke(dlg, new Object[] {ar});         }         public void SetDataInGrid(IAsyncResult ar)         {             localhost.Orders oOrders;             // Grab the web service out of the async result object AsyncState property             oOrders = (localhost.Orders)ar.AsyncState;             // Get the data out of the finished web service             DataSet ds = oOrders.EndGetAllOrders(ar);             // Put the data into the grid             dataGrid1.DataMember = "Orders";             dataGrid1.DataSource = ds;         }     } } 

Don't get confused by the invoke in WebServiceCallback. Windows forms are single threaded by nature. When the callback from the Web service fires, you are not on the thread that created the control. If you attempt to set the DataSource property while on the wrong thread, you can cause undesirable results, including your program hanging. The invoke is used to transfer control to the thread that created the datagrid and then load the data on that thread.

Asynchronous calls are harder in a Web page than in a Windows form. After a Web page has been sent back to the browser, there is no way to update information in it further. Asynchronous calls are still of limited use in a Web page, however. If you have several Web service calls to make to create a page, fire them all off in an asynchronous fashion at the start of page processing and then continue doing other work in the page ”perhaps retrieving information from a database, performing calculations, or doing anything else required to build the page.

This brings us to the other ways of calling a Web service asynchronously. It is possible to call the Web method using Begin but without specifying a callback method. You can then continue with other processing. When you need the data from the Web service, you have two options:

  1. Loop while looking at the IsCompleted property of the AsyncResult object. If all you are doing in the loop is checking the IsCompleted property, this is not the most efficient technique. It has the disadvantage of chewing up CPU cycles that other processes could be using. It has the advantage, however, of letting you do other work while waiting for the Web service to finish its work.

  2. Utilize the AsyncWaitHandle of the AsyncResult object to cause the thread to wait until the Web service signals completion. This doesn't spin the CPU, wasting needless processing cycles. eeYou can specify a timeout for the wait and then check the IsCompleted property to see if a timeout has occurred. The disadvantage of this, however, is that your code can't be off doing other processing while waiting for the call to return.

Listing 6.17 shows an example of a Web form calling the NorthwindOrders Web service asynchronously.

Listing 6.17 A Web Form That Calls the NorthwindOrders Service Asynchronously and Loads the Orders into a Grid
 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 NorthwindWebClient {     /// <summary>     /// Summary description for WebForm1.     /// </summary>     public class WebForm1 : System.Web.UI.Page     {         protected System.Web.UI.WebControls.DataGrid DataGrid1;         private void Page_Load(object sender, System.EventArgs e)         {             IAsyncResult ar;             localhost.Orders oOrders = new localhost.Orders();             // Start the web service call             ar = oOrders.BeginGetAllOrders(null, null);             // Do other work....             // All done so wait for the web service to come back             // This waitone waits for 20 seconds and then continues             ar.AsyncWaitHandle.WaitOne(20000, false);             // Check to see if the async call completed.             // If not write a timeout message             if(!ar.IsCompleted)                 Response.Write("Timed out");             else             {                 // Data is ready so put it into the grid                 DataGrid1.DataMember = "Orders";                 DataGrid1.DataSource = oOrders.EndGetAllOrders(ar);                 DataGrid1.DataBind();             }         }         #region Web Form Designer generated code         override protected void OnInit(EventArgs e)         {             //             // CODEGEN: This call is required by the ASP.NET Web Form Designer.             //             InitializeComponent();             base.OnInit(e);         }         /// <summary>         /// Required method for Designer support - do not modify         /// the contents of this method with the code editor.         /// </summary>         private void InitializeComponent()         {             this.Load += new System.EventHandler(this.Page_Load);         }         #endregion     } } 

This code fires off the asynchronous Web method right at the beginning of page load. It then continues to do other processing. Just before rendering the page back to the user, it waits for the results from the WebMethod for 20 seconds. If the Web method completes sooner, WaitOne exits as soon as the method completes. This means that WaitOne will wait at most 20 seconds but may wait for as few as 0 seconds.

Cookies and Proxies

By default, the proxies created by WSDL or Visual Studio .NET do not interact with cookies. This means that even though you may turn on Session state in the Web service, unless you take a few extra steps on the client, you will never get persistent Session state.

SoapHttpClientProtocol has a CookieContainer property, which is intended to hold a reference to the cookie container class that can be used to maintain cookie information across invocations of Web methods. By default, this property is empty. It is quite easy, however, to create a new cookie container and put a reference to it into the property. Either the Web service reference or the cookie container must persist across invocations, most likely as a member of your top-level class for this to work. Listing 6.18 shows an example of a Windows form that creates a cookie container and puts it into the Web proxy. It utilizes the state Web service that we created back in Listing 6.5.

Listing 6.18 A Windows Form That Creates a Cookie Container and Utilizes the State Web Service
 using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data; namespace StateClient {     /// <summary>     /// Summary description for Form1.     /// </summary>     public class Form1 : System.Windows.Forms.Form     {         internal System.Windows.Forms.Button btnGet;         internal System.Windows.Forms.Label lblGetValueText;         internal System.Windows.Forms.Label lblGetValue;         internal System.Windows.Forms.TextBox txtGetKey;         internal System.Windows.Forms.Label lblGetKey;         internal System.Windows.Forms.Button btnSet;         internal System.Windows.Forms.TextBox txtSetValue;         internal System.Windows.Forms.TextBox txtSetKey;         internal System.Windows.Forms.Label lblSetValue;         internal System.Windows.Forms.Label lblSetKey;         /// <summary>         /// Required designer variable.         /// </summary>         private System.ComponentModel.Container components = null;         localhost.State ss = new localhost.State();         public Form1()         {             //             // Required for Windows Form Designer support             //             InitializeComponent();             // Initialize the cookie container and set it so we can             // maintain state             ss.CookieContainer = new System.Net.CookieContainer();         }         /// <summary>         /// Clean up any resources being used.         /// </summary>         protected override void Dispose( bool disposing )         {             if( disposing )             {                 if (components != null)                 {                     components.Dispose();                 }             }             base.Dispose( disposing );         }         #region Windows Form Designer generated code         /// <summary>         /// Required method for Designer support - do not modify         /// the contents of this method with the code editor.         /// </summary>         private void InitializeComponent()         {             this.btnGet = new System.Windows.Forms.Button();             this.lblGetValueText = new System.Windows.Forms.Label();             this.lblGetValue = new System.Windows.Forms.Label();             this.txtGetKey = new System.Windows.Forms.TextBox();             this.lblGetKey = new System.Windows.Forms.Label();             this.btnSet = new System.Windows.Forms.Button();             this.txtSetValue = new System.Windows.Forms.TextBox();             this.txtSetKey = new System.Windows.Forms.TextBox();             this.lblSetValue = new System.Windows.Forms.Label();             this.lblSetKey = new System.Windows.Forms.Label();             this.SuspendLayout();             //             // btnGet             //             this.btnGet.Location = new System.Drawing.Point(128, 112);             this.btnGet.Name = "btnGet";             this.btnGet.TabIndex = 19;             this.btnGet.Text = "Get";             this.btnGet.Click += new System.EventHandler(this.btnGet_Click);             //             // lblGetValueText             //             this.lblGetValueText.Location = new System.Drawing.Point(16, 168);             this.lblGetValueText.Name = "lblGetValueText";             this.lblGetValueText.Size = new System.Drawing.Size(100, 16);             this.lblGetValueText.TabIndex = 18;             //             // lblGetValue             //             this.lblGetValue.Location = new System.Drawing.Point(16, 152);             this.lblGetValue.Name = "lblGetValue";             this.lblGetValue.Size = new System.Drawing.Size(88, 16);             this.lblGetValue.TabIndex = 17;             this.lblGetValue.Text = "Value:";             //             // txtGetKey             //             this.txtGetKey.Location = new System.Drawing.Point(16, 128);             this.txtGetKey.Name = "txtGetKey";             this.txtGetKey.TabIndex = 16;             this.txtGetKey.Text = "Key";             //             // lblGetKey             //             this.lblGetKey.Location = new System.Drawing.Point(16, 112);             this.lblGetKey.Name = "lblGetKey";             this.lblGetKey.Size = new System.Drawing.Size(72, 16);             this.lblGetKey.TabIndex = 15;             this.lblGetKey.Text = "Key:";             //             // btnSet             //             this.btnSet.Location = new System.Drawing.Point(128, 16);             this.btnSet.Name = "btnSet";             this.btnSet.TabIndex = 14;             this.btnSet.Text = "Set";             this.btnSet.Click += new System.EventHandler(this.btnSet_Click);             //             // txtSetValue             //             this.txtSetValue.Location = new System.Drawing.Point(16, 72);             this.txtSetValue.Name = "txtSetValue";             this.txtSetValue.TabIndex = 13;             this.txtSetValue.Text = "Value";             //             // txtSetKey             //             this.txtSetKey.Location = new System.Drawing.Point(16, 32);             this.txtSetKey.Name = "txtSetKey";             this.txtSetKey.TabIndex = 11;             this.txtSetKey.Text = "Key";             //             // lblSetValue             //             this.lblSetValue.Location = new System.Drawing.Point(16, 56);             this.lblSetValue.Name = "lblSetValue";             this.lblSetValue.Size = new System.Drawing.Size(88, 16);             this.lblSetValue.TabIndex = 12;             this.lblSetValue.Text = "Value:";             //             // lblSetKey             //             this.lblSetKey.Location = new System.Drawing.Point(16, 16);             this.lblSetKey.Name = "lblSetKey";             this.lblSetKey.Size = new System.Drawing.Size(72, 16);             this.lblSetKey.TabIndex = 10;             this.lblSetKey.Text = "Key:";             //             // Form1             //             this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);             this.ClientSize = new System.Drawing.Size(216, 189);             this.Controls.AddRange(new System.Windows.Forms.Control[] {                                                                           this. btnGet,                                                                           this. lblGetValueText,                                                                           this. lblGetValue,                                                                           this. txtGetKey,                                                                           this. lblGetKey,                                                                           this. btnSet,                                                                           this. txtSetValue,                                                                           this. txtSetKey,                                                                           this. lblSetValue,                                                                           this. lblSetKey});             this.Name = "Form1";             this.Text = "Form1";             this.ResumeLayout(false);         }         #endregion         /// <summary>         /// The main entry point for the application.         /// </summary>         [STAThread]         static void Main()         {             Application.Run(new Form1());         }         private void btnSet_Click(object sender, System.EventArgs e)         {             // Set the value             ss.SetValue(this.txtSetKey.Text, this.txtSetValue.Text);         }         private void btnGet_Click(object sender, System.EventArgs e)         {             // Get the value             this.lblGetValueText.Text = ss.GetValue(this.txtGetKey.Text);         }     } } 

In this form, the Web service is a member variable of Form1. It persists for the life of the form. On form load, a cookie container is created and associated with the instance of the Web service. This enables Session state to work across each of the Web service method calls.

for RuBoard


C# Developer[ap]s Guide to ASP. NET, XML, and ADO. NET
C# Developer[ap]s Guide to ASP. NET, XML, and ADO. NET
ISBN: 672321556
EAN: N/A
Year: 2005
Pages: 103

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