ﻁ DevExpertise » Blog Archive » ASP.NET Tip/Trick: Use a Base Page Class for All Application Pages

DevExpertise

Practical tips and tricks for all things .NET, SharePoint, Silverlight, InfoPath, and general application development.

viagra pfizer kaufen http://www.fiabci-asiapacific.com/?Nty=1... http://www.fiabci-asiapacific.com/?Nty=1...
http://www.cricyt.edu.ar/?itemid=93362&s... achat viagra en france venta de tadalafil
http://wrkc.kings.edu/index.php?Name=399... cialis en europe cialis ficha tecnica
achat cialis inde http://www.isg.rhul.ac.uk/akay/teaching/...
acheter cialis tadalafil acheter du viagra en espagne
vente viagra rapide tadalafil generico españa cialis günstig
foro kamagra contrareembolso http://www.cerphi.net/?size=83183&price=... beställ kamagra vendo viagra on line ordina cialis viagra sur le net forum

ASP.NET Tip/Trick: Use a Base Page Class for All Application Pages

Posted by DevExpert on March 25th, 2009

All coders worth their salt know that duplicating code isn’t a best practice, and you should consolidate and leverage object inheritance where necessary.  When done correctly, this promotes better maintainability and a better overall application.

I’ve been doing a lot of straight ASP.NET application programming lately, and no matter how many ASP.NET applications I write, I always use a certain number of common methods in my pages’ code-behind.  For example, I get and set view state values, I retrieve values from the cache, or verify query strings have been included.  Because I’m doing these same types of things in most of my pages, it makes sense to include a lot of the leg work in a base class that each of my pages can inherit.  This blog post will provide you the default base class I always start with, and will explain and demonstrate a few of the methods.

At a high level, my base class is divided into the following four regions:

image

Query String Methods
Let’s take a look at the Query String Methods first.  Many pages will have support for query strings, and most of the time these query string values will need to be validated.  Consider a scenario where you are accessing data from a database, and you navigate to a page with a URL of http://webapp/page.aspx?id=10.  You pull out the ID query string value and pass that in as a parameter and retrieve the appropriate results.  But what if you modify the query string value and access a page with a URL of http://webapp/page.aspx?id=abc?  Are you checking to make sure the value is numeric? Are you even checking to make sure an ID query string has been specified?  Well, you should!  A lot of this logic can be wrapped in a base class, and through the use of inheritance and overridden methods, the specific logic can be written. 

I have three methods declared in my base class:

  • RequiredQueryStrings: Returns a list of all required query string keys.
  • CheckQueryStrings: Ensures all required query strings have been specified.
  • CheckQueryStringValues: Ensures the specified query string values are actually valid.

These methods are declared as follows:

/// <summary>
/// When overriden, returns a list of all required query string keys
/// </summary>
/// <returns></returns>
protected virtual List<string> RequiredQueryStrings() {
    return null;
}

/// <summary>
/// When overriden, checks the actual values of query strings
/// </summary>
/// <returns></returns>
protected virtual bool CheckQueryStringValues() {
    return true;
}

/// <summary>
/// Verifies the required query string are actually present
/// </summary>
/// <returns></returns>
protected bool CheckQueryStrings() {
    List<string> values = RequiredQueryStrings();

    if (values == null || values.Count == 0) {
        return true;
    }
    else {
        foreach (string value in values) {
            if (Request.QueryString[value] == null) {
                return false;
            }
        }
    }

    return true;
}


In addition to these methods, my base page’s Init method checks these methods and depending on the results, allows the rest of the code to run or redirects you to an error page:

protected override void OnInit(EventArgs e) {
    base.OnInit(e);

    if (!CheckQueryStrings()) {
        // all required query strings have not been specified
        RedirectToPage("Error.aspx");
    }

    if (!CheckQueryStringValues()) {
        // one or more query string values are invalid
        RedirectToPage("Error.aspx");
    }
}


To use this, I simply inherit my application pages from my PageBase class, and override the appropriate methods:

public partial class ViewWidget : PageBase {

    protected override List<string> RequiredQueryStrings() {
        List<string> values = new List<string>();
        values.Add("widgetID");

        return values;
    }

    protected override bool CheckQueryStringValues() {
        int widgetID = 0;
        int.TryParse(Request.QueryString["widgetID"].ToString(), out widgetID);

        return (widgetID > 0);
    }

    protected void Page_Load(object sender, EventArgs e) { }
}


Notice all I’m doing is overriding the base class methods, and specifying the things that are required.  It’s up to the base class to do the actual error handling, which in my case involves navigating to an error page.  The important thing to note is that the error handling logic is declared in ONE place.  Each individual page is only responsible for identifying the values that should be checked.

Now, when I access my ViewWidget.aspx page with a valid URL, such as http://webapp/ViewWidget.aspx?widgetID=10, I get the following page:

image


If I access it with an invalid URL, such as http://webapp/ViewWidget.aspx?widgetID=xyz, I get redirected to the error page:

image

 

Redirection Methods

Chances are your web application contains more than just one page, and you will have to navigate to other pages.  Once in awhile ASP.NET will throw a ThreadAbortException when redirecting to another page, which doesn’t matter, and we don’t really need to do anything when that occurs.  My redirection methods consist of two methods:

  • RedirectToPage: Redirects to a page and ignores the exception that is sometimes thrown.
  • RedirectToPageWithQueryStrings: Redirects to a page and includes all current query string keys and values.  Since this method ultimately calls RedirectToPage, any exception is also ignored.

These methods are declared as follows:

/// <summary>
/// Redirects the application to the specified page, and ignores the 
/// erroneous error that is sometimes thrown
/// </summary>
/// <param name="url"></param>
protected void RedirectToPage(string url){
    try{
        Response.Redirect(url);
    }
    catch{
        // catch the ThreadAbortException that is occasionally thrown by ASP.NET
    }
}
/// <summary>
/// Redirects to another page and carries over all current 
/// query string keys and values
/// </summary>
/// <param name="url"></param>
protected void RedirectToPageWithQueryStrings(string url) {
    string queryStringList = string.Empty;

    if (!string.IsNullOrEmpty(url)) {
        if (Request.QueryString.Count > 0){

            // rebuild the query string list
            for(int i = 0; i < Request.QueryString.Count;i++){
                queryStringList += string.Format("{0}={1}&", 
                    Request.QueryString.GetKey(i), Request.QueryString.Get(i));
            }

            // remove the erroneous ampersand
            queryStringList = queryStringList.TrimEnd(new char[] { '&' });

            // append the '?' to the beginning
            if (!string.IsNullOrEmpty(queryStringList)) {
                url = "?" + queryStringList;
            }
        }

        RedirectToPage(url);
    }
}

 

View State Methods

I utilize view state occasionally, and have included a couple methods to help manage this:

  • GetViewStateValue: Retrieves a value from view state, and if it doesn’t exist returns the specified default value.
  • SetViewStateValue: Sets a view state value.
  • ClearViewStateValue: Clears a view state value.

These methods are declared as follows:

/// <summary>
/// Retrieves a value from ViewState
/// </summary>
/// <param name="key"></param>
/// <param name="defaultValue"></param>
/// <returns></returns>
protected object GetViewStateValue(string key, object defaultValue) {
    return ((ViewState[key] == null) ? defaultValue : ViewState[key]);
}

/// <summary>
/// Sets a value in ViewState
/// </summary>
/// <param name="key"></param>
/// <param name="val"></param>
protected void SetViewStateValue(string key, object val) {
    ViewState[key] = val;
}

/// <summary>
/// Clears a value from ViewState
/// </summary>
/// <param name="key"></param>
protected void ClearViewStateValue(string key) {
    ViewState[key] = null;
}

 

Cache Methods

I also leverage the application cache, and have included a few methods to help manage this as well:

  • GetCachedItem: Retrieves a value from the application cache, and if it doesn’t exist returns null.
  • SetCachedItem: Adds an item to the application cache.
  • ClearCachedItem: Removes an item from the application cache.

These methods are declared as follows:

/// <summary>
/// Returns an item from the application cache
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
protected object GetCachedItem(string key) {
    object returnValue = null;

    try {
        returnValue = Cache.Get(key);
    }
    catch { }

    return returnValue;
}

/// <summary>
/// Adds in item to the application cache
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="minutes"></param>
protected void SetCachedItem(string key, object value, int minutes) {
    try {
        Cache.Insert(key, value, null, 
            DateTime.Now.AddMinutes(minutes), TimeSpan.Zero);
    }
    catch { }
}

/// <summary>
/// Clears an item from the application cache
/// </summary>
/// <param name="key"></param>
protected void ClearCachedItem(string key) {
    try {
        Cache.Remove(key);
    }
    catch { }
}

 


These are just a few of the methods that are good candidates for placement in a base class.  You could just as easily as methods to manage session variables, or some other type of common functionality in your application.  The point is to identify places where you can simplify and reuse code.  This will make it much easier to develop, maintain, and enhance in the future.

I’ve included my base page in the ZIP file below.  As always, my code is provide as-is and without warranty!

Download: PageBase.zip

21 Responses to “ASP.NET Tip/Trick: Use a Base Page Class for All Application Pages”

  1. Olikh Says:

    For these purposes I use a Common project in my every solution.
    - COmmon
    - – QueryStrings utils
    - – ViewState utils
    - – Strings utils
    etc.

    In this case there is no need to copy the code but just to add a reference to the project.

    Thank you for the post!

  2. Alex Says:

    You should use Generic methods feature to get and set values from/to viewstate.
    Will be helpful!

    Alex.

  3. Jason Allgood Says:

    In your RedirectToPageWithQueryStrings method, shouldn’t you be checking the Request.QueryString to see if it is null or empty instead of the queryStringList? You just set queryStringList to String.Empty in the line of code before, so how is it to be anything but empty? Also, if it is null or empty, does the page not get redirected to the original url? There is no else statement to handle this.

  4. Emmanuel Says:

    Hmm… you’re swalling exceptions? And ScottGu linked to you, too…

  5. Emmanuel Says:

    That is to say: “swallowing”.

  6. Shail Says:

    Hello,
    It seems a nice idea to have a common PageBase class for all pages in an application. But I have these questions.

    1. Will it will work perfectly with MasterPages and themes ? I hope if I will use this nothing will break. Like I want to do this in my on going application.
    2. Any effects on Even Handlers ?
    3. Once I have the PageBase class, will all the functions will be seen in Intellisense of aspx page ? I am using VS 2005

    Thanks
    Shail

  7. DevExpert Says:

    Jason, you are absolutely right — I meant to verify ‘url’ is not null or empty. I’ve updated the post to reflect this. Thanks for catching that!

  8. DevExpert Says:

    Shail,
    1. This will work fine, as long as you don’t inherit your master page class from this class — they’re 2 different types of classes. This will only work for ASPX application pages. As long as you inherit only your ASPX pages, it shouldn’t break anything.
    2. Nope, this approach doesn’t do anything to break event handlers. Keep in mind that you’re already using inheritance and using a base page class (the System.Web.UI.Page) when you’re creating ASPX pages. The only difference here is you’re adding another layer between that class and your ASPX pages. Ultimately though, every page will still inherit from System.Web.UI.Page.
    3. Yep, IntelliSense will pick these methods up.

    Good luck!

  9. Mike Ohlsen Says:

    Why not use Response.Redirect(url, false)? This will prevent the ThreadAbortException from being thrown and allow processing to continue with calling Response.End.

    http://msdn.microsoft.com/en-us/library/a8wa7sdt(VS.80).aspx
    http://support.microsoft.com/default.aspx?scid=kb;en-us;312629

  10. DevExpert Says:

    Mike — why didn’t I use that? Because I didn’t know it existed! *Insert newbie comment here*

    Thanks a million for pointing this out!!

  11. Mike Ohlsen Says:

    DevExpert, you just have to be careful. using Response.Redirect(url, false) means execution continues. Any code after Response.Redirect (which you dont have any in your example) and in later page events will still fire. So you have to be aware.

  12. Hilton Giesenow Says:

    Nice post, some great tips! My only problem with a new base class is that developers can forget to do it. Some other possible solutions are overriding the default Visual Studio templates, and using Extension Methods. I’ve got a complimentary idea on using PageAdapters to do some similar things that might be of interest.

  13. Thomas Haggren Says:

    Great article :)

    Here is a good article about the “Response.Redirect(url) ThreadAbortException” http://www.c6software.com/CodeSolutions/dotnet/ThreadAbortException.aspx

  14. DevExpert Says:

    Good stuff — thanks for the info!!

  15. DevExpert Says:

    Hilton, very interesting. I hadn’t even considered page adapters for this. I’ll definitely keep it in mind for future projects. Thank you!

  16. Ram Chandra Nagar Says:

    Hi this is use full if you are working on web based application realy its reduse code redudency
    thanks

  17. jyest Says:

    Hi, it’s a really helpful article to me,

    Just 1 question, I use vb.net, and when I try to use following code in my code, I got a dead loop

    ‘If the URL is modified
    Private Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
    ‘mybase.OnInit(e) will invoke Page_Init
    MyBase.OnInit(e)
    End Sub

    Any ideas or suggestions? thanks

  18. Antwan Hussain Says:

    Thank you for the good blog entry on working in home. I appreciate it. Thanks!

  19. Sabina Orofino Says:

    Which is actually fairly vital for what I’m appear at now, thanks a bunch.

  20. DaNTheatR Says:

    Nice post, very helpful!

    In your RedirectToPageWithQueryStrings method, shouldn’t you be adding the queryStringList to the ‘url’ argument instead of replacing it with the ‘?’ followed by queryStringList?

    url = "?" + queryStringList; should be url += "?" + queryStringList;

    Thanks!

  21. PRK Laser Eye Surgery Says:

    :~* I am very thankful to this topic because it really gives up to date information .’.

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>