Click here to Skip to main content
Click here to Skip to main content
Go to top

Stop Refresh after Submitting your Request

, 14 Mar 2004
Rate this:
Please Sign up or sign in to vote.
This article describes a way to implement a control allowing user to stop refesh of a page after submitting the request.

Introduction

One of the common problems faced by web developers is to disable refresh of the browser once the data has been posted to the database. You will notice this problem when your form performs an insert to the database. If you have an insert using a primary key on a sequence or auto-increment column, then the end-user can possibly insert many rows by hitting the refresh browser button several times. There are many possible solutions to this problem if you do a Google on this topic.

Simple solution

The simplest solution is to do a Response.Redirect("selfPage") from your server side submit button event after processing your request. Many people, including me, just do not use Response.Redirect as a way of navigation to avoid unnecessary server trips.

Multiple submits

Please note: This topic is not about preventing multiple submits on a page. This is about stopping the refresh of a page after you have submitted your request. This is useful in one scenario where after submitting the request, the user disables the submit button so that end-user is not able to do multiple submit clicks. The end-user can still post the results back to the server by hitting the Refresh button on the browser. If you are looking for stopping multiple submits then you can use JavaScript on the client side or use the One Click control.

Conventional solution

The conventional solution is to prevent the user from refreshing the screen by storing session tokens and comparing them with the token stored in the web form through VIEWSTATE through auto post back. This solution is handy if you have enabled auto postback to true. If that is not the case then you may store the variable in a hidden field. A typical solution is given below:

In the PAGE_LOAD event, you store the session token generated after a first submit. In the submit button event, the sessions and the page tokens are compared and if they do not match then it is a case of a refresh button used to submit the same request again.

protected System.Web.UI.WebControls.Button SubmitButton;
protected System.Web.UI.WebControls.Label RefreshID;
private void Page_Load(object sender, System.EventArgs e)
{
    if (RefreshID.Text.Length == 0) 
    {
        RefreshID.Text = Session.SessionID+DateTime.Now.Ticks.ToString();
    }
} 
private void Button1_Click(object sender, System.EventArgs e)
{
    string sesToken = (string) Session[FrameworkConst.SYNC_CONTROL_KEYWORD];
    string pageToken = RefreshID.Text;
    if (sesToken != null && sesToken != pageToken)
    {
        Response.Write("The Refresh was performed after submit.");
    } 
    else
    {
        // do your processing here to avoid Refresh trap
        Response.Write("The processing is done here. Disabling submit 
        button so that user can not perform multiple submit.");
        Response.Write("But still user can peform Refresh on page.");
    }
    Session[FrameworkConst.SYNC_CONTROL_KEYWORD] = 
         Session.SessionID+DateTime.Now.Ticks.ToString();
    RefreshID.Text = sesToken; 
    SubmitButton.Enabled = false;
}

Another solution

Fortunately, ASP.NET provides several ways of reducing coding if we can determine a pattern. The disadvantage with the conventional approach is that we have to include conditions in the submit button event logic to handle the refresh button problem. Suppose your product contains several hundred web forms, and if you need to handle the refresh button logic, then you will have to go and update all the pages. Custom web server control and the HTTP modules provide means to achieve the same functionality. Drop this custom control on the form where you want to disable the refresh button problem. You might not want to do this on every page as sometimes there is a need to allow the refresh button functionality. One such example would be a search page. But you definitely want to include this on pages where you need to perform an Insert/Update/Delete on the database.

Implementation

You need to register the HTTP module in your web.config in the system.web section.

<httpModules>
<add name="SyncHttpModule" type="EAD.Controller.SyncHttpModule, sync"/>
</httpModules>

You need to register this control on a web page.

<%@ Register TagPrefix="cc3" 
    Namespace="EAD.WebControls.Client" Assembly="sync"%>

Drop this control on your form anywhere between your form tags.

<cc3:SyncControl runat="server"></cc3:SyncControl>

You don't need to do any coding in your Web Forms to handle this scenario.

How does it work?

The philosophy for SyncControl to work in tandem with the HTTP module is same as that described in the conventional solution. I like to remove the repetitive code as much as I can from my pages. This gives a better control if we can determine patterns in the code and a way to implement the patterns. In my opinion, if you have a good library of patterns and you use them through your own framework then you can achieve real rapid application development.

We need to set a token first in session and then in request, and compare them to determine if they are different. Through the HTTP handler, we set the token in session. There is an event called PreRequestHandlerExecute in the HTTP pipeline, you can access your session in this event. If you use other events, then the session will not be available so you practically cannot use the BeginRequest event. The token is set in this event and a compare is made between the session and the request tokens and if they are different then it is a case of refresh. Now you can determine what you need to do at this time. I prefer to send the request to a page that tells the user that you have reached this page as you tried to refresh the previous page and allow the user to go back to the previous page.

private void OnPreRequestHandlerExecute(object source, EventArgs e)
{
    HttpContext context = ((HttpApplication) source).Context;
    string _keyword = FrameworkConst.SYNC_CONTROL_KEYWORD;
    string sesToken = (string) context.Session[_keyword];
    string reqToken = context.Request.Params[_keyword];
    if(reqToken != FrameworkConst.BYPASS_SYNC_KEYWORD)
    {
        context.Session[_keyword] = 
        context.Session.SessionID+DateTime.Now.Ticks.ToString();
    }
    if(reqToken != null && reqToken != sesToken)
    {
        string path=context.Request.ApplicationPath+
        &"/Common/SyncControl.aspx?returnUrl="+
        &context.Request.Url.AbsolutePath;
        context.Server.Transfer(path);
    }
}

The SyncControl creates a hidden input field on the form and it sets the value of the hidden field to the session value that was set in the HTTP module.

public class SyncControl : System.Web.UI.WebControls.WebControl
{
    private string _keyword = FrameworkConst.SYNC_CONTROL_KEYWORD;
    bool _bypass = false;
    public bool Bypass
    {
        get { return _bypass; }
        set { _bypass = value;}
    }
    protected override void Render(HtmlTextWriter output)
    {
        StringBuilder outputStr = new StringBuilder();
        string keyword = (_bypass) ? FrameworkConst.BYPASS_SYNC_KEYWORD : 
        (string)this.Context.Session[_keyword];
        outputStr.Append("<!-- ********* Text Generated by 
        &SyncControl ********** -->\n");
        outputStr.Append("<input type=hidden name=\""+ _keyword+"\" 
        value=\""+keyword+"\">\n");
        outputStr.Append("<!-- ********* End of Text Generated by 
        &SyncControl ********** -->\n");
        output.Write(outputStr.ToString());
    }
}

If you do not use SyncControl on pages that do not require this handling, then the page functions in a normal way. There is a milli-little penalty here – this logic in the HTTP module executes every time the server processes a page. There is a much simpler solution than what is described in this article – use Response.Redirect in your submit event if you need to return to the same page. I do not recommend the use of Response.Redirect as a rule, and that is why this control is used.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

vikramk
Web Developer
United States United States
Vikram is an Enterprise Application Architect specializing in EAI, ETL, all relational databases and transforming legacy applications to Microsoft .Net environment. Vikram works for a consulting firm in Research Triangle Park, NC. Vikram has expertise in all relational databases, Cobol, mainframe, OO programming, C, Perl and Linux. C# is a newfound craze for Vikram.

Comments and Discussions

 
QuestionAfter Using it CSS not works PinmemberNourBerro19-Feb-12 0:35 
SuggestionWant a working solution? Pinmemberbgmate27-Oct-11 16:10 
GeneralRe: Want a working solution? Pinmemberbgmate27-Oct-11 16:39 
GeneralUnknown server tag 'cc3:SyncControl' PinmemberSabyasachi7326-May-11 2:36 
GeneralCompatibilty with some components (.NET 2) Pinmembersergentrazor10-Jul-10 0:19 
GeneralMy vote of 1 PinmemberRitesh wagh21-Feb-10 22:13 
GeneralRe: My vote of 1 PinmemberHiren Solanki28-Dec-10 23:00 
Generalwhen use in asp.net2.0,all css and image path are disabled Pinmemberzhouhuanjia20-Jul-08 23:07 
GeneralPage Refresh Checking Duplicate Row Insert Pinmemberenggpalash18-Jun-08 1:20 
GeneralRe: Page Refresh Checking Duplicate Row Insert Pinmembersalihovic26-Oct-09 20:54 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140921.1 | Last Updated 15 Mar 2004
Article Copyright 2004 by vikramk
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid