ASP.NET: Detecting Page Refresh

Link

Page Refresh

12.11.2004
Introduction

A common problem that Web Application Developers encounter is how to stop the user from refreshing the page. This is a problem if the previous request to the server was a PostBack, which, for example, inserted the WebForm’s data into a database. The result: duplicate rows in the database. The answer to this problem is that you can’t stop the user from refreshing the page, however there is a way to determine if this event has occurred.

In his article “Build Your ASP.NET Pages on a Richer Bedrock” Dino Esposito outlined a mechanism to detect a page refresh. This method is cumbersome and more complicated than necessary, although the fundamental idea is sound and forms the basis of this solution. Dino’s mechanism uses a counter stored on the page and a session variable to store the previous request’s counter on the server, if the two match then we have a page refresh.
A Simpler Method

Keeping the whole process within a base Page Class ensures that the mechanism is completely encapsulated (and simple to implement) and if we use ViewState we eliminate the need to use an additional hidden field. Also, as we simply want to test if the two storage devices contain the same value, we can use two boolean variables, which further simplifies the process.

The last decision to make is where, in the Page’s lifecycle, should the process take place. As we are using ViewState it would seem logical to perform the operation in the LoadViewState and SaveViewState methods. Using these two methods, and not the OnLoad method, has further benefits in that it eliminates potential problems with sub-classes implementing Page_Load.
How The Process Works

The LoadViewState method, which is part of the Page’s initialisation phase, is only invoked during PostBack and therefore SaveViewState is the only method, of the two ViewState related methods, to be called when the page is first requested.

protected override object SaveViewState()
{
Session["__ISREFRESH"] = _refreshState;
object[] allStates = new object[2];
allStates[0] = base.SaveViewState();
allStates[1] = !_refreshState;
return allStates;
}

Note: _refreshState (which on initial page request is defaulted to false and on subsequent PostBack requests is the value of ViewState) is assigned to the Session["__ISREFRESH"] item and the negated _refreshState is saved to the new ViewState.

Once a PostBack event takes place the LoadViewState method is called.

protected override void LoadViewState(object savedState)
{
object[] allStates = (object[]) savedState;
base.LoadViewState(allStates[0]);
_refreshState = (bool) allStates[1];
_isRefresh = _refreshState == (bool) Session["__ISREFRESH"];
}

Note: The _refreshState is retrieved from ViewState and compared with the value in the Session["__ISREFRESH"] item. The result is stored in _isRefresh, which is used by the IsRefresh Property.

The listing below shows the entire class definition:

namespace StevenBey.Web.UI
{
public class Page : System.Web.UI.Page
{
private bool _refreshState;
private bool _isRefresh;

public bool IsRefresh
{
get
{
return _isRefresh;
}
}

protected override void LoadViewState(object savedState)
{
object[] allStates = (object[]) savedState;
base.LoadViewState(allStates[0]);
_refrehState = (bool) allStates[1];
_isRefresh = _refreshState == (bool) Session["__ISREFRESH"];
}

protected override object SaveViewState()
{
Session["__ISREFRESH"] = _refreshState;
object[] allStates = new object[2];
allStates[0] = base.SaveViewState();
allStates[1] = !_refreshState;
return allStates;
}
}
}

Testing The Process

<%@ Page Inherits="StevenBey.Web.UI.Page" %>

IsRefresh = <%= IsRefresh %>

Clicking the “Test Refresh” button invokes a PostBack, however the value of IsRefresh doesn’t change until you click on the browser’s Refresh button or press F5 on the keyboard (and then click “Retry”). Clicking the “Test Refresh” button once again resets the value of IsRefresh to false.

Live Demo

Conclusion

In this article I have demonstrated a simplified method of detecting a page refresh event.

Download the files used in this this article.

