Wednesday, March 10, 2010

A back button for asp.net pages


For my app I needed a back button. Internet explorer and other browsers have back buttons, most mice have them as well but I needed my own small link to drop on my forms. Implementing it was no big deal, given you consider one essential quirk. After browsing around on the web I consider it worthwhile to share my findings.

The essential thing is what back really stands for. When an user is working with an aspx page she will regularly post back to the page leading to many renderings of the same url. By default back is back to the previous request. An application like Community Server (which is an asp.net app) works this way. Write you comment and click submit. When you click the back button of your mouse after that you'll be back editing the comment. When you click submit again it might look like you 're posting an updated comment. In reality CS does receive a new comment. (Don't try this at home, to prevent comment spamming CS blocks posting comments in that pace). To give the user a better user experience thesmartNavigation property of an asp.net webform comes to the help. Setting it to true will redirect the user to the previous page when the back button is clicked. It does this by some script magic. Alas smartNavigation can play some nasty tricks on you when you try to redirect from a page which has it enabled.

In code you can see from which url the user came in the UrlReferrer property of the Request.. This always show the url of the last roundtrip, whether smartNavigation is switched on or off. So it will be the url of the page itself on a postback. On the first rendering of the page it will contain the intended page the user came from. So checking postback in combination with the referrer should do to find the desired url. The url has to be stored over roundtrips. On the best example I found on the web, by master of mysteryJuval Löwy, it is stored in the session. This is a full demo ((free) registration required) where clicking a linkbutton performs a redirect to an URL. But besides problems with smartnavigation I think the viewstate would be a better place to store the url than the session.

I use a plain HyperLink. The essence of my back link boils down to

private void Page_Load(object sender, System.EventArgs e)
{
if (! IsPostBack)
HyperLink1.NavigateUrl = Request.UrlReferrer.AbsoluteUri;
}

The NavigateUrl is set on the first request and will be saved over roundtrips in the viewstate.

As I am a bad and a lazy typist I don't want to code these lines again and again. Let's make it a custom control. Take these steps:

  • Add a new project, a Web ControlLibrary
  • Delete the webusercontrol1
  • Add a new item to the library, a Web Custom Control. Give it a real name
  • Delete all generated implementation code
  • Copy in this code
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;

namespace ButonBacklLibrary
{
///
/// Summary description for MyBackButton.
///

[ToolboxData("<{0}:MyBackButton runat=server>")]
public class MyBackButton : System.Web.UI.WebControls.HyperLink
{
protected override void OnLoad(EventArgs e)
{
if (! Page.IsPostBack)
base.NavigateUrl = Page.Request.UrlReferrer.AbsoluteUri;
base.OnLoad (e);
}

[Browsable(false)]
public new string NavigateUrl
{
get
{
return base.NavigateUrl;
}
}
}
}

The MyBackButton inherits from the HyperLink control. In the overriden OnLoad method the code to get the referral url is executed and stored in the NavigateURL property of the base, HyperLink, class. It no longer makes sense to manipulate the NavigateURL property of the back control in the designer or from code. I cannot override the property as it is not virtual. Using the new keyword the original property is shadowed. In code and in the designer my version of the property named NavigateURL is used. The implementation of the property can still get to the inherited property. The property getter just reads the base property, but the setter property has gone. I can no longer change the URL from code. By setting the [Browsable(false)] attribute on the property it will also be gone from the property window in the designer.

To get this button into the VS toolbox:

  • Right click the toolbox
  • Choose Add/Remove items
  • In the dialog click the browse button
  • Select the library we just built It's the dll in the bin\debug or bin\release directory
  • The control will show up in the toolbox.

You can start using the control in you project. Debugging works well, breakpoints set in the control's source will be hit.

Now you have a back button which is independent of the smartNavigation and session settings. But it does need the viewstate. Fiddling with that is another story.

No comments: