Click here to Skip to main content
Click here to Skip to main content

Refresh Module

, 29 May 2007
Rate this:
Please Sign up or sign in to vote.
How to make a browser's refresh manageable

Requirements

All code in the example application is intended to be run using .NET 2.0 only. There is no solution for the 1.0/1.1 versions.

Introduction

Most of you are familiar with the feature of all web-browsers that when you press the F5 button, the content of a page is refreshed. After the F5 button is pressed, the browser repeats the previous request to the page. Nothing wrong will actually happen when the previous request is made by the GET method. However, problems appear when the last request is made by the POST method. Let's consider an example where a user is transferring money to a shop to pay for some goods. Having completed this operation, the user refreshes the page and as a result the server code is executed once again with the same data. Thus, the user may accidentally pay twice.

Where are we going?

The purpose of this article is to give you a generic tool to improve your application. Moreover, you will not need to change the application code. If you have a good MVC framework, you can read this article just to find out how people work in worse conditions than you do. This article is intended for those who develop their application without any MVC frameworks or previously developed supporting applications. It will teach you how to make any page refresh manageable.

Here we go…

Since standard ASP.NET functionality doesn't allow us to track the process of refreshing the page, we should add this functionality ourselves. For this purpose we will use an HTTP module. Also, it's obvious that we should store some marker on a client. Then later we will be able to recognize whether the current request is due to the user having refreshed the page or due to the page being "valid."

basic schema

We have just defined our core algorithm. This simple condition will regulate all of our further steps. Note that the module does nothing when a page is requested by the GET method. This is our second rule.

How to use the Refesh module

First of all, we need to modify Web.config for ASP.NET to see the RefreshModule module and call it.

<system.web>
    <httpModules>
        <add name="RefreshModule" 
            type="RefreshModule.Module, RefreshModule"/>
    </httpModules>
</system.web>        

Than we need to add a reference to the RefreshModule assembly, as well as add the using statement.

using RefreshModule;

It's enough to get information when a page is being refreshed. Now we can use the RefereshHelper.IsPageRefreshed property, which can be checked to determine that the page is refreshed.

[Refresh()]
public partial class Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
         if(IsPostBack && !RefereshHelper.IsPageRefreshed)
        {
            // do some work with the submitted date
        }
        else
        {
            
           // do some work when the page is loaded with the GET method
        }
    }
}

At first it looks great that we can recognize any refresh request while a page is executed. Actually, this approach suits better for new pages due to the fact that we know about this functionality. For existing pages, however, we have to reorganize the code. What if we don't care that the manual refresh handling or the code of our page is complex and we don't want to change anything? In this case, we should modify the attribute slightly to get automatic refresh handling.

[Refresh(AutoRedirect = true)]
public partial class Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
    }
}

When the RefreshModule module intercepts a request, it checks whether the automatic refresh handling is needed or not. This is the simplest automatic handling case when the RefreshModule module performs redirection to the same page after any postback is completed. The biggest disadvantage of this approach is the additional round trip from a client to the server. So, this approach should be only suggested for using with "lightweight" pages. How can we improve this situation? What if we want to show some additional information to a user? It's easy to implement. All we need to do is to keep modifying the RefreshAttribute attribute.

[Refresh(MessageModulePath = "MessageControl.ascx")]
public partial class Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
    }
}

We pointed to control that will be loaded -- and its output sent to a browser as a response -- while the page is being refreshed. Actually, RefreshModule builds a valid response page based on a template which you can modify as needed. This template is defined in the RefreshModule code. If we want to customize the appearance by applying styles or adding JavaScript code, we should implement the INotificationProvider interface and register it. We can do this as follows.

public interface INotificationProvider
{
   string Title
   {
      get;
   }

   string HeadHTML
   {
      get;
   }
}

//This is a very simple example
public class NotificationProvider : INotificationProvider
{
    public string Title
    {
        get { return "Custom title"; }
    }

    public string HeadHTML
    {
        get
        {
            return
                @"<link rel=""STYLESHEET"" type=""text/css"" 
                    href=""styles.css"">
                <style>
                #info table{
                    margin: 100px 0px 0px 200px;     
                }
                </style> 
             ";   
        }
    }
}

void Application_Start(object sender, EventArgs e) 
{
   RefereshHelper.RegisterNotificationProvider(new NotificationProvider());

}

It's going well so far. So let's go ahead and learn how to show a better result to the user. To do that, we have to take these steps:

  • Create an empty page which will be used as a template for notification messages.
  • Add the RefreshUIAttribute attribute to the page.
[Refresh(MessageModulePath = "Notification.ascx")]
[RefreshUI("__RefreshTemplate.aspx", "ContentPlaceHolder1")]
public partial class SmartAttributeNotification : Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }
}

The RefreshUIAttribute attribute has two parameters: template page path and container for the notification control, as defined by applying the RefreshAttribute attribute. One issue that arises here is the generation of an additional page or pages which are not necessarily supposed to be viewed by the users. To make viewing the template pages impossible, I recommend using complex names for such pages and placing them in a separate folder, e.g. [RefreshUI("RefreshTemplates/_CDFECE8A56874700877B0C22D256E0CD_.aspx", "ContentPlaceHolder1")]. This URL is much better protected from being accidentally viewed. On the other hand, it is easier to make a mistake while typing a URL like this one. Fortunately, the RefreshModule supports another method of defining a template page and container.

[Refresh(MessageModulePath = "Notification.ascx")]
//[RefreshUI("__RefreshTemplate.aspx", "ContentPlaceHolder1")]
public partial class SmartIntrefaceNotification : Page, 
    IRefreshWith<UISample> 
{
    protected void Page_Load(object sender, EventArgs e)
    {
      
    }
}

As you can see, the page inherits a generic IRefreshWith<T> interface. That interface doesn't contain any method and is used only as a marker. Real values are defined in the interface's typed parameter. In the example, the actual date is passed through the UISample class which implements the IUIProvider interface. Note that when a template page is executed, the RefreshModule replaces the action attribute value of the <form> tag with the original request's URL. See the example application for more details.

Summary

Now you have a tool that will help you to make your application appear and work more professionally. I didn't want to make this module complex with extraneous features and settings, so it should take you just a couple of simple steps to get it working. If you need more features or customization possibilities, it's better to use any well-know application framework. Below you can find two screenshots of a test application.

Figure 1: Test page after submit is completed

test page

Figure 2: Automatic response result

custom response result

History

  • 18 May, 2007 - Original version posted

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

Valery_Minsk

Belarus Belarus
No Biography provided

Comments and Discussions

 
GeneralGreat article~! Pinmemberkwang-sik Jeon3-Sep-09 18:05 

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.140826.1 | Last Updated 29 May 2007
Article Copyright 2007 by Valery_Minsk
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid