Section 6.3. Moving to Another Page

6.3. Moving to Another Page

By default, when a page is submitted to the server, it is posted back to itself. However, there are many situations in a web application where you need to direct the application flow to another page, either directly or after posting to the server. There are four different ways to do this: HyperLink , Server.Transfer , Response.Redirect , and cross-page posting.

6.3.1. HyperLink

The Hyperlink control navigates directly to the location contained in the NavigateUrl property of the control without a postback to the server. This control is covered in Chapter 4.

6.3.2. Server.Transfer

The TRansfer method of the HttpServerUtility class takes a URL of an .aspx or .htm page (but not .asp ) as a string argument and posts back to the server. Execution of the current page is terminated and execution of the new page begins.

Because the HttpResponse.End method is called on the current page, it always raises a THReadAbortException . This is usually not an issue, but if the Server.Transfer occurs as part of a connection-based database transaction (see Chapter 10 for details on connection-based database transactions) inside a TRy block, where the Rollback method is called in a catch block, the transaction will never commit because the transaction Commit method will be negated by the ThreadAbortException , unless you specifically catch the THReadAbortException , as in the following code snippet:

 try {    //  do database stuff,then Commit the transaction    transaction.Commit();    //  Navigate to another page assuming a successful Commit.    //  This will raise a ThreadAbortException every time.    Server.Transfer("OrderDetails.aspx?OrderID=" + strOrderID); } catch (ThreadAbortException ex) {    //  placeholder to catch the routine exception } catch (Exception ex) {    //  there was a problem w/ the Commit, so roll back    transaction.Rollback(); } finally {    //  always close the connection    connection.Close(); } 

The original and target pages must be part of the same application. The target page can access public members of the control page, as will be demonstrated.

Server.Transfer does not verify that the current user is authorized to view the target page. If this is important for your application, you will need to use one of the other techniques described here.

After the transfer to the new page, the browser will continue to display the URL of the original page in its address box and not the current page. The browser's history does not reflect the transfer, so clicking the browser's Back button generally will not yield the desired results.

An overloaded form of the method takes a Boolean argument, which, if true , will indicate that the QueryString and Form collections of the original page will be preserved. The default is false .

This overload is particularly useful when you truly need to transfer complete control to another page. For example, if you were creating a multi-step web-based setup wizard and you needed the order of the various steps to be conditional based on the user's selections on previous answers, you could use this Server.Transfer overload to pass complete control to the pertinent page and preserve any QueryString and Form collections from previous pages or steps in the setup wizard.

Keep in mind that view state will not be preserved from page to page even though view state is stored within a hidden form variable. View state is page-scoped and invalidates when transferred to another page via Server.Transfer .

6.3.3. Response.Redirect

The Redirect method of the HttpResponse class is the programmatic equivalent of a HyperLink. It takes a URL of an .aspx or .htm page (but not .asp ) as a string argument and performs a client-side redirect without posting back to the server. Consequently, it is faster than Server.Transfer . Since it is a completely new server request, it forces complete authentication and authorization.

Data from the original page is unavailable to the target page unless they are both in the same application, in which case data can be transferred using Session or Application state.

An overloaded form of this method takes a Boolean argument, which if true , indicates that the current page execution will be terminated.

6.3.4. Cross-Page Posting

A page can be submitted to the server and post directly back to another page. This is implemented via the PostBackUrl property of specific controls. It can only transfer to another .aspx page, not .asp or .htm . Controls from the previous page are available by using the Page.PreviousPage property.

If the original page and target page are both within the same application, then like all pages in an application, they can share Session and Application state as well as public members of the original page. A page can cross-post to a page outside the application, but data from the originating page is not available to the target page.

If the PreviousPage property of the target page is accessed, the original page is instantiated again and the stored View state from the original page is restored. Consequently, the performance penalty from using the PreviousPage property is directly affected by the amount of information stored in View state in the previous page. (View state is covered in more detail later in this chapter.)

Cross-page posting is new to Version 2.0 of ASP.NET.


To see how these three techniques work, create a new web site in VS2005 called CrossPagePostingSimple. Drag three Button controls onto the default content page and name them btnServerTransfer , btnRedirect , and btnCrossPage . In Design view, double-click each of the first two buttons to give them default Click event handlers. btnCrossPage does not have any event handler code. However, for that button, set the PostBackUrl property to TargetPage.aspx . The complete code listing for the content file, Default.aspx , is shown in Example 6-4, with the three Button declarations highlighted.

Example 6-4. Default.aspx for CrossPagePostingSimple
 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs"       Inherits="_Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server">     <title>Cross-Page Posting</title> </head> <body>     <form id="form1" runat="server">     <div>        <h1>Cross-Page Posting</h1>  <asp:Button ID="btnServerTransfer" runat="server"          Text="Server.Transfer"          OnClick="btnServerTransfer_Click" />        <asp:Button ID="btnRedirect" runat="server"          Text="Response.Redirect"          OnClick="btnRedirect_Click" />        <asp:Button ID="btnCrossPage" runat="server"          Text="Cross-Page Post"          PostBackUrl="TargetPage.aspx" />  </div>     </form> </body> </html> 

In the code-behind file, enter the event handlers shown in Example 6-5.

Example 6-5. Event handlers in Default.aspx.cs for CrossPageSimple
 protected void btnServerTransfer_Click(object sender, EventArgs e) {  Server.Transfer("TargetPage.aspx");  } protected void btnRedirect_Click(object sender, EventArgs e) {  Response.Redirect("TargetPage.aspx");  } 

Now add a new web page to the project and call it TargetPage.aspx . For now, this is a simple page with only an HTML header element, as shown in Example 6-6. There is no code behind page for the target page at this point (other than the boilerplate created by VS2005).

Example 6-6. TargetPage.aspx for CrossPageSimple
 <%@ Page Language="C#" AutoEventWireup="true"    CodeFile="TargetPage.aspx.cs" Inherits="TargetPage_aspx" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server">     <title>Target Page</title> </head> <body>     <form id="form1" runat="server">     <div>       <h1>Target Page</h1>     </div>     </form> </body> </html> 

Set Default.aspx as the Start page and run the application. You will get something like that shown in Figure 6-2.

Figure 6-2. CrossPagePostingSimple

Clicking on the Server.Transfer button will bring up the page shown in Figure 6-3.

Figure 6-3. TargetPage via Server.Transfer

The URL in the address bar still points to the original page, Default.aspx .

Now click on the browser Back button to get back to the original page and click on either the Response.Redirect or Cross-Page Post buttons. The result will be almost the same, shown in Figure 6-4.

Figure 6-4. TargetPage via Response.Redirect or Cross-Page Post

Notice, however, that the URL now points to the current page, TargetPage.aspx . Though the end result of the Response.Redirect and the cross-page post appears the same, there is a fundamental difference. Response.Redirect does not post to the server, and so no server-side code can execute. Cross-page posting does post to the server, as does Server.Transfer , so you can handle the Click event and run server-side code.

The cross-page post was accomplished simply by setting the PostBackUrl property of the button.

 PostBackUrl="TargetPage.aspx" /> 

PostBackUrl is a property of all controls that implement the IButtonControl interface. This includes the Button , ImageButton , and LinkButton ASP.NET server controls. Since cross-page posting is implemented on a control-by-control basis, rather than a page basis, it gives great flexibility in directing where a page will post back to.

6.3.4.1. Retrieving data from the previous page

When posting to a different page, a typical requirement is to access controls and objects from the previous page. You could stash cross-page data in session state (described later in this chapter), but that consumes server resources and should be used cautiously with large objects.

The Page class exposes the PreviousPage property to provide a reference to the previous page object. There are two different ways of retrieving data from this Page reference, both of which will be demonstrated shortly. The technique you can use is dependent upon whether or not the Page object is strongly typed .

A strongly typed object has a very specific collection of public members, with each member being of a specific type. Under these circumstances, you could retrieve a public member of a Page , say a property called Password , of type string, with the following line of code:

 string str = PreviousPage.Password; 

Under normal circumstances, i.e., by default, the Page object returned by the PreviousPage property is not strongly typed. In this case, to retrieve the contents of a control, you must use late-binding, i.e., use reflection to determine what controls are in the Page 's Controls collection at runtime and find a specific control using the FindControl method of the Page . However, late-binding imposes a performance penalty, and so should be avoided if possible.

In order to strongly type the PreviousPage Page object, the content file of the target page (i.e., the page being transferred to) must have an additional directive, PreviousPageType , added at the top of the file. The PreviousPageType directive has two possible attributes, of which only one may be used at a time on a page:



TypeName

A string representing the type of the previous page



VirtualPath

A string representing the relative URL of the previous page

To see this in action, copy the previous example, CrossPagePostingSimple, to a new web site, CrossPagePostingAccessingPrevious. To default.aspx , add a DropDownList named ddlFavoriteActivity populated with a number of your favorite activities, along with some <br/> elements to space things out. Default.aspx is listed in Example 6-7, with the new code highlighted. Set the AutoPostback property of the DropDownList to TRue so you can see the that when the form is posted normally, it comes back to itself.

Example 6-7. Default.aspx for CrossPagePostingAccessingPrevious
 <%@ Page Language="C#" AutoEventWireup="true"    CodeFile="Default.aspx.cs" Inherits="_Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server">     <title>Cross-Page Posting</title> </head> <body>     <form id="form1" runat="server">     <div>       <h1>Cross-Page Posting</h1>  Select your favorite activity:&nbsp;        <asp:DropDownList ID="ddlFavoriteActivity" runat="server"           AutoPostBack="true">          <asp:ListItem Text="Eating" />          <asp:ListItem Text="Sleeping" />          <asp:ListItem Text="Programming" />          <asp:ListItem Text="Watching TV" />          <asp:ListItem Text="Sex" />          <asp:ListItem Text="Skiing" />          <asp:ListItem Text="Bicycling" />        </asp:DropDownList>  <br />        <br />        <br />        <asp:Button ID="btnServerTransfer" runat="server"          Text="Server.Transfer"          OnClick="btnServerTransfer_Click" />        <asp:Button ID="btnRedirect" runat="server"          Text="Response.Redirect"          OnClick="btnRedirect_Click" />        <asp:Button ID="btnCrossPage" runat="server"          Text="Cross-Page Post"          PostBackUrl="TargetPage.aspx" />     </div>     </form> </body> </html> 

Since the Page object returned by the PreviousPage property can only access public members, you must publicly expose ddlFavoriteActivity . The best way to do this is to create in the Page class a public, read-only property of type DropDownList . To do that, edit Default.aspx.cs to add the code highlighted in Example 6-8.

Example 6-8. Default.aspx.cs for CrossPagePostingAccessingPrevious
 using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using System.Threading;         //  necessary for ThreadAbortException public partial class _Default : System.Web.UI.Page {     protected void Page_Load(object sender, EventArgs e)     {     }  public DropDownList FavoriteActivity    {       get { return ddlFavoriteActivity; }    }  protected void btnServerTransfer_Click(object sender, EventArgs e)     {        Server.Transfer("TargetPage.aspx");     }    protected void btnRedirect_Click(object sender, EventArgs e)     {        Response.Redirect("TargetPage.aspx");     }  } 

There is no inherent reason why this property must be read-only. By adding a set accessor, you could make it read/write. However, in this type of scenario, read-only is usually adequate.

Now that you have exposed a public property that returns an instance of a DropDownList , you must prepare the target page to retrieve it. Modify the content page of the Target page, TargetPage.aspx , adding the code highlighted in Example 6-9.

Example 6-9. TargetPage.aspx in CrossPagePostingAccessingPrevious
 <%@ Page Language="C#" AutoEventWireup="true"    CodeFile="TargetPage.aspx.cs" Inherits="TargetPage_aspx" %>  <%@ PreviousPageType  VirtualPath="~/Default.aspx" %>  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server">     <title>Target Page</title> </head> <body>     <form id="form1" runat="server">     <div>       <h1>Target Page.</h1>  Your favorite activity is        <asp:Label ID="lblActivity" runat="server" Text="unknown" />  </div>     </form> </body> </html> 

You added a PreviousPageType directive, with the VirtualPath attribute set to the URL of the original page. (The ~/ preceding the filename is not required but is put there by Intellisense in the VS2005 editor. It resolves to the root of the application.) You also added a Label server control to display the value retrieved from the DropDownList on the previous page.

The final step in this process is to add the highlighted lines of code from Example 6-10 to the TargetPage code-behind file.

Example 6-10. TargetPage.aspx.cs for CrossPagePostingAccessingPrevious
 using System; using System.Data; using System.Configuration; using System.Collections; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; public partial class TargetPage_aspx : System.Web.UI.Page {     protected void Page_Load(object sender, EventArgs e)     {  if (Page.PreviousPage != null)        {          lblActivity.Text =               PreviousPage.FavoriteActivity.SelectedItem.ToString();        }  } } 

This code in the Page_Load event handler first tests to see if the PreviousPage property has been set. If it hasn't, for example if you arrive here by clicking on the Response.Redirect button on the Default page, then the initially declared (i.e., declared in TargetPage.aspx ) Text property of lblActivityText will be displayed.

If the PreviousPage property has been set, by posting the request to the server using either Server.Transfer or cross-page posting, then lblActivity will be populated by retrieving the SelectedItem property of ddlFavoriteActivity via the FavoriteActivity property.

The implication of this entire process is that any page can only be transferred to by a single other page since the previous page name is hardcoded in the PreviousPageType directive if you are to use strongly typed Page objects and the PreviousPage property. However, this is not the case. You can transfer or post from any page as long as they all have the same signature , i.e., the specific list of public members and types.

If all the pages you need to transfer from do not have the same signature, or if you cannot know at design time the name of a page to specify the types, you will have to use late -binding techniques (or, more likely, session state). Once again, this technique incurs a significant performance penalty versus the early-bound, strongly typed method.

To see late-binding at work, copy the previous example, CrossPagePostingAccessingPrevious, to a new web site called CrossPagePostingAccessingPreviousLateBound. Default.aspx is unchanged from before, but there is no longer any need for the public property FavoriteActivity , so that can be deleted from Default.aspx.cs . In TargetPage.aspx , delete the PreviousPageType directive. Then, in TargetPage.aspx.cs , replace the Page_Load method with the highlighted code from Example 6-11.

Example 6-11. TargetPage.aspx.cs for CrossPagePostingAccessingPreviousLateBound
 using System; using System.Data; using System.Configuration; using System.Collections; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; public partial class TargetPage_aspx : System.Web.UI.Page {     protected void Page_Load(object sender, EventArgs e)     {  if (Page.PreviousPage != null)        {           DropDownList ddl =             (DropDownList)Page.PreviousPage.FindControl("ddlFavoriteActivity");          if (ddl != null)             lblActivity.Text = ddl.SelectedItem.ToString() +                                   " (late-bound)";        }  } } 

By removing the public property FavoriteActivity from the default.aspx.cs listed in Example 6-8, the Text assignment line of code in Example 6-10 fails. Instead, Page_Load in Example 6-11 uses the FindControl method of the Pageclass to get a reference directly to the DropDownList . The PreviousPageType directive was removed because it no longer serves any purpose.

Note well that the PreviousPage property is still defined but only if the page was navigated to via a server post. If you click the Response.Redirect button, which redirects to the target page from client-side code, not server code, then lblActivity will never be populated in Page_Load and the initial value will be used again.

6.3.4.2. How did I get here?

It is often helpful to know if a page has been opened directly or as the result of a transfer or cross-page post. Two read-only Page properties of type Boolean, IsPostBack and IsCrossPagePostBack , allow this to be determined.

Though the IsCrossPagePostBack property is new to Version 2.0 of ASP.NET, the usage of these two properties is such that Version 1.x behavior is unchanged.


The values that these properties assume is not always what you might expect at first glance. To follow this, copy the previous example, CrossPagePostingAccessingPreviousLateBound, to a new web site called CrossPagePostingPostBackProperties. You will add Label controls to each of the two content pages to display the values of the various properties, and you will modify the two Page_Load methods to populate those labels. All four files are listed, with the new code highlighted, in Examples 6-12 through 6-15.

Example 6-12. Default.aspx for CrossPagePostingPostBackProperties
 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs"    Inherits="_Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server">     <title>Cross-Page Posting</title> </head> <body>     <form id="form1" runat="server">     <div>       <h1>Cross-Page Posting</h1>        Select your favorite activity:&nbsp;        <asp:DropDownList ID="ddlFavoriteActivity" runat="server"          AutoPostBack="true">          <asp:ListItem Text="Eating" />          <asp:ListItem Text="Sleeping" />          <asp:ListItem Text="Programming" />          <asp:ListItem Text="Watching TV" />          <asp:ListItem Text="Sex" />          <asp:ListItem Text="Skiing" />          <asp:ListItem Text="Bicycling" />        </asp:DropDownList>        <br />        <br />        <br />        <asp:Button ID="btnServerTransfer" runat="server"          Text="Server.Transfer"          OnClick="btnServerTransfer_Click" />        <asp:Button ID="btnRedirect" runat="server"          Text="Response.Redirect"          OnClick="btnRedirect_Click" />        <asp:Button ID="btnCrossPage" runat="server"          Text="Cross-Page Post"          PostBackUrl="TargetPage.aspx" />  <br />       <br />       IsPostBack:       <asp:Label ID="lblIsPostBack" runat="server" Text="not defined" />       <br />       IsCrossPagePostBack:       <asp:Label ID="lblIsCrossPagePostBack" runat="server"                  Text="not defined" />       <br />       PreviousPage:       <asp:Label ID="lblPreviousPage" runat="server" Text="not defined" />  </div>     </form> </body> </html> 

Example 6-13. Default.aspx.cs for CrossPagePostingPostBackProperties
 using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using System.Threading;         //  necessary for ThreadAbortException public partial class _Default : System.Web.UI.Page {     protected void Page_Load(object sender, EventArgs e)     {  lblIsPostBack.Text = IsPostBack.ToString();        lblIsCrossPagePostBack.Text = IsCrossPagePostBack.ToString();        if (Page.PreviousPage != null)           lblPreviousPage.Text = Page.PreviousPage.Title;  }    protected void btnServerTransfer_Click(object sender, EventArgs e)     {        Server.Transfer("TargetPage.aspx");     }    protected void btnRedirect_Click(object sender, EventArgs e)     {        Response.Redirect("TargetPage.aspx");     }  } 

Example 6-14. TargetPage.aspx for CrossPagePostingPostBackProperties
 <%@ Page Language="C#" AutoEventWireup="true"    CodeFile="TargetPage.aspx.cs" Inherits="TargetPage_aspx" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server">     <title>Target Page</title> </head> <body>     <form id="form1" runat="server">     <div>        <h1>Target Page.</h1>        Your favorite activity is        <asp:Label ID="lblActivity" runat="server" Text="unknown" />  <br />        <br />        IsPostBack:        <asp:Label ID="lblIsPostBack" runat="server" Text="not defined" />        <br />        IsCrossPagePostBack:        <asp:Label ID="lblIsCrossPagePostBack" runat="server"                   Text="not defined" />        <br />        PreviousPage:        <asp:Label ID="lblPreviousPage" runat="server"                   Text="not defined" />        <br />        Previous Page IsPostBack:        <asp:Label ID="lblPreviousPageIsPostBack" runat="server"                   Text="not defined" />        <br />        Previous Page IsCrossPagePostBack:        <asp:Label ID="lblPreviousPageIsCrossPagePostBack" runat="server"                   Text="not defined" />  </div>     </form> </body> </html> 

Example 6-15. TargetPage.aspx.cs for CrossPagePostingPostBackProperties
 using System; using System.Data; using System.Configuration; using System.Collections; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; public partial class TargetPage_aspx : System.Web.UI.Page {     protected void Page_Load(object sender, EventArgs e)     {        if (Page.PreviousPage != null)        {           DropDownList ddl =              (DropDownList)Page.PreviousPage.FindControl("ddlFavoriteActivity");           if (ddl != null)              lblActivity.Text = ddl.SelectedItem.ToString() +                      " (late-bound)";        }  lblIsPostBack.Text = IsPostBack.ToString();        lblIsCrossPagePostBack.Text = IsCrossPagePostBack.ToString();        if (Page.PreviousPage != null)        {           lblPreviousPage.Text = Page.PreviousPage.Title;           lblPreviousPageIsPostBack.Text =                Page.PreviousPage.IsPostBack.ToString();           lblPreviousPageIsCrossPagePostBack.Text =                Page.PreviousPage.IsCrossPagePostBack.ToString();        }  } } 

Running CrossPagePostingPostBackProperties through the various scenarios reveals the matrix shown in Table 6-4.

Table 6-4. PostBack property values

Action

Page

Property

Value

default.aspx posting itself

default.aspx

default.aspx

default.aspx

IsPostBack

IsCrossPagePostBack

PreviousPage

true

false

null

default.aspx to TargetPage.aspxPage via Server.Transfer

TargetPage.aspx

TargetPage.aspx

TargetPage.aspx

default.aspx

default.aspx

IsPostBack

IsCrossPagePostBack

PreviousPage

IsPostBack

IsCrossPagePostBack

false

false

Default

true

false

default.aspx to TargetPage.aspxPage via cross-page posting

TargetPage.aspx

TargetPage.aspx

TargetPage.aspx

default.aspx

default.aspx

IsPostBack

IsCrossPagePostBack

PreviousPage

IsPostBack

IsCrossPagePostBack

false

false

Default

true

true


You can see the effects of default.apx posting back to itself by selecting a new value from the DropDownList since the AutoPostBack property is set to true for that control. The only difference between posting to a new page via Server.Transfer and cross-page posting is in the value of the original page's IsCrossPagePostBack property, which is false for the former and true for the latter.



Programming ASP. NET
Programming ASP.NET 3.5
ISBN: 0596529562
EAN: 2147483647
Year: 2003
Pages: 173

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