posts - 225, comments - 305, trackbacks - 56

My Links

News




I am born in Bangladesh and currently live in Melbourne, Australia. I am a co-founder and core developer of Pageflakes www.pageflakes.com and CEO at Simplexhub, a highly experienced software development company based in Melbourne Australia and Dhaka, Bangladesh.

I also created SmartCodeGenerator

Some of my articles
Flexible and Plugin based .Net Application..
Mass Emailing Functionality with C#, .NET 2.0, and Microsoft® SQL Server 2005 Service Broker'
Write your own Code Generator or Template Engine in .NET
Smart Code Generator .NET: Usage Overview
Smart Code Generator .NET: Architectural Overview
Smart Code Generator .NET: using with NAnt and Cassini

Archives

Free Programming Language Training

Smart404: Handle 404 smartly in ASP.NET

Introduction
The 404 or Not Found error message is an HTTP standard response code, there are many reasons for a 404 to show up like,

  • Mistyped URL
  • Pages have been moved.
  • Pages have been deleted.

The default error page for 404 may look something similar to this:

The purpose of this blog/article is to discuss ways to handle 404 smartly in ASP.NET.

So the big question is how? On an event of 404, the first thing I would try do is to catch the event and redirect to somewhere where I can handle it in a more nicer way. In ASP.NET its just a matter of second, simply add the following node in your web.config thats it.

    <customErrors mode="On">
      <error statusCode="404" redirect="~/error404.aspx" />
    </customErrors>

What we have done here is on an event of 404 we are redirecting to a custom "error404.aspx" page.

Now common practice is to display some decent error messages or links on this page, but we can really do lot more than that, one thing to note here is we are redirecting to an ASPX page and we can do smart coding in the code behind file.

  • In an event of mistyped url we can suggest valid pages (Intelligent 404).
  • In case of deleted / moved page we can redirect smartly to the correct page.

Lets look at how we can implement this.

Intelligent 404

To be able to suggest potential valid pages intelligently,

  • First, we need to know what we are searching for.
  • Second, we need to know the available pages in the website.
  • Third, we need to create uri list from the available file list. 
  • Forth, we need to match the page that we are looking for, in the urilist and suggest the potential uris.

Lets look at all this in code:

This is how we can find out what we are looking for:

    string from = Request.QueryString["aspxerrorpath"];
    int index = from.LastIndexOf("/") + 1;
    string search = from.Substring(index).Replace(".aspx", string.Empty).Replace("-", " ");
 

Then we need the list of available files, the following method filters by file extension and return all the list of files (including files in subfolder). 

    private List<string> GetAllFiles(string directory, string filter, bool getFilesInSubDirs)
    {        
        List<string> filesList = new List<string>();
        
        string[] files = null;
        if (filter == null)
        {
            files = Directory.GetFiles(directory);
        }
        else
        {
            files = Directory.GetFiles(directory, filter);
        }
        filesList.AddRange(files);//add all files in that current folder.
 
        if (getFilesInSubDirs)
        {
            //Check if the current directory has sub-directories
            string[] subDirs = Directory.GetDirectories(directory);
            //if yes, then call recursive functions..
            if (subDirs.Length > 0)
            {
                //now look for all files in current folder's sub-dir's.
                foreach (string subDir in subDirs)
                {
                    List<string> tempList = GetAllFiles(subDir, filter, getFilesInSubDirs);
                    filesList.AddRange(tempList);
                }
            }
        }
        return filesList;
    }  

