In this chapter, you will learn how to:
Enable client sessions
Store and retrieve data on a per-client basis
Store and retrieve data on an application basis
Earlier in this book, we described the relationship between ASP.NET and XML Web services and explained that ASP.NET provides some key services that simplify the development of more complex XML Web service projects. In this chapter, we will examine ASP.NET support for state management.
By default, XML Web services created in the Microsoft .NET Framework are stateless; the service handles every client request in isolation and does not share data between requests, even those from the same client. This has not affected the design of the examples in previous chapters because we were able to treat each credit card validation request independently. We did not need to share data between client requests to validate credit card numbers.
By contrast, stateful XML Web services store data while processing a request and can use the data when processing future requests. ASP.NET provides two types of state management.
Client state, in which data about a particular client request is stored and used to affect the processing of future requests from that client.
Application state, which is not client specific. Data from any request (regardless of the client) is stored and used to affect the processing of any future request.
The network protocol used for communication between clients and XML Web services is stateless, meaning that not all of the requests from the client will be made using the same HTTP connection. ASP.NET provides a mechanism to identify clients when requests are made using several HTTP connections and to allow a programmer to store data that is unique to each identified client. These requests are grouped together as a session. ASP.NET does not create client sessions by default. You must use the EnableSession property of the WebMethod attribute to indicate which methods of the XML Web service class require client state. The following code fragments illustrate how this is done.
When a client first makes a request to an XML Web service, ASP.NET creates a new session for the client and adds a cookie to the XML Web service response. For our purposes, a cookie is simply a piece of text that contains an identifier for the client. The client includes the cookie in any subsequent requests to the same XML Web service, enabling ASP.NET to uniquely identify the client and associate requests together; however, sessions are created only when client state is enabled via the EnableSession property of the WebMethod attribute.
When Microsoft Visual Studio .NET creates a new XML Web service project, the main service class is automatically derived from the System.Web.Services.WebService class. This base class provides you with access to client sessions via the WebService.Session property, which returns an instance of the HttpSessionState class. The HttpSessionState class (one of the .NET collection classes) can store name/value pairs that can be retrieved when the client makes subsequent requests.
The XML Web service that we will develop to demonstrate client sessions keeps a record of the number of validation requests that a client sends to the service and the number of those requests that fail. We could not keep track of this information without client state, because we need to create data and maintain access to it over multiple client requests.
The XML Web service is based on the XML Web service example from the section "Using Custom Fault Codes" in Chapter 7. We will define a new data type to represent the client request statistics.
Procedure 10-1. Create the Project
Open the project that you created in Chapter 7. The URL for that project should be http://localhost/XMLWebServices/Chapter07/CustomFaultCodes/ValidatorService.
Select Copy Project from the Project menu, and then copy the project to http://localhost/XMLWebServices/Chapter10/StateManagement/ValidatorService.
Open the new project in Visual Studio .NET, and then save the solution file for the new project.
Procedure 10-2. Create the New Data Type
In Solution Explorer, right-click on the ValidatorService project item (highlighted in bold) and select Add followed by Add Class from the shortcut menu. Type ValidationState into the Name text box, and then click Open.
This step creates a new Microsoft Visual Basic .NET or C# class file; an entry will appear in Solution Explorer, named ValidationState.cs or ValidationState.vb depending on the language you are using.
Right-click on the ValidationState.cs or ValidationState.vb file in Solution Explorer, and then select View Code from the shortcut menu.
Delete all of the code in the editor window, and replace it with the following code.
This code defines the ClientStats class, which we will use to track the total number of requests made by a client and how many of those requests were for invalid card numbers.
Procedure 10-3. Update the XML Web Service Class
In Solution Explorer, right-click on the Validation.asmx file and select View Code from the shortcut menu.
This opens the code-behind file (either Validation.asmx.cs or Validation.asmx.vb depending on the language you are using).
Add the following statements to the code file to define the GetClientStatistics method.
This method demonstrates the basic functionality of the Session object, which is to store name/value pairs for each client. The first line of the method body attempts to retrieve the ClientStats object for the client that has invoked this method and creates one if needed.
The first line highlighted in bold demonstrates how to retrieve a name/value pair from the Session object; the second bold statement shows how to add a new name/value pair. (If you have used the classes from the System.Collections namespace, you will notice that adding data to and retrieving data from the Session object is similar to the way that the Hashtable collection class is used.) Notice that we do not have to worry about which client we are dealing with. ASP.NET automatically ensures that the Session object is working with the correct set of data. We store an instance of the ClientStats class, using the name clientstats.
Example 10-5. C#
[WebMethod(EnableSession=true)] public ClientStats GetClientStatistics() { ClientStats x_stats = (ClientStats)Session["clientstats"]; if (x_stats == null) { // we need to create a new ClientStats object for this // session; typically because this is the first request // that the client has made and there is no prior state // information available in the session. x_stats = new ClientStats(); Session["clientstats"] = x_stats; } return x_stats; }
Example 10-6. Visual Basic .NET
<WebMethod(EnableSession:=True)> _ Public Function GetClientStatistics() As ClientStats Dim x_stats As ClientStats If Session("clientstats") Is Nothing Then ’ we need to create a new ClientStats object for this ’ session; typically because this is the first request ’ that the client has made and there is no prior state ’ information available in the session. x_stats = New ClientStats() Session("clientstats") = x_stats Else x_stats = CType(Session("clientstats"), ClientStats) End If Return x_stats End Function
Replace the existing ValidateCard method with the following code.
The differences between this method and the version in the example from Chapter 7 are shown in boldface. Notice that we have modified the WebMethod attribute declaration to enable client sessions. The other changes to the ValidateCard method update the running statistics using the ClientStats class that we defined in the previous section. We have encapsulated all of the statements that deal with the Session object in the method that we created in the previous step; the modifications to the ValidateCard method ensure that the statistics are maintained for the client. We have added the finally clause to the try statement to ensure that we record requests that result in an exception being thrown by the CreditCardValidator.dll library. Otherwise, the ValidateCard method would return as soon as the SoapException was thrown, and we would not be able to update our statistics correctly.
Example 10-7. C#
[WebMethod(EnableSession=true)] public void ValidateCard(ref ValidationObject p_object) { // define a boolean to hold the result // of the validation request. bool x_result = false; // define a boolean to indicate if the // validation request resulted in an // exception being thrown by the // CreditCardValidator.dll library bool x_error = false; try { // create the validator instance that we will // use to check the card number Validator x_validator = new Validator(); // use the type of card supplied in the // validation object to determine which // library method we should call in order // to perform the validation. switch (p_object.o_card_type) { case CARD_TYPE.AMEX: // the client has requested that we validate // an AMEX card number x_result = x_validator.ValidateAMEX( p_object.o_card_number); break; case CARD_TYPE.MASTERCARD: // the client has requested that we validate // an MasterCard card number x_result = x_validator.ValidateMasterCard( p_object.o_card_number); break; case CARD_TYPE.VISA: // the client has requested that we validate // an VISAcard number x_result = x_validator.ValidateVisa( p_object.o_card_number); break; default: // the method should not reach this point; if it // does, it is because the client has specified // a value which is not contained in the CARD_TYPE // enumeration. Should this happen, the client has // requested that we validate a card type that we // do not support. x_result = false; break; } } catch (ApplicationException x_ex) { // update the variable to indicate // that an exception has been thrown by // CreditCardValidator.dll library x_error = true; // return a soap exception with a custom fault // code based on the type of the application // exception throw GetException(x_ex); } finally { // get the status object for this client ClientStats x_stats = GetClientStatistics(); // increment the counter for the total // number of requests x_stats.o_total_requests++; // if the result was not true, or if an // exception was thrown, then update the // failed request counter if (x_error || !x_result) { x_stats.o_failed_validations++; } // set the result status in the validation object p_object.o_valid = x_result; } }
Example 10-8. Visual Basic .NET
<WebMethod(EnableSession:=True)> _ Public Sub ValidateCard(ByRef p_object As ValidationObject) ’ define a boolean to hold the result ’ of the validation request Dim x_result As Boolean ’ define a boolean to indicate if the ’ validation request resulted in an ’ exception being thrown by the ’ CreditCardValidator.dll library Dim x_error As Boolean = False Try ’ create the validator instance that we will ’ use to check the card number Dim x_validator As Validator = New Validator() ’ use the type of card supplied in the ’ validation object to determine which ’ library method we should call in order ’ to perform the validation. Select Case p_object.o_card_type Case CARD_TYPE.AMEX ’ the client has requested that we validate ’ an AMEX card number x_result = x_validator.ValidateAMEX( _ p_object.o_card_number) Case CARD_TYPE.MASTERCARD ’ the client has requested that we validate ’ an MasterCard card number x_result = x_validator.ValidateMasterCard( _ p_object.o_card_number) Case CARD_TYPE.VISA ’ the client has requested that we validate ’ an VISAcard number x_result = x_validator.ValidateVisa( _ p_object.o_card_number) Case Else ’ the method should not reach this point; if it ’ does, it is because the client has specified ’ a value which is not contained in the CARD_TYPE ’ enumeration. Should this happen, the client has ’ requested that we validate a card type that we ’ do not support. x_result = False End Select Catch x_ex As ApplicationException ’ update the variable to indicate ’ that an exception has been thrown by ’ CreditCardValidator.dll library x_error = True ’ return a soap exception with a custom fault ’ code based on the type of the application ’ exception Throw GetException(x_ex) Finally ’ get the status object for this client Dim x_stats As ClientStats = GetClientStatistics() ’ increment the counter for the total ’ number of requests x_stats.o_total_requests = x_stats.o_total_requests + 1 ’ if the result was not true, or if an ’ exception was thrown, then update the ’ failed request counter If x_error Or Not x_result Then x_stats.o_failed_validations _ = x_stats.o_failed_validations + 1 End If ’ set the result status in the validation object p_object.o_valid = x_result End Try End Sub
Build the project by selecting Build Solution from the Build menu or pressing Ctrl+Shift+B.
By default, support for cookies is disabled in the XML Web service proxy class that is created by Visual Studio .NET. This means that the proxy class will not send requests that include the unique identifier assigned to the client by ASP.NET. To enable cookie support (and therefore client session state), the CookieContainer property of the proxy class must be set to a new instance of the System.Net.CookieContainer class. The identifier assigned by ASP.NET is only valid for one instance of the proxy class. ASP.NET will identify a new client each time a new proxy class is created and the CookieContainer property is set.
In this section, we will build a Windows Forms client that makes use of the GetClientStatistics Web method that we created in the example from the previous section. Unlike the clients we created in earlier chapters, the ValidatorService proxy class we create in this chapter will be an instance variable, meaning that a single instance of the class will be used to send all requests to the XML Web service. Previously, we created a new proxy class for each request. By defining the proxy as an instance variable and setting the CookieContainer property when it is created, all of the requests the client sends to the XML Web service will use the same client identifier and be considered a single session by the XML Web service.
Procedure 10-4. Create the Windows Form
Copy the client template project to C:XMLWebServicesSBSProjectsChapter10StateManagement as described in the sidebar "XML Web Service Client Projects" in Chapter 7. Change the Size property of Form1 to 288, 272.
Add the following controls to Form1, and configure their properties as specified in the table:
Control | Property | Value |
---|---|---|
Label | Text | Total Requests Made: |
TextAlign | MiddleRight | |
Location | 40, 168 | |
Size | 120, 23 | |
Label | Text | Delete the contents of the Text property value. |
TextAlign | MiddleLeft | |
Name | TotalRequests | |
Location | 176, 168 | |
Size | 96, 23 | |
Label | Text | Total Invalid Card Numbers: |
TextAlign | MiddleRight | |
Location | 8, 200 | |
Size | 152, 23 | |
Label | Text | Delete the contents of the Text property value. |
TextAlign | MiddleLeft | |
Name | TotalInvalid | |
Location | 176, 200 | |
Size | 96, 23 |
If you have added the controls correctly, the form should look like this:
Procedure 10-5. Add the Web Reference
Add a Web reference to the ValidatorService XML Web service that we created earlier in the chapter. The URL for the ValidatorService service is http://localhost/XMLWebServices/Chapter10/StateManagement/ValidatorService/Validation.asmx . (For details about adding a Web reference, see the section "Creating a Web Reference" in Chapter 4.)
In Solution Explorer, right-click the Web reference and select Rename from the shortcut menu. Rename the Web reference Validator.
Procedure 10-6. Edit the Code File
Double-click on the Validate button in the Form1 design view so that you can add the code that will be executed when the user clicks the button.
Add the following code to complete the ValidateButton_Click method.
The statements responsible for obtaining the statistics from the XML Web service are marked in bold; the ValidateButton_Click method now makes two calls to the XML Web service, one to request the card number validation (via the ValidateCard method) and another to get the ClientStats object (via the GetClientStatistics method).
Example 10-9. C#
private void ValidateButton_Click(object sender, System.EventArgs e) { // create the ValidationObject that we will send to // the XML Web service ValidationObject x_object = new ValidationObject(); // set the card type for the validation object based // on the user selection in the CardType ComboBox switch (CardType.Text) { case "AMEX": x_object.o_card_type = CARD_TYPE.AMEX; break; case "MasterCard": x_object.o_card_type = CARD_TYPE.MASTERCARD; break; case "VISA": x_object.o_card_type = CARD_TYPE.VISA; break; } // set the card number value in the ValidationObject x_object.o_card_number = CardNumber.Text; try { o_service.ValidateCard(ref x_object); // set the text of the result label based // on the response from the XML Web service if (x_object.o_valid) { Result.Text = "Number Valid"; } else { Result.Text = "Number Invalid"; } } catch (System.Web.Services.Protocols.SoapException x_ex) { switch (x_ex.Code.ToString()) { case "Client.IllegalCharacter": Result.Text = "Illegal Character"; break; case "Client.InvalidLength": Result.Text = "Invalid Length"; break; case "Client.InvalidPrefix": Result.Text = "Invalid Prefix"; break; default: Result.Text = "Unexpected Error"; break; } } // get the client statistics from the XML Web service ClientStats x_state = o_service.GetClientStatistics(); TotalRequests.Text = x_state.o_total_requests.ToString(); TotalInvalid.Text = x_state.o_failed_validations.ToString(); }
Example 10-10. Visual Basic .NET
Private Sub ValidateButton_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles ValidateButton.Click ’ create the ValidationObject that we will send to ’ the XML Web service Dim x_object As ValidationObject = New ValidationObject() ’ set the card type for the validation object based ’ on the user selection in the CardType ComboBox Select Case CardType.Text Case "AMEX" x_object.o_card_type = CARD_TYPE.AMEX Case "MasterCard" x_object.o_card_type = CARD_TYPE.MASTERCARD Case "VISA" x_object.o_card_type = CARD_TYPE.VISA End Select ’ set the card number value in the ValidationObject x_object.o_card_number = CardNumber.Text Try o_service.ValidateCard(x_object) ’ set the text of the result label based ’ on the response from the XML Web service If x_object.o_valid Then Result.Text = "Number Valid" Else Result.Text = "Number Invalid" End If Catch x_ex As System.Web.Services.Protocols.SoapException Select Case x_ex.Code.ToString() Case "Client.IllegalCharacter" Result.Text = "Illegal Character" Case "Client.InvalidLength" Result.Text = "Invalid Length" Case "Client.InvalidPrefix" Result.Text = "Invalid Prefix" Case Else Result.Text = "Unexpected Error" End Select End Try ’ get the client statistics from the XML Web service Dim x_state As ClientStats = o_service.GetClientStatistics() TotalRequests.Text = x_state.o_total_requests.ToString() TotalInvalid.Text = x_state.o_failed_validations.ToString() End Sub
Add the following statements to define the ValidatorService proxy class as an instance variable of Form1.
These statements should be inserted immediately after the declaration of the Form1 class. The following excerpt shows the Form1 class declaration; the statements that add the instance variable are marked in bold.
Add the following statements (marked in bold) to the constructor of the Form1 class. These statements initialize the ValidatorService class for use in the ValidateButton_Click method.
Visual Basic .NET programmers will have to expand the region labeled Windows Form Designer generated code in the text editor by clicking on the + sign.
Example 10-13. C#
public Form1() { // // Required for Windows Form Designer support // InitializeComponent(); // create the proxy object o_service = new ValidatorService(); // set the cookie container, so that the proxy object // will be able to correctly use cookie to provide // state information o_service.CookieContainer = new System.Net.CookieContainer(); // get the client statistics from the XML Web service ClientStats x_state = o_service.GetClientStatistics(); TotalRequests.Text = x_state.o_total_requests.ToString(); TotalInvalid.Text = x_state.o_failed_validations.ToString(); }
Example 10-14. Visual Basic .NET
Public Sub New() MyBase.New() ’This call is required by the Windows Form Designer. InitializeComponent() ’Add any initialization after the InitializeComponent() call ’ create the proxy object o_service = New ValidatorService() ’ set the cookie container, so that the proxy object ’ will be able to correctly use cookie to provide ’ state information o_service.CookieContainer = New System.Net.CookieContainer() ’ get the client statistics from the XML Web service Dim x_state As ClientStats = o_service.GetClientStatistics() TotalRequests.Text = x_state.o_total_requests.ToString() TotalInvalid.Text = x_state.o_failed_validations.ToString() End Sub
Build the solution by selecting Build Solution from the Build menu or pressing Ctrl+Shift+B.
Procedure 10-7. Test the XML Web Service
Select Start Without Debugging from the Debug menu (or press Ctrl+F5) to start the client.
Enter the credit card number 4921 8352 2155 2042 into the client, and then click the Validate button.
The client will request that the ValidatorService XML Web service validate the credit card number and then obtain the request statistics, which are displayed at the bottom of the client window, as shown in the following screen shot. Because you have entered a valid card number, the statistics report that you have made one request and that no invalid requests have been sent.
Enter baddata as the card number, and then click the Validate button.
The request statistics will now report a total of two requests, one of which was invalid. Remember that the client does not keep a record of the requests; the statistical record is obtained afresh from the XML Web service each time that the Validate button is clicked.
This example provides a simple demonstration of the facility to store name/value pairs in the Session object and the support provided by ASP.NET to identify clients even when requests are made using multiple network connections. Without this support, our example would not have worked and would have returned a new instance of the ClientStats object for every request. Instead, ASP.NET recognized that the two requests came from the same client and that they therefore should be associated together as part of the same client session.
In the examples in the chapters so far, you’ve created a C# or Visual Basic .NET class that contains methods that are exposed as the methods of an XML Web service. What we have not mentioned up to now is that a new instance of this class is created for each request from a client, even if that client has made requests previously. Creating a new instance for each request provides the benefits of scalability, performance, and security. This fact did not affect the design of the examples in previous chapters because each client request was self-contained; the client requested that a card number be validated and each client request was processed in isolation. Subsequent requests from the same client or from other clients were treated independently and shared no common data.
One effect of this approach is that it prevents you from using variables to maintain data values. No values assigned to variables can be shared between client requests because a new instance of the XML Web service class is created every time a Web method is invoked.
Support for application state is not enabled as with client session state; the Application property is always available for any XML Web service when the .asmx code-behind file is derived from the WebService class, including all XML Web service projects created by Visual Studio .NET. The Application property returns an instance of the HttpApplicationState class, which can be used to store name/value pairs that are accessible during requests from any client.
To demonstrate the features of the Application property, we will extend the XML Web service created earlier, in the section "Using Client Sessions," to maintain a list of the validation requests received by the XML Web service. The list will reflect requests made by all clients of the service. To expose the request history, we will define a new method named GetValidationHistory, which will return a string containing details of each request that has been made, one to a line.
Procedure 10-8. Modify the XML Web Service Class
Open the XML Web service project that you created in the section "Using Client Sessions." The URL for this project should be http://localhost/XMLWebServices/Chapter10/StateManagement/ValidatorService.
In Solution Explorer, right-click on the Validation.asmx file and select View Code from the shortcut menu to open the code-behind file (either Validation.asmx.cs or Validation.asmx.vb, depending on the language you are using).
Add the following statements to the finally clause of the catch statement in the ValidateCard method. The statements that you need to add are marked in bold.
When a client request is processed by the ValidateCard method, we attempt to retrieve an ArrayList through the Application property by using the name ValidationObjects. We use this list to build the validation request history. The ArrayList will not exist for the first request received after IIS loads the XML Web service, so we take care to create it as needed. Once we have the ArrayList, we add the ValidationObject received from the client so that we have a record of the type of card, the card number, and the result indicating the validity of the card number.
Example 10-15. C#
} finally { // get the status object for this client ClientStats x_stats = GetClientStatistics(); // increment the counter for the total // number of requests x_stats.o_total_requests++; // if the result was not true, or if an // exception was thrown, then update the // failed request counter if (x_error || !x_result) { x_stats.o_failed_validations++; } // set the result status in the validation object p_object.o_valid = x_result; // update the array list held in the application // state to reflect the new request ArrayList x_list = (ArrayList)Application["ValidationObjects"]; // check to ensure that we have a list to work with - if the // value returned from the Application object is null, this // is the first request made to the XML Web service method, // and we should create the list for use by future calls if (x_list == null) { x_list = new ArrayList(); Application["ValidationObjects"] = x_list; } x_list.Add(p_object); }
Example 10-16. Visual Basic .NET
Finally ’ get the status object for this client Dim x_stats As ClientStats = GetClientStatistics() ’ increment the counter for the total ’ number of requests x_stats.o_total_requests = x_stats.o_total_requests + 1 ’ if the result was not true, or if an ’ exception was thrown, then update the ’ failed request counter If x_error Or Not x_result Then x_stats.o_failed_validations _ = x_stats.o_failed_validations + 1 End If ’ set the result status in the validation object p_object.o_valid = x_result Dim x_list As ArrayList _ = CType(Application("ValidationObjects"), ArrayList) ’ check to ensure that we have a list to work with - if the ’ value returned from the Application object is null, this ’ is the first request made to the XML Web service method, ’ and we should create the list for use by future calls If x_list Is Nothing Then x_list = New ArrayList() Application("ValidationObjects") = x_list End If ’ update the array list held in the application ’ state to reflect the new request x_list.Add(p_object) End Try
Add the following statements to the code file to define the GetValidationHistory method.
When invoked, this method iterates through the list of ValidationObject instances and uses the StringBuilder class to construct a multiline String that contains the details of one validation request per line.
Example 10-17. C#
[WebMethod] public string GetValidationHistory() { // generate the information to be placed in the cache // create the string builder, which we will use // to construct the response to the client StringBuilder x_builder = new StringBuilder(); // get the array list from the application state object ArrayList x_list = (ArrayList)Application["ValidationObjects"]; // check to ensure that we have a list to work with - if the // value returned from the Application object is null, this // is the first request made to the XML Web service method, // and we should create the list for use by future calls if (x_list == null) { x_list = new ArrayList(); Application["ValidationObjects"] = x_list; } // run through the list and build up the contents // of the StringBuilder to contain one summary line // for each of the validation requests we have processed foreach (ValidationObject x_object in x_list) { x_builder.Append(x_object.o_card_type + " " + x_object.o_card_number + " " + x_object.o_valid + " "); } // update the local reference to the history data so return x_builder.ToString(); }
Example 10-18. Visual Basic .NET
<WebMethod()> _ Public Function GetValidationHistory() As String ’ generate the information to be placed in the cache ’ create the string builder, which we will use ’ to construct the response to the client Dim x_builder As StringBuilder = New StringBuilder() ’ get the array list from the application state object Dim x_list As ArrayList = _ CType(Application("ValidationObjects"), ArrayList) ’ check to ensure that we have a list to work with - if the ’ value returned from the Application object is null, this ’ is the first request made to the XML Web service method, ’ and we should create the list for use by future calls If x_list Is Nothing Then x_list = New ArrayList() Application("ValidationObjects") = x_list End If ’ run through the list and build up the contents ’ of the StringBuilder to contain one summary line ’ for each of the validation requests we have processed Dim x_object As ValidationObject For Each x_object In x_list x_builder.Append(String.Concat(x_object.o_card_type, " ", _ x_object.o_card_number, " ", x_object.o_valid, " ")) Next ’ update the local reference to the history data so Return x_builder.ToString() End Function
Scroll to the top of the Form1 code view, and then add the following statement to import the System.Text namespace. This gives the code access to the StringBuilder class.
Build the solution by selecting Build Solution from the Build menu or pressing Ctrl+Shift+B.
We can use the client we built in the section "Consuming an XML Web Service That Uses Client State" to make validation requests of the XML Web service, but we need a different client to obtain and display the history of those requests. In this section, we will create a new Web Forms application that will show the list of requests.
Once we have the WebFormsClient project structure in place, we’ll need to create the user interface. We’ll build a simple interface with a text box to display the request history and a button whose Click event will cause the history to be obtained from the XML Web service. Don’t worry about getting the size and position of the components exact; just be sure that the result looks something like WebForm1 shown here:
Procedure 10-9. Create the Project
Create a Visual Studio .NET project using the C# or Visual Basic .NET ASP.NET Web Application template. Use the URL http://localhost/XMLWebServices/Chapter10/StateManagement/WebFormsClient for this example.
Add a Web reference to the ValidatorService XML Web service that we created in the previous section. The URL for the ValidatorService service is http://localhost/XMLWebServices/Chapter10/StateManagement/ValidatorService/Validation.asmx .
Rename the Web reference Validator.
Procedure 10-10. Create the Web Form
Double-click the WebForm1.aspx entry in Solution Explorer to open WebForm1 in design view.
Press F4 to open the property page for the WebForm1 DOCUMENT element.
Change the Title property of DOCUMENT to Validation History Client.
Add the Web controls listed in the following table to WebForm1, and configure their properties with the values specified.
Control | Property | Value |
---|---|---|
TextBox | ReadOnly | True |
Rows | 20 | |
TextMode | MultiLine | |
Height | 192px | |
Width | 406px | |
ID | HistoryTextBox | |
Button | Text | Get History |
Height | 29px | |
Width | 141px | |
ID | HistoryButton |
Procedure 10-11. Implement the WebFormsClient Functionality
In the WebForm1 design view, double-click on the Get History button.
Visual Studio .NET switches WebForm1 to code view and displays an empty method named HistoryButton_Click. Changing this method allows us to control what happens when the user clicks the Get History button.
Add the following code to the method.
When the button is clicked, the statement you’ll add to the HistoryButton_Click method will request the history string from the XML Web service and display it in the text box. Notice that we replace any existing text with the new history String; the entire request history is returned from the XML Web service each time the GetValidationHistory method is invoked.
Scroll to the top of the WebForm1 code view, and then add the following statement to import the namespace of the proxy class.
Press Ctrl+Shift+B, or select Build Solution from the Build menu to build the solution.
We now have three components: an XML Web service that maintains a history of client validation requests, a Windows Forms client that makes the validation requests, and a Web Forms client that uses the new GetValidationHistory Web method to obtain a list of the requests made by all clients. We will now generate a small number of validation requests and use the Web Forms client to display the list.
Procedure 10-12. Generate the Validation Requests
Start the client application.
Using Windows Explorer, execute the Windows Forms client application we created earlier in this chapter. C# programmers can find the file at C:XMLWebServicesSBSProjectsChapter10StateManagement WindowsFormsClientindebugWindowsFormsClient.exe. Visual Basic .NET programmers will find the file at C:XMLWebServicesSBSProjectsChapter10 StateManagementWindowsFormsClientinWindowsFormsClient.exe.
Check that the VISA item is selected as the card type, and then enter the number 4921 8352 2155 2042 as the card number.
Click the Validate button.
Select the AMEX item as the card type, and then enter baddata as the card number.
Click the Validate Button.
Select the MasterCard item as the card type, and enter 1234 as the card number.
Click the Validate Button.
Procedure 10-13. View the Validation Request History
Press F5; Visual Studio .NET launches Microsoft Internet Explorer and loads the WebFormsClient page.
Click the Get History button.
As you can see in the following, the text box displays a list of the card types and numbers that we entered above, as well as a Boolean representing the validity of the card number. Depending on what operating system you are running, your display might look slightly different.
To | Do This |
---|---|
Enable client sessions | Apply the following attribute declaration to the methods of your XML Web service class. If you are using C#, the declaration is |
Store or retrieve name/value pairs that are private to each client | Use the Session property of the WebService class. |
Enable application state | Application state is always enabled. |
Store or retrieve name/value pairs that are shared between all clients | Use the Application property of the WebService class. |
3.145.172.146