UrlRewrite – Virtual Directories and the Tilde

Last week I was making some SEO changes to one of the projects I’m working on when I ran into a problem using the tilde specifier in my runat=”server” URLs. For example,

<asp:HyperLink
     ID="m_hlContedit"
     runat="server"
     NavigateUrl="~/tools/ContentEdit/Menu.aspx"
     >Site Admin Home</asp:HyperLink>

Instead of the ~ resolving to the application directory, it was resolving to the directory the browser thought I was in. This was cause by the fact that I was doing a UrlRedirect from a subdirectory to an ASPX file in the root of my application while handling a 404 error. But the ASPX file was in the root directory. So .NET thought I was in the root directory of my application while the browser thought I was in some sub directory.

For an example of how to create virtual directories and UrlRewrites, see my previous article,

http://blog.dmbcllc.com/2008/07/17/virtual-files-using-httpcontextrewritepath/

Since I searched all over the Internet looking for a built in way to solve this problem, I came to the conclusion that, at least as far as ASP.NET 2.0 is concerned, there is no easy fix. Which leaves me with no other way of fixing the problem than with brute force.

Since I already had code that gave me the application directory, all I really needed to do was iterate over all the controls, look for the ones that had URLs (HyperLink, Image, and ImageButton, in my case) and replace the tilde with the application directory.

The first thing we need to consider is how we obtain the application directory. I do it with this code:

applicationDirectory = Request.ApplicationPath;
if (!applicationDirectory.StartsWith("/"))
    applicationDirectory = "/" + applicationDirectory;
if (!applicationDirectory.EndsWith("/"))
    applicationDirectory = applicationDirectory + "/";

I then call a method that gets called recursively

fixupHrefs(this.Controls);

You might be tempted to put this block of code in Page_Load() which may work for you. However, to have code that will work in every scenario, that is, code that has the URL’s initialized statically, code that is initialized with databinding, and code that is initialized with codebehind, you’ll want to call this in your OnPreRender overload.

protected override void OnPreRender(EventArgs e)
{
    applicationDirectory = Request.ApplicationPath;
    if (!applicationDirectory.StartsWith("/"))
        applicationDirectory = "/" + applicationDirectory;
    if (!applicationDirectory.EndsWith("/"))
        applicationDirectory = applicationDirectory + "/";
    fixupHrefs(this.Controls);
    base.OnPreRender(e);
}

(note, applicationDirectory is a member variable because we are going to use it in fixupHrefs()).

So all that is left is to do the fix up.

private void fixupHrefs(ControlCollection cc)
{
    foreach (Control c in cc)
    {
        if (c is HyperLink)
        {
            HyperLink h = (HyperLink)c;
            if(h.ImageUrl.StartsWith("~"))
            {
                h.ImageUrl = h.ImageUrl.Replace("~/", applicationDirectory);
            }
            if(h.NavigateUrl.StartsWith("~"))
            {
                h.NavigateUrl = h.NavigateUrl.Replace("~/", applicationDirectory);
            }
        }
        else if (c is Image)
        {
            Image i = (Image)c;
            if (i.ImageUrl.StartsWith("~"))
                i.ImageUrl = i.ImageUrl.Replace("~/", applicationDirectory);
        }
        else if (c is ImageButton)
        {
            ImageButton i = (ImageButton)c;
            if (i.ImageUrl.StartsWith("~"))
                i.ImageUrl = i.ImageUrl.Replace("~/", applicationDirectory);
        }
        else
            fixupHrefs(c.Controls);
    }
}

This code loops through all of the controls on the form, determines if it is a type that needs to be fixed, and then replaces “~/” with the application directory.

Hope this helps somebody who is having a similar problem.

Related Post

3 Responses to “UrlRewrite – Virtual Directories and the Tilde”

Leave a Reply

Comment Policy:

  • You must verify your comment by responding to the automated email that is sent to your email address. Unverified comments will never show.Leave a good comment that adds to the conversation and I'll leave your link in.
  • Leave me pure spam and I'll delete it.
  • Leave a general comment and I'll remove the link but keep the comment.

Notify me of followup comments via e-mail

Bear