After getting the files we need to turn them into proper uris. 

    public List<string> GenerateUriList(string directory, string rootUri)
    {
        List<string> filelist = GetAllFiles(directory, "*.aspx", true);
        List<string> uriList = new List<string>(filelist.Count);
        foreach (string str in filelist)
        {
            string uri = str.Replace(directory, rootUri);
            uri = uri.Replace(@"\", "/");            
            uriList.Add(uri);
        }
        return uriList;
    }

We also need to be able to match and find the potential uris, like this,

    bool GetMatchingUri(string search, string uri)
    {
        //case in sensitive match
        string term = search.ToLowerInvariant().Trim();
        string[] terms = term.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
        string regex = string.Format(System.Globalization.CultureInfo.InvariantCulture, "({0})", string.Join("|", terms));
        int result = (Regex.Matches(uri.ToLowerInvariant(), regex).Count);
        return result > 0;     
    }

And finally the Suggest() method which uses all the above codes and makes the 404 more intelligent, and suggests potential Uris. You can call this during OnPage_Load event of your error404.aspx.

    public partial class error404 : System.Web.UI.Page
    {
      protected void Page_Load(object sender, EventArgs e)
      {
        if (Request.QueryString["aspxerrorpath"] != null)
        {
            Suggest();
        }
      }
    }

    private void Suggest( )
    {
        string from = Request.QueryString["aspxerrorpath"];
        int index = from.LastIndexOf("/") + 1;
        string search = from.Substring(index).Replace(".aspx", string.Empty).Replace("-", " ");
        //
        string rootDirectory = Request.PhysicalApplicationPath;
        string rawurl = Request.RawUrl;        
        int index1 = rawurl.LastIndexOf('/');
        //Get the virtual root directory.
        string virtualDirectory = rawurl.Substring(0, index1 + 1);
        
        //Get UriList
        List<string> uriList = GenerateUriList(rootDirectory, "");
        foreach (string uri in uriList)
        {   
            if (GetMatchingUri(search, uri))
            {
                LiteralControl result = new LiteralControl(string.Format("<li><a href=\"{0}\">{1}</a></li>", uri, uri));
                phSearchResult.Controls.Add(result);
            }
        }
    }

here phSearchResult is a ASP.NET Placeholder control.

The end result may look something like this, where I intentionally typed an url (localhost/Albums.aspx) which does not exist, notice how the error404.aspx intelligently suggests the correct urls instead. 

 

Redirecting smartly to the correct Page

Another common responsibility of a Web Admin is to be able to point to the right pages when there is a change/move/rename/delete of existing pages. The referers/search engines may still cache the old url and use it, but the website need to handle this situation and properly redirect to the correct page/pages. In ASP.NET this is again pretty easy, by using the same technique mentioned above we can redirect the page to error404.aspx and handle this in the code behind file.

To achieve this, first thing we need is some sort of database/xml where we can define old and new url mappings.

<?xml version="1.0"?>
<ArrayOfUrlMap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <UrlMap>
    <OldUrl>?404;http://www.mysite.com/albums.htm</OldUrl>
    <NewUrl>~/Albums.aspx</NewUrl>
  </UrlMap>
  <UrlMap>
    <OldUrl>?aspxerrorpath=/albums.html</OldUrl>
    <NewUrl>~/Albums.aspx</NewUrl>
  </UrlMap>  
</ArrayOfUrlMap>

Note, I have put two types of url, the reason is, IIS and ASP.NET development Server generates different urls. 

 
    string queryString = Request.Url.Query.ToString();
    //result of the above line will be different based on IIS of ASP.NET
    //?404;http://www.mysite.com/albums.htm (generated by IIS)
    //?aspxerrorpath=/resume.html (generated by ASP.NET development Server)

Secondly we need to match the oldUrl with the list in the database/xml and redirect to the right location.

    protected void Page_Load(object sender, EventArgs e)
    {
        string queryString = Request.Url.Query.ToString();
        string match = FindMatchingPage(queryString);
        if (match != null)
        {
          //Set the Response status code to 301 (Moved Permanently)
          //redirect to the new Url
        }
        else
        {
            //Do Something else ie Suggest()
        }
        Response.End();
    } 
    private string FindMatchingPage(string queryString)
    {
      //search in your db/xml
      //if (queryString == oldurl)
      //return matching new url
    }
    
And thats it we are done.
 

Conclusion

In ASP.NET its very easy to handle 404, I have just demonstrated 2 smart ways of handling 404.
I hope this helps and thank you for being with me so far.

Print | posted on Tuesday, October 23, 2007 8:06 PM |

Feedback

Gravatar

# re: Smart404: Handle 404 smartly in ASP.NET

Thank you Shahed,

Not only is this very clear but also works and is useful.

Cheers,

Jon
11/9/2007 9:28 PM | Jon Byron
Gravatar

# re: Smart404: Handle 404 smartly in ASP.NET

We have the same setup on our site and the requested page is returned in the aspxerrorpath query string but i have not been able to get to the query strings requested in the original url. As an example if i browse :wwwmyhost.com/mydir/mypage.aspx?id=something I do not get back id=something back in the aspxerrorpath querystring. If there is a way to get it please let me know.
5/22/2008 3:17 AM | Vish
Gravatar

# re: Smart404: Handle 404 smartly in ASP.NET

Hİ CAN TIU CORRECT MY SITE I HAS http://turkiye.ecd.cc/error404.aspx PROBLEM HOW CAN I CORRECT İT CAN YOU SHOW ME WAY OR CAN YOU THAT? PLEASE ANSWER
5/26/2008 6:37 PM | master
Gravatar

# re: Smart404: Handle 404 smartly in ASP.NET

Thank you very much
10/18/2008 11:28 PM | Dinesh
Gravatar

# re: Smart404: Handle 404 smartly in ASP.NET

Its nice code, but I don't see how it properly returns a status code of 404. Search engines need to see a 404 code returned if you want them to remove the page from their database. When I setup one of my sites with google webmaster tools it pointed this out to me.
5/25/2009 12:07 PM | Strip Clubs
Gravatar

# re: Smart404: Handle 404 smartly in ASP.NET

Thank you, but I think you are talking about 301 redirection here, instead of just 404. If our site/page is moved we need to do a 301 redirection, which indicates that the previous URL has been permanently removed and all future requests should be directed to the given new URL. Here we have handled only 404, where we assumed the URLs are invalid and not need to handle 301.
5/25/2009 1:35 PM | Shahed Khan

Post Comment

Title  
Name  
Email
Url
Comment   

Powered by: