Search code examples
asp.nethttp-status-code-404rebaseradixrebasing

How do you rebase hyperlinks and content in an ASP.NET page?


I have an ASP.NET page to handle "404 page not found" it's setup by configuring the <customErrors> section in my web.config file and setting the custom error page for 404 errors in IIS manager.

It works as expected for pages in the root of my website but doesn't work in a subdirectory of the site - the hyperlinks and content in my custom error page have the wrong url base.

All the links in my error page are server-side controls (runat="server") and have their links based with "~/".

When I browse the site with http://mysite/nosuchfolder/nosuchfile the page renders with links thinking it's being served from the root, rather from nosuchfolder and as such all the links are broken in the browser as the browser is basing links from nosuchfolder.

Is there any way to 'tell' the ASP.NET page to re-base links on a different folder/filename?

Notes:

  • The majority of the page template is rendered from a master page
  • I'm running IIS6 and have set custom error 404 to URL: /error404.aspx
  • In my web.config file I have configured the <customErrors> section to redirect to /error404.aspx
  • As a workaround I am using the HTML <base> tag in the page, but I want to avoid this
  • I don't want to have to change all my "~/" based links to "/" or an in-line basing hack

Solution

  • Scott Gu's article on URL rewriting put me on the right path (so to speak!) - thanks for the tip James.

    The answer is to use Context.RewritePath(newPath)

    Here is the code I use in my custom 404 page -

    protected override void Render(HtmlTextWriter writer)
    {
        string rebase = Server.UrlDecode(Request.ServerVariables["QUERY_STRING"]);
    
        if (rebase.Length>10 && rebase.StartsWith("404;"))
        {
            try
            {
                rebase = new Uri(rebase.Substring(4)).AbsolutePath;
            }
            catch
            {
                rebase = "/";
            }
            finally
            {
                Context.RewritePath(rebase);
            }
        }
    
        base.Render(writer);
        Response.StatusCode = 404;
    }
    

    To handle missing .aspx pages in the same way, there is a setting in web.config called redirectMode that you set to ResponseRewrite

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

    This stops the default behaviour of redirecting the user to ~/error404.aspx?aspxerrorpath=badfile

    Note: this setting is new to the latest ASP.NET service packs (e.g. Framework 3.5 SP1)

    MSDN Reference for redirectMode