Saturday, September 22, 2007

ASP.NET: Resolve Virtual Paths with a Simple Anchor Tag

Web developers have traditionally struggled with the issue of maintaining relative links throughout a web site that would always point to the correct folder/directory, no matter where the link was referenced from.

A relative link shows the web browser how to navigate up or down the folder structure of the site in order to get to the target page.

Lottery Post, being a very large and deep site, has this problem extensively.

For example, let's look at the link to the contact page located at www.lotterypost.com/contact.aspx from a forum topic located at https://www.lotterypost.com/thread/161745.

As you can see, the contact page is located in the site's root folder, and the forum topic is located in a folder called "thread".  From the perspective of the forum topic, the contact page is located "up" in the folder structure (or "down" is you envision your root folder at the bottom), so a relative link would look like this:

<a href="../contact.aspx">Contact</a>

The two dots and the slash ("../") before the file name indicates that the browser needs to "go up one folder" to find the contact page.  If I was viewing an individual post at https://www.lotterypost.com/thread/161745/887609 I would need to go up two folders, so I'd put "../../" before the file name.

When coding a huge site it becomes immensely difficult to maintain all those relative paths, especially when you decide to change the folder of a page.

For example, if I changed the topic page one level deeper (like www.lotterypost.com/forums/thread/161745), I would need to remember to change the relative page to the contact page inside it.

With hundreds of links on every page, the problem is magnified.

ASP.NET helps with "Web application root operator"

ASP.NET introduced a tilde character ("~") as a new operator called the "Web application root operator".  The operator only works with server controls.

Its function is to substitute the proper relative path at runtime from the current page to the target page.

So if the topic page uses a server control like this:

<asp:HyperLink NavigateUrl="~/contact.aspx" Text="Contact" runat="server" />

It outputs the following HTML to the page at runtime:

<a href="../contact.aspx">Contact</a>

Because I used the tilde character in the path, if I later move the topic page to a different folder depth, it will automatically adjust to the correct relative path in the final HTML page output.

Use the same concept with a normal <a> tag

Because the tilde character only works with server controls, if you tried to insert the tilde into a normal anchor ("<a>") tag, the literal text of the tilde would be output exactly as you wrote it — no relative path substitution would occur at runtime.

For example:

<a href="~/contact.aspx">Contact</a>

..would yield exactly the same thing on the final HTML page, with no relative path substitution:

<a href="~/contact.aspx">Contact</a>

If you clicked that link, the browser would try to go to the page www.lotterypost.com/thread/~/contact.aspx — obviously not what you want, and would produce a 404 Not Found error.

The trick to making the simple anchor tag ("<a>") substitute the relative path at runtime?

Simply add runat="server" to the tag, which transforms it into a server control, as follows:

<a href="~/contact.aspx" runat="server">Contact</a>

Now when you open the page it will correctly substitute the relative path, and will look like this:

<a href="../contact.aspx">Contact</a>

This substitution occurs because ASP.NET pre-processes the URLs of all built-in server controls, substituting the tilde character with the proper relative path. 

Note, this substitution does not automatically occur on your own custom controls.  For that, you need to transform the tilde yourself, like Rick Strahl's solution (see the comments on that post too).

All HTML controls can be "upgraded"

This is a very simple example of the power that many people do not know even exists with regular HTML controls.

You can add the same runat="server" to any regular HTML control and change it into a powerful server control.

Want to change whether or not a regular HTML control is rendered to the page at runtime?

Simply add an id and runat attributes to the control, and then you can manipulate the visible property from your code behind, just like a regular server control.

After experimenting with this you may find, like I did, that there are several uses for "upgrading" regular HTML controls.  However, I have found in my own experience that uses of this method should be restrained to very simple cases, such as changing the visibility or class at runtime.

The reason is that the ASP.NET controls are more powerful, so if you intend on doing powerful things you don't want to start with a control that will limit you at some point.

Enjoy your new set of "upgraded" controls!

0 Comments:

Post a Comment

<< Home