C# Developeramp;#039;s Guide to ASP.NET, XML, and ADO.NET [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

C# Developeramp;#039;s Guide to ASP.NET, XML, and ADO.NET [Electronic resources] - نسخه متنی

Jeffrey P. McManus; Chris Kinsman

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید









Consuming Web Services



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 servicehence 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.




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 pageperhaps 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:




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.




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 proxiesListing 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.



/ 106