This entry was posted in Uncategorized. Bookmark the permalink.
  • Zubair Ahmed

    Hi,

    Could you provide the VB.NET code for the above, please?

  • Joep

    Hi,

    I like the idea but unfortunately it will not work when users also use Back in the browser.
    Suppose the page has 2 buttons that cause postbacks, Button1 inserts the record when it is not a refresh, and Button2 does some other action.
    The scenario is:
    1. open the page (saves viewstate)
    2. press Button1 (loads and saves viewstate)
    3. press Button2 (loads and save viewstate)
    4. press Back (restores previous viewstate client side)
    5. refresh the page, and a second record is inserted

    Due to the Back, the viewstate is toggled while the boolean in the session is not toggled, hence IsRefresh makes the wrong decision.

  • Curca

    Thank you very much for your suggestion.
    It’s works.
    It’s more easy than Dino’s solution.

    Good bye

    Enzo & Luigi

  • karthikeyan

    it is work only while page is refereshing it displays message box(retry)
    otherwise it doenot work if there is no message box(retry)while page is refereshing

    Tec notes—if client has data it makes message box(retry) while page is refereshing

  • I realise that this is almost 2 year since this have been posted but I have only just come across this page and want to address the comment by Zubair Ahmed.

    The behaviour, whereby pressing the Back button causes the ViewState and Session to become synchronised, would happen with any mechanism to detect a page refresh. The reason for this is that using a HiddenField or ViewState is the only way in which the process can work and the action of pressing the Back button cannot be detected/counteracted on the server. A possible solution is to use Response.Redirect, which would effectively do a clean refresh, thereby ensuring the Session and page are not in synch. However, I haven’t tested this theory and cannot say that it is a definitive solution.

    It is useful to have a mechanism that detects a page refresh, however, it cannot be the only solution to be employed. For example, in my example at the beginning of the article is talked about inserting data into a database. The best solution to prevent this from happening is to ensure that the data doesn’t exist in the database, before performing the insert.

  • smithersgs

    It’s been posted for a long time, but for anyone intereted in VB version look at…
    http://www.codeproject.com/aspnet/Detecting_Refresh.asp

  • wills

    Here is how I’m using your example. However, I encountered an error – see below the code. Do I need to
    call SaveViewState() in pageload when the page is 1st requested?

    protected void Page_Load(object sender, EventArgs e)
    {
    //control postback
    if (!Page.IsPostBack)
    {
    //
    }
    if (Page.IsPostBack)
    {
    //
    }
    //clear page history
    DestoryPageHistory();
    }

    protected void btnSubmit_Click(object sender, EventArgs e)
    {
    try
    {
    LoadData();
    }
    catch (Exception ex)
    {
    Utilities.LogError(ex);
    Response.Redirect(“error.aspx”);
    }
    }

    public void LoadData()
    {
    //trap refresh to prevent duplicate entries
    if (IsRefresh == true)
    {
    //clear, destroy, redirect
    ClearForm();
    DestoryPageHistory();
    Response.Redirect(“default.aspx”);
    }
    else
    {
    try
    {
    sql insert – nothing special
    ClearForm();
    DestoryPageHistory();
    }
    catch (Exception ex)
    {
    Utilities.LogError(ex);
    Response.Redirect(“error.aspx”);
    }
    }
    }

    protected void ClearForm()
    {
    //clear form fields – nothing special
    }

    protected void DestoryPageHistory()
    {
    //destroy page history
    Response.Expires = 0;
    Response.ExpiresAbsolute = DateTime.Now;
    Response.CacheControl = “no-cache”;
    }

    #region”TrapRefresh”
    private bool _refreshState;
    private bool _isRefresh;

    public bool IsRefresh
    {
    get
    {
    return _isRefresh;
    }
    }

    protected override void LoadViewState(object savedState)
    {
    object[] allStates = (object[])savedState; //
    base.LoadViewState(allStates[0]);
    _refreshState = (bool)allStates[1];
    _isRefresh = _refreshState == (bool)Session[“__ISREFRESH”];
    }

    protected override object SaveViewState() //put in pageload when it is 1st requested?
    {
    Session[“__ISREFRESH”] = _refreshState;
    object[] allStates = new object[2];
    allStates[0] = base.SaveViewState();
    allStates[1] = !_refreshState;
    return allStates;
    }
    #endregion
    ———————–

    Error:
    Event Type: Warning
    Event Source: ASP.NET 2.0.50727.0
    Event Category: Web Event
    Event ID: 1309
    Event code: 3005
    Event message: An unhandled exception has occurred.
    Exception type: NullReferenceException
    Exception message: Object reference not set to an instance of an object.

    Stack trace: at _Default.LoadViewState(Object savedState)
    at System.Web.UI.Control.LoadViewStateRecursive(Object savedState)
    at System.Web.UI.Page.LoadAllState()
    at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

  • matilda

    YouTubeRobot.com today announces YouTube Robot 2.0, a tool that enables you to download video from YouTube.com onto your PC, convert flv files to various video formats to watch it when you are on the road on mobile devices like mobile phone, iPod, iPhone, Pocket PC, PSP, or Zune.Product page:youtuberobot.com
    Direct download link: youtuberobot.com/download/utuberobot.exe
    Company web-site: youtuberobot.com
    E-mail: support@youtuberobot.com

  • smatcoder

    Do you want to Learn Sharepoint ???

    Learn Share Point freely

    http://hotsoftwareslist.blogspot.com/2007/10/learn-sharepoint-freely.html

    Download EBooks Freely in .pdf,.chm formats and ready for interview questions….

    http://hotsoftwareslist.blogspot.com/2007/08/download-ebook.html

  • HttpContext.Current.Items.Add(“test”, search)
    Response.Redirect(“test.aspx”, True)

    it works fine with server.transefer and when page load….
    it lost data when page is postback any help!