Recipe 3.3 Submitting a Form to a Different Page

     

3.3.1 Problem

You need to submit the information on one page ”a form, for example ”to another. You might want to do this in order to use one page to collect form data and a second page to process it.

The ASP.NET model does not "normally" support submitting a form to any page other than itself. If you are willing to revert to the classic ASP model by removing the runat ="server " attribute from the form element, the page can be submitted to any other page in the same manner, as was done in ASP pages. We don't recommend this approach, however, because it does not take advantage of the built-in functionality provided by the server controls to automatically recreate the controls and populate them with the data submitted with the form, making your coding tasks much harder.


3.3.2 Solution

There are two ways to solve this problem:

  • Use the Server.Transfer method in a button click event handler in the code-behind of the first page to transfer control to a second page, after saving the contents of the first in session scope. Example 3-7 through Example 3-12 show the .aspx and code-behind files for the application that implements this solution.

  • Use the Server.Transfer method in a button click event handler in the code-behind of the first page to transfer control, along with the form contents in the viewstate , to the second page. This approach is described at the end of Recipe 3.2.3 and includes some give-and-take about why one approach might be favored over the other, since neither is entirely perfect.

3.3.3 Discussion

The first solution uses the Server.Transfer method to transfer control to a second page when a button click event handler executes in the code-behind of the first page. As with all the recipes in this chapter, this solution is most easily explained in the context of an example. Before we delve into the example, though, it's useful to relate what happens in ASP.NET when a form is submitted to itself and how the results of that submittal can be used to solve the problem at hand.

The code-behind class for an ASP.NET page is a class that derives from System.Web.UI.Page . This class encapsulates all data and server-side functionality for the page. When a form is submitted to itself, ASP.NET instantiates the page class with the data the user has submitted ”that is, ASP.NET uses the data from the form submittal to repopulate the controls to their former state. This object can then be passed to any page, object, or method that has a need for the data.

In order to store the Page class instance representing the first page to session state and retrieve it in the second page, nothing special needs to be done to the .aspx file that collects the form data. In the following example, the form is a simple one that contains three text fields to capture the user's first name, last name , and age, and a button to submit the data to the server.

In the code-behind of the page that collects the form data, the data members that are to be accessible to the processing page must have their accessibility set to public . Normally, the accessibility would be set to protected ; however, protected members are accessible only by the object itself and other objects that derive from the parent class. In this solution, the second page instantiates a class of type CH03SubmitToAnother_FirstPageVB1 (the class of the first page) rather than deriving from it.

A publicly accessible constant, SES_SUBMITTED_DATA , is provided to name the variable stored in session scope to avoid the problem with "magic values" and improve the maintainability of the code. Magic values are literals that have special significance in a system. As a general rule, you should replace magic values with named constants in order to prevent inadvertently varying them somewhere in your code. And when the same magic values appear in many different classes, they should be treated as global constants in your application rather than declaring them repeatedly in each class.

In the click event handler you write for the Submit button, the page object is placed in session scope to provide access to the data by the page that will process the data. This is done by calling the Add method of the Session object and passing it the name of the session-scoped variable (which is defined by the constant SES_SUBMITTED_DATA ) and a reference to the current page (represented by the Me keyword in VB.NET and this in C#).

Control is then transferred to the page that will process the form data by calling the Transfer method of the Server class and providing it the URL of the page to which control is to be transferred.

The second parameter for the Server.Transfer method must be set to False in this example to avoid sending the form data in the viewstate to the processing page. See the alternate example for an approach to using the viewstate to pass the information to the processing form.


The .aspx file for the page that processes the form data is nothing special. In this example, it simply has three labels used to display the data from the submitted form. We use Label controls in our example to demonstrate that the two pages can be quite different.

The code-behind for the form data processing page is also quite simple. First, the page object previously stored in session scope is recovered. The session variable is then destroyed to recover the system resources used to store the data by setting it equal to Nothing (in VB) or null (in C#).

The text for the labels on the form processing the data is then set to the values from the previous page. Our example simply displays the values. A real-world example might store the data in a database and would require additional code to handle the data access.

A drawback to the technique of placing the page object in session scope is that it can consume a significant amount of server resources if there are a large number of users on the system and/or the page object is large.


A second approach to submitting a form to another page for processing is to pass the information in the forms collection from the page where the data is entered to the processing page. The forms collection contains all of the data entered on the first page along with any hidden fields, including the viewstate , of the first page. This approach is similar to the classic ASP approach of posting to another page and may be desirable if the project requirements dictate that session scope will not be used for any data storage.

The .aspx file for the sending and receiving forms must be modified to disable the "machine authentication check" that is normally performed on the viewstate . By default, ASP.NET adds an encrypted value to the viewstate that is unique to the machine serving the page and the page itself. This allows ASP.NET to verify that the viewstate has not been tampered with by the client. The "machine authentication check" is disabled by setting the EnableViewStateMac attribute in the Page directive to false , as shown here:

 <%@ Page language="c#" AutoEventWireup="false" Codebehind="FormSubmitToAnother_FirstPageCS2.aspx.cs" Inherits="ASPNetCookbook.CSExamples.FormSubmitToAnother_FirstPageCS2"  EnableViewStateMac="False"  %> 

There is a significant drawback to using this approach. By disabling the "machine authentication check," the page submitted back to the server can be altered by the client, resulting in page errors or access to data the client is not authorized to view. You'll have to gauge whether this drawback outweighs the drawback of the previous technique ”neither approach is perfect.


In the code-behind for the page that collects the data, the code in the click event for the button is changed to simply transfer control to the processing page with the second parameter of the Server.Transfer method set to True . This preserves the form data from the first page and passes it to the second page for processing.

 
figs/vbicon.gif
 Private Sub btnSubmit_Click(ByVal sender As Object, _ ByVal e As System.Web.UI.ImageClickEventArgs) _ Handles btnSubmit.Click  Server.Transfer("CH03SubmitToAnother_SecondPageVB2.aspx", True)  End Sub 'btnSubmit_Click 
figs/csharpicon.gif
 private void btnSubmit_Click(Object sender, System.Web.UI.ImageClickEventArgs e) {  Server.Transfer("CH03SubmitToAnother_SecondPageCS2.aspx", true);  } // btnSubmit_Click 

The code-behind for the page that processes the form data needs no code for this example. The reason is that, in this example, we are just displaying the data on the page. In a real-world example, the values of the form fields can be accessed just as they would if the form were submitted to itself.

ASP.NET will populate the controls on the second page with the data from the forms collection of the first page. Controls that match by name and datatype will be populated with data from the first form. If the controls on the second form have different names or datatype s, they are not populated. This requires very tight linkage between the pages and can be a significant maintenance issue.


The alternate approach described here may not work correctly in Version 1.1 of the .NET Framework due to a bug in the implementation. The bug is described in Microsoft Knowledge Base article 821758 (http://support.microsoft.com/default.aspx?kbid=821758). To work correctly, the hotfix described in article 821156 (http://support.microsoft.com/default.aspx?kbid=821156) must be applied.


Example 3-7. Submitting a form to another page ”first page (.aspx)
 <%@ Page Language="vb" AutoEventWireup="false" Codebehind="CH03SubmitToAnother_FirstPageVB1.aspx.vb" Inherits="ASPNetCookbook.VBExamples.CH03SubmitToAnother_FirstPageVB1" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>Form Submission To Another Page</title> <link rel="stylesheet" href="css/ASPNetCookbook.css"> </head> <body leftmargin="0" marginheight="0" marginwidth="0" topmargin="0"> <form id="frmSubmitToAnother" method="post" runat="server"> <table width="100%" cellpadding ="0" cellspacing="0" border="0"> <tr> <td align="center"> <img src="images/ASPNETCookbookHeading_blue.gif"> </td> </tr> <tr> <td class="dividerLine"> <img src="images/spacer.gif" height="6" border="0"></td> </tr> </table> <table width="90%" align="center" border="0"> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <tr> <td align="center" class="PageHeading"> Form Submission To Another Page - Approach 1 (VB) </td> </tr> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <tr> <td align="center"> <table border="0"> <tr> <td class="LabelText">First Name: </td> <td> <asp:TextBox ID="txtFirstName" Runat="server" Columns="30" CssClass="LabelText" /> </td> </tr> <tr> <td class="LabelText">Last Name: </td> <td> <asp:TextBox ID="txtLastName" Runat="server" Columns="30" CssClass="LabelText" /> </td> </tr> <tr> <td class="LabelText">Age: </td> <td> <asp:TextBox ID="txtAge" Runat="server" Columns="30" CssClass="LabelText" /> </td> </tr> <tr> <td align="center" colspan="2"> <br> <asp:ImageButton ID="btnSubmit" Runat="server" ImageUrl="images/ buttons /button_submit.gif" /> </td> </tr> </table> </td> </tr> </table> </form> </body> </html> 

Example 3-8. Submitting form to another page code-behind ”first page (.vb)
 Option Explicit On Option Strict On '----------------------------------------------------------------------------- ' ' Module Name: CH03SubmitToAnother_FirstPageVB1.aspx.vb ' ' Description: This module provides the code behind for ' CH03SubmitToAnother_FirstPageVB1.aspx ' '***************************************************************************** Namespace ASPNetCookbook.VBExamples Public Class CH03SubmitToAnother_FirstPageVB1 Inherits System.Web.UI.Page 'controls on form Public txtFirstName As System.Web.UI.WebControls.TextBox Public txtLastName As System.Web.UI.WebControls.TextBox Public txtAge As System.Web.UI.WebControls.TextBox Protected WithEvents btnSubmit As System.Web.UI.WebControls.ImageButton 'the following constant is used to define the variable in session scope 'used to pass the form data  Public Const SES_SUBMITTED_DATA As String = "SubmittedData"  '************************************************************************* ' ' ROUTINE: Page_Load ' ' DESCRIPTION: This routine provides the event handler for the page load ' event. It is responsible for initializing the controls ' on the page. '------------------------------------------------------------------------- Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load If (Not Page.IsPostBack) Then 'Put user code to initialize the page here End If End Sub 'Page_Load '************************************************************************* ' ' ROUTINE: btnSubmit_Click ' ' DESCRIPTION: This routine provides the event handler for the submit ' button click event. It is responsible passing the form ' data to another form for processing. '-------------------------------------------------------------------------  Private Sub btnSubmit_Click(ByVal sender As Object, _   ByVal e As System.Web.UI.ImageClickEventArgs) _   Handles btnSubmit.Click   'add this object to session scope   Session.Add(SES_SUBMITTED_DATA, Me)   'transfer control to the page that will process the form data   'NOTE: Second parameter for the transfer method must be set false to   ' avoid transferring the viewstate to the next form. If the   ' viewstate is transferred without disabling the machine   ' authentication check, an exception will be thrown due to a   ' corrupted viewstate (would fail MAC check)   Server.Transfer("CH03SubmitToAnother_SecondPageVB1.aspx", False)   End Sub 'btnSubmit_Click  End Class 'CH03SubmitToAnother_FirstPageVB1 End Namespace 

Example 3-9. Submitting a form to another page code-behind ”first page (.cs)
 //---------------------------------------------------------------------------- // // Module Name: CH03SubmitToAnother_FirstPageCS1.aspx.cs // // Description: This module provides the code behind for // CH03SubmitToAnother_FirstPageCS1.aspx // //**************************************************************************** using System; using System.Web.UI; namespace ASPNetCookbook.CSExamples { public class CH03SubmitToAnother_FirstPageCS1 : System.Web.UI.Page { // controls on form public System.Web.UI.WebControls.TextBox txtFirstName; public System.Web.UI.WebControls.TextBox txtLastName; public System.Web.UI.WebControls.TextBox txtAge; protected System.Web.UI.WebControls.ImageButton btnSubmit; // the following constant is used to define the variable in session scope // used to pass the form data  public const String SES_SUBMITTED_DATA = "SubmittedData";  //************************************************************************ // // ROUTINE: Page_Load // // DESCRIPTION: This routine provides the event handler for the page // load event. It is responsible for initializing the // controls on the page. //------------------------------------------------------------------------ private void Page_Load(object sender, System.EventArgs e) { // wire the submit button click event this.btnSubmit.Click += new ImageClickEventHandler(this.btnSubmit_Click); if (!Page.IsPostBack) { // Put user code to initialize the page here } } // Page_Load //************************************************************************ // // ROUTINE: btnSubmit_Click // // DESCRIPTION: This routine provides the event handler for the submit // button click event. It is responsible processing the // form data. // //------------------------------------------------------------------------  private void btnSubmit_Click(Object sender,   System.Web.UI.ImageClickEventArgs e)   {   // 'add this object to session scope   Session.Add(SES_SUBMITTED_DATA, this);   // transfer control to the page that will process the form data   // NOTE: Second parameter for the transfer method must be set false to   // avoid transferring the viewstate to the next form. If the   // viewstate is transferred without disabling the machine   // authentication check, an exception will be thrown due to a   // corrupted viewstate (would fail MAC check)   Server.Transfer("CH03SubmitToAnother_SecondPageCS1.aspx", false);   } // btnSubmit_Click  } // CH03SubmitToAnother_FirstPageCS1 } 

Example 3-10. Submitting form to another page ”second page (.aspx)
 <%@ Page Language="vb" AutoEventWireup="false" Codebehind="CH03SubmitToAnother_SecondPageVB1.aspx.vb" Inherits="ASPNetCookbook.VBExamples.CH03SubmitToAnother_SecondPageVB1" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>Form Submission To Another Page - Second Page</title> <link rel="stylesheet" href="css/ASPNetCookbook.css"> </head> <body leftmargin="0" marginheight="0" marginwidth="0" topmargin="0"> <form id="frmSubmitToAnother" method="post" runat="server"> <table width="100%" cellpadding="0" cellspacing="0" border="0"> <tr> <td align="center"> <img src="images/ASPNETCookbookHeading_blue.gif"> </td> </tr> <tr> <td class="dividerLine"> <img src="images/spacer.gif" height="6" border="0"></td> </tr> </table> <table width="90%" align="center" border="0"> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <tr> <td align="center" class="PageHeading"> Form Submission To Another Page - Approach 1 (VB) </td> </tr> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <tr> <td align="center"> <table border="0"> <tr> <td colspan="2" align="center" class="PageHeading"> Data Submitted From Previous Form </td> </tr> <tr> <td class="LabelText">First Name: </td> <td class="LabelText"> <asp:Label ID="lblFirstName" Runat="server" /> </td> </tr> <tr> <td class="LabelText">Last Name: </td> <td class="LabelText"> <asp:Label id="lblLastName" Runat="server" /> </td> </tr> <tr> <td class="LabelText">Age: </td> <td class="LabelText"> <asp:Label ID="lblAge" Runat="server" /> </td> </tr> </table> </td> </tr> </table> </form> </body> </html> 

Example 3-11. Submitting a form to another page code-behind ”second page (.vb)
 Option Explicit On Option Strict On '----------------------------------------------------------------------------- ' ' Module Name: CH03SubmitToAnother_SecondPageVB1.aspx.vb ' ' Description: This module provides the code behind for ' CH03SubmitToAnother_SecondPageVB1.aspx ' '***************************************************************************** Namespace ASPNetCookbook.VBExamples Public Class CH03SubmitToAnother_SecondPageVB1 Inherits System.Web.UI.Page 'controls on form Protected lblFirstName As System.Web.UI.WebControls.Label Protected lblLastName As System.Web.UI.WebControls.Label Protected lblAge As System.Web.UI.WebControls.Label '************************************************************************* ' ' ROUTINE: Page_Load ' ' DESCRIPTION: This routine provides the event handler for the page load ' event. It is responsible for initializing the controls ' on the page. '-------------------------------------------------------------------------  Private Sub Page_Load(ByVal sender As System.Object, _   ByVal e As System.EventArgs) Handles MyBase.Load   Dim submittedPage As CH03SubmitToAnother_FirstPageVB1   'get the form data from session scope then remove the session variable   'to conserve resources   submittedPage = _   CType(Session.Item(CH03SubmitToAnother_FirstPageVB1.SES_SUBMITTED_DATA), _   CH03SubmitToAnother_FirstPageVB1)   Session.Item(CH03SubmitToAnother_FirstPageVB1.SES_SUBMITTED_DATA) = Nothing   'set the values on this form with the data from the submitted form   lblFirstName.Text = submittedPage.txtFirstName.Text   lblLastName.Text = submittedPage.txtLastName.Text   lblAge.Text = submittedPage.txtAge.Text   End Sub 'Page_Load  End Class 'CH03SubmitToAnother_SecondPageVB1 End Namespace 

Example 3-12. Submitting a form to another page code-behind ”second page (.cs)
 //---------------------------------------------------------------------------- // // Module Name: CH03SubmitToAnother_SecondPageCS1.aspx.cs // // Description: This module provides the code behind for // CH03SubmitToAnother_SecondPageCS1.aspx // //**************************************************************************** using System; namespace ASPNetCookbook.CSExamples { public class CH03SubmitToAnother_SecondPageCS1 : System.Web.UI.Page { // controls on form protected System.Web.UI.WebControls.Label lblFirstName; protected System.Web.UI.WebControls.Label lblLastName; protected System.Web.UI.WebControls.Label lblAge; //************************************************************************ // // ROUTINE: Page_Load // // DESCRIPTION: This routine provides the event handler for the page // load event. It is responsible for initializing the // controls on the page. // //------------------------------------------------------------------------  private void Page_Load(object sender, System.EventArgs e)   {   CH03SubmitToAnother_FirstPageCS1 submittedPage;   // get the form data from session scope then remove the session   // variable to conserve resources   submittedPage =   (CH03SubmitToAnother_FirstPageCS1)   (Session[CH03SubmitToAnother_FirstPageCS1.SES_SUBMITTED_DATA]);   Session[CH03SubmitToAnother_FirstPageCS1.SES_SUBMITTED_DATA] = null;   // set the values on this form with the data from the submitted form   lblFirstName.Text = submittedPage.txtFirstName.Text;   lblLastName.Text = submittedPage.txtLastName.Text;   lblAge.Text = submittedPage.txtAge.Text;   } // Page_Load  } // CH03SubmitToAnother_SecondPageCS1 } 



ASP. NET Cookbook
ASP.Net 2.0 Cookbook (Cookbooks (OReilly))
ISBN: 0596100647
EAN: 2147483647
Year: 2006
Pages: 179

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