Need a simple CRM and Project Management system?
Check out JobNimbus - CRM for Contractors and Service Professionals.

Fixing Relative Paths in C# ASP.NET When Using Url Rewriting

UPDATE: This method is generally used in situations where you have relative paths in your project so that links (image, href, css, etc) work on your development environment (where the VS web server inserts a virtual path), as well as your production environment that may or may not have that same virtual path.  The simpler way to handle this situation is to change the virtual path in your development environment.  To do this, click on your web site project and look in the properties dialog.  You should see a Virtual Path setting.  Change that to '/' and you will no longer get a virtual path in your development environment.  This only works in VS 2005 SP1 and later.  Once you have the project configured this way, you are safe to use absolute paths everywhere in your project.

One of our clients recently asked us to add URL rewriting to their site so that the URLs looked nicer.  Essentially, we were trying to change something like http://devtoolshed.com/product.aspx?id=1234 to something like http://devtoolshed.com/product/1234.  You can accomplish this very easily using the URL Rewrite Module for IIS 7, which is very cool and will probably be the topic of a future blog post.



Broken Links
Everything was working well until I realized that this broke any links or references that were relative instead absolute.  For example, consider an image reference to "images/logo.gif".  After URL Rewriting, since the base url had changed, the browser was now looking for http://devtoolshed.com/product/images/logo.gif, which doesn't exist.

There are a number of different ways people attempt to solve this problem - most of which don't work in all situations.

Option 1: Make all paths absolute.
One option is to change all URLs to absolute paths, like "/images/logo.png".  The problem with this is that it doesn't work if you're viewing the web site from the visual studio devlopment environment because the development web server launches the site from a sub-directory instead of from the "web server" root.  You can go this route, but you'll have trouble developing and testing.

Option 2: Use ~/.
.NET controls allow you to set urls to "~/page.aspx" or "~/images/image.png", and it will handle changing ~/ to the correct path for you.  Magic.  This works great in both development environments and production environments in normal situations, but it still doesn't work when you use URL Rewriting because it translates into relative paths still.

Option 3: Use more URL Rewriting rules to fix things
You could tell the URL rewriting engine to intercept these newly broken references and rewrite them into URLs that work.  In desparation I went down this path a few steps - it was a nightmare.  I wouldn't recommend it.

Option 4: Using Request.ApplicationPath (the right way).
Prefixing all of your links with Request.ApplicationPath works well for the most part.  It gives you the absolute path to the root of your web site, which is good because we want to work with absolute paths, and it's good because it changes based on whether you're running in your development environment or on a production server.  It's one failing is that it is inconsisant when it comes to trailing slashes.  Without going into details about why this is, I'll just tell you that the correct way to address this is to use Request.ApplicationPath.TrimEnd('/') whenever you use it.

What you end up with here is code that looks like this in your code behind files:

Response.Redirect(Request.ApplicationPath.TrimEnd('/') + "/url.aspx");
sb.Append("<a href=\"" + Request.ApplicationPath.TrimEnd('/') + "search.aspx?q=" + ...);

 

and like this in your aspx pages:

<a href=<%= Request.ApplicationPath.TrimEnd('/') + "/Rss.aspx" %> >RSS Feed</a>
<link href=<%= Request.ApplicationPath.TrimEnd('/') + "/css/style.css" %> rel="stylesheet" type="text/css" />

 

And of course, what you really end up with are links that always work.

What about CSS?
CSS links are a little more trickey because you can't use Request.ApplicationPath in them by default.  The solution - make it so that css files are parsed for C# code.  I cringed a little when I first saw this technique, but after thinking about it more, and after actually using it, I liked it a lot.  Aside from allowing you to create links in CSS files that always work, you have a little more flexibility in the css that is produced - think if/else blocks, etc.  Here's how you do it.  In your web.config file, add these two sections:

<compilation debug="true">
    <buildProviders>
    <!-- So we can map paths correctly in css files -->
    <add extension=".css" type="System.Web.Compilation.PageBuildProvider" />
    </buildProviders>
</compilation>

 

and

IIS 6

<httpHandlers>
    <add path="*.css" verb="GET" type="System.Web.UI.PageHandlerFactory" validate="True" />
</httpHandlers>

 

IIS 7

<system.webServer>
  <modules>
    <handlers>
      <add name="Parse CSS Files" preCondition="integratedMode" verb="GET" path="*.css" type="System.Web.UI.PageHandlerFactory" />
    </handlers>
  </modules>
</system.webServer>

 

Then in your css files, you can do this:

<!-- This line goes at the top.  This makes all browsers recognize this as css -->
<%@ ContentType="text/css" %>
 
.home_background
{
     background-image:url(<%= Request.ApplicationPath.TrimEnd("/") %>/images/bg_home_search.png);
}

 

Attribute NavigateUrl

Hi There,

And what I do when I have something like that ?

<asp:HyperLink ID="hplMoveis" NavigateUrl="~/Produto.aspx?tp=m" ForeColor="#182C33" runat="server">MÓVEIS</asp:HyperLink>

I cannot use <%%> in the NavigateUrl attribute... so, I cant use the suggestion.

Thanks.
Marcelo.

URL absolute path problem after URL rewriting

This is a good and ideal solution. (taken from the top section).

One option is to change all URLs to absolute paths, like "/images/logo.png". The problem with this is that it doesn't work if you're viewing the web site from the visual studio devlopment environment because the development web server launches the site from a sub-directory instead of from the "web server" root. You can go this route, but you'll have trouble developing and testing.

You an acheive this by this workaround:
1. Make the Use dynamic port property of the website in the IDE to False
2. Set a port number, say 5155 ,6166, 7177, depending on how many projects you run at the same time.
3. Make this url global by adding it in the DB or a settings XML file.
eg. "http://www.localhost:6166/" (change this in the real web server to "http://www.yousite.com/" or what ever.)

4. Load this data in the Session Start event for the first time in the Global.asax and make it public by adding it into the Application collection object (this is to prevent the overhead of repeated calling of the same path in all sessions.) You can fetch this from the Application object in all the following sessions.

5. add this url in the pages:
eg.

You can follow this in CSS, javascript, ashx files and so on...
Thanks

Build errors using the CSS web.config trick.

I am getting lots of build errors on the css file. Why is it so?

For option 1 you can set the

For option 1 you can set the site to run without a subdirectory by changing its virtual path to / in the properties of the project.

Thank you very much!Give me

Thank you very much!Give me lots of help!

For CSS, use relative paths

Thanks for the tutorial!
Some suggestions:

  • For the ASPX files, you can also use:
        <%= ResolveUrl(~/Rss.aspx") %>
    
  • For the CSS file, you can use relative paths. So it becomes:
        background-image: url('../images/bg_home_search.png');
    

Code not working for IIS 6 but is for IIS 7

The css file is not parsing on our IIS 6 server but it does on my local IIS 7 machine. I've altered the web.config for each so that the correct config settings are used for the individual server but it just does not parse on IIS6.



<!-- So we can map paths correctly in css files -->


...




...

hPLvcrWMPCDOIpXDg

well it's pretty much the same, since at the end you'll have a sub-domaine , you can aeslwl host in a free hosting website as a sumbdomaine and spare yourself the trouble , it would have been worth all the pain if at the end your host will be a .com or something of your choice ! but nice tutorial anyway !

<compilation debug="true"

<compilation debug="true" defaultLanguage="c#">
<buildProviders>
<!-- So we can map paths correctly in css files -->
<add extension=".css" type="System.Web.Compilation.PageBuildProvider" />
</buildProviders>
...

<httpHandlers>
<remove verb="*" path="*.asmx"/>
<add path="*.css" verb="GET" type="System.Web.UI.PageHandlerFactory" validate="True"/>
...

Do NOT use Request.ApplicationPath!!!

Code bombs out in IIS7!

use the following instead:
background-image:url(<%= Page.ResolveUrl("~/images/bg_home_search.png") %>);

External CSS Link

~/ for the root.

In your CSS you can use relative paths.

< link rel="stylesheet"

< link rel="stylesheet" type="text/css" href='<%=Page.ResolveUrl("~/Styles/default.css")%>' / >

This wat left out in my previous post.