Posting Among Forms Now and in ASP.NET 2.0...

ASP.NET 2.0 brings back cross-page posting.


By: Brian Mains Date: August 27, 2004 Download the code.

If you've been an ASP developer for some time, you probably know that posting data among multiple web forms has been a touchy issue as of late. If you aren't familiar with this feature, here is a recap:

In ASP, posting data to another page was simple. The form's action property contained the name of the page to post the data to. All of the controls within that form element are available to the subsequent page through the Request.Form collection. The key used to retrieve the value is the ID of the control in the initial page. The form was posted using several techniques; however, using a submit button was the easiest. When a submit button existed in a form, the form automatically posted back to the server upon clicking it.

When ASP.NET and the .NET framework 1.x were released, Microsoft changed its approach to form posting and removed cross-posting capabilities. The only option was to post the data internally within the page. There were several reasons for doing this; namely, the AutoPostBack property. This property allows posting back to the server on certain control events, such as a DropDownList controls SelectedIndexChanged event. This post back isn’t due to data-posting, but rather is a UI feature. If the form could redirect to another form via the action property, when the form posted back, this feature would automatically redirect the page incorrectly.

There are alternatives to posting the data to another page. The page has to post back internally initially, but could then be redirected to another web form. A snapshot of the form data could be passed to the Session or Cache to retain the data during page redirection. Alternatives to this approach are the Server.Transfer and Server.Execute (more documentation can be found here: http://www.dotnetjohn.com/articles.aspx?articleid=142). However, each of these features weren't quite the same as in ASP.

As a potential workaround, the method I would often use when posting data back to the server is to use a series of Panel or HtmlTable controls to handle the logical flow of the application. Only one panel or table would be present at a time, which created a wizard-like interface for the application. An example of this approach is:

<body>
  <form id="form1" runat="server">
  <div>
    <asp:Panel ID="Panel1" Runat="server">
      Display <font color="purple">Panel 1</font> content here<br />
      <br />
      Provide controls or do something  here<br />
      <asp:LinkButton ID="LinkButton1" Runat="server" OnClick="LinkButton1_Click">Next >></asp:LinkButton></asp:Panel>
    <asp:Panel ID="Panel2" Runat="server">
      Display <font color="navy">Panel 2</font> content here<br />
      <br />
      Provide controls or do something  here<br />
      <asp:LinkButton ID="LinkButton2" Runat="server" OnClick="LinkButton2_Click">Next >></asp:LinkButton></asp:Panel>
    <asp:Panel ID="Panel3" Runat="server">
      Display <font color="teal">Panel 3</font> content here<br />
      <br />
      Provide controls or do something  here<br />
      <asp:LinkButton ID="LinkButton3" Runat="server" OnClick="LinkButton3_Click">Next >></asp:LinkButton></asp:Panel>
    <asp:Panel ID="Panel4" Runat="server">
      Display <font color="silver">Panel 4</font> content here<br />
      <br />
      Provide controls or do something  here</asp:Panel>
    </div>
    </form>
</body>

The problem with this approach is the design view (in Visual Studio .NET) for a page in this manner can be a mess, especially when each panel could have twenty or more controls encapsulated within.

Continuing with the previous example, the code uses a private enumeration to represent each panel. The ChangeDisplay method is responsible to show/hide the appropriate panel based on the enumerated value. Initially, the first panel is always shown when the Page is loaded. Each page has some sort of control that triggers a server-side event; this control is typically a LinkButton; however, in reality, it could be any server control that triggers a post back and calls the ChangeDisplay method. My implementation appears below:

'The enumeration, one for each panel
Private Enum DisplayType
  Step1
  Step2
  Step3
  Step4
End Enum

'Changes the panel to only show one panel in the page
Private Sub ChangeDisplay(ByVal objType As DisplayType)
  Panel1.Visible = (objType = DisplayType.Step1)
  Panel2.Visible = (objType = DisplayType.Step2)
  Panel3.Visible = (objType = DisplayType.Step3)
  Panel4.Visible = (objType = DisplayType.Step4)
End Sub

Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
  'Load the first step initially when the page loads
  If (Not Page.IsPostBack) Then
    Me.ChangeDisplay(DisplayType.Step1)
  End If
End Sub

'Linkbuttons to change the display in the form; each one pages
'through, similar to a wizard
Sub LinkButton1_Click(ByVal sender As Object, ByVal e As System.EventArgs)
  Me.ChangeDisplay(DisplayType.Step2)
End Sub

Sub LinkButton2_Click(ByVal sender As Object, ByVal e As System.EventArgs)
  Me.ChangeDisplay(DisplayType.Step3)
End Sub

Sub LinkButton3_Click(ByVal sender As Object, ByVal e As System.EventArgs)
  Me.ChangeDisplay(DisplayType.Step4)
End Sub

ASP.NET 2.0 has reversed this approach and brought back cross-page posting. This is a completely different approach than the ASP implementation. The key is the PostBackURL property, available in specific controls such as the LinkButton or the Button controls. This property redirects to the appropriate page and makes the form data available through the PreviousPage property. Each control is available from the FindControl method.

The following code illustrates form posting between pages. The page below is the initial page (crosspage1.aspx), which contains two TextBox controls. The values that the user provides will be available to the posted form specified in the PostBackURL property of the LinkButton.

<%@ Page Language="VB" ClassName="CrossPage1" %>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
  <title>Untitled Page</title>
</head>
<body>
  <form id="form1" runat="server">
  <div align="center">
  <table>
    <tr>
      <td>Enter some Text:</td>
      <td><asp:TextBox ID="TextBox1" Runat="server"></asp:TextBox></td>
    </tr>
    <tr>
      <td>Enter more Text:</td>
      <td><asp:TextBox ID="TextBox2" Runat="server"></asp:TextBox></td>
    </tr>
    <tr>
      <td align="center" colspan="2">
        <asp:LinkButton ID="LinkButton1" Runat="server" PostBackUrl="~/CrossPage2.aspx">Submit Page</asp:LinkButton>
      </td>
    </tr>
  </table>
  </div>
  </form>
</body>
</html>

The recipient page (crosspage2.aspx) retrieves the data through the PreviousPage property, a property of the Page class. References to the TextBox controls above are retrieved using the FindControl method. The result from this method is an object and must be converted to the appropriate type.

<%@ Page Language="VB" ClassName="CrossPage2" %>

<script runat="server">
  Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
    Label1.Text = String.Empty

    'If posted from CrossPage1.aspx to CrossPage2.aspx...
    If (Not IsNothing(Me.PreviousPage)) Then
      'Retrieve the textbox values from FindControl
      Dim TextBox1 As TextBox = CType(Me.PreviousPage.FindControl("TextBox1"), TextBox)
      Dim TextBox2 As TextBox = CType(Me.PreviousPage.FindControl("TextBox2"), TextBox)

      'If found TextBox1, write the value
      If (Not IsNothing(TextBox1)) Then
        Label1.Text &= "TextBox1: " & TextBox1.Text & "<br>"
      End If

      'If found TextBox2, write the value
      If (Not IsNothing(TextBox2)) Then
        Label1.Text &= "TextBox2: " & TextBox2.Text & "<br>"
      End If

    Else
      Label1.Text = "No values posted from another page."
    End If
  End Sub
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
  <title>Untitled Page</title>
</head>
<body>
  <form id="form1" runat="server">
  <div align="center">
  <asp:Label ID="Label1" Runat="server" EnableViewState="False"></asp:Label> <br />
  <br />
  <asp:HyperLink ID="HyperLink1" Runat="server" NavigateUrl="~/crosspage1.aspx">Back</asp:HyperLink>
  </div>
  </form>
</body>
</html>

Posting data between pages is back, and is as simple and functional as in ASP. This is a great new feature to the .NET 2.0 framework.

About the Code

If the panel controls separation (presented initially, and in pages.aspx in the attached web site) is a desired feature, the .NET framework version 2 features two new controls that make logical grouping easier: the MultiView and the Wizard controls. More information on these controls will be provided in an article later.

You may download the code here.