Scott Hanselman

ASP.NET MVC and the new IIS7 Rewrite Module

October 10, '08 Comments [9] Posted in ASP.NET | ASP.NET MVC | IIS
Sponsored By

Last year I noticed that there were 11 ways to get to my blog. Literally 11 different URLs and it wasn't helping me my ranking in the search engines. I wrote about this in detail and how I used ISAPI_Rewrite to fix it up.

Fast forward to this year and the IIS7 team has been taking advantage of IIS7's modular design to release a bunch of new modules out-of-band.

Both the newest ISAPI_Rewrite and Apache's standard mod_rewrite module uses distributed configuration files or .htaccess files.

Here's just part of my .htaccess file that makes sure that all the incoming URLs end up at the final canonical http://www.hanselman.com/blog/

RewriteRule /blog/default\.aspx http\://www.hanselman.com/blog/ [I,RP] 
RewriteCond Host: ^hanselman\.com
RewriteRule (.*) http\://www.hanselman.com$1 [I,RP]

RewriteCond Host: ^computerzen\.com
RewriteRule (.*) http\://www.hanselman.com$1 [I,RP]

RewriteCond Host: ^www.computerzen\.com
RewriteRule (.*) http\://www.hanselman.com/blog/ [I,RP]

After you've installed the IIS7 Rewrite module, you can bring rules in a couple ways. The nicest is by importing them directly. Notice the tree view in the screenshot below. It gets updated in as you type.

Note that the importer only really understands rules in the mod_rewrite syntax. It doesn't fully support ISAPI_Rewrite so some things like Host: and [I] aren't supported in this release, but I'm hoping (and I've formally asked) that they'll support them for the final RTW (Release to Web). If you have ISAPI_Rewrite rules, you can either convert them then manually edit them to tidy up (what I did), or you can convert them to mod_rewrite syntax first.

For example, in the rule importer UI I could have replaced the ISAPI_Rewrite directive "Host:" with "%{HTTP_HOST}" and "[I]" with "[NC]" (meaning case insensitive). Or, I can just edit the incorrectly imported rules.

image

This is useful for importing existing rules like mine, but it's still hard since we're talking obscure formats left and right. There's also an Add Rule wizard:

Add rule(s)

It's REALLY easy with the User Friendly URL dialog to interactively create mappings between the URLs your app uses and the URLs you want. See in the screenshot below how the combo-box is dynamically populated based on the example I put in the top text box?

Add rules to enable user friendly URLs (2)

The User Interface for this module is surprisingly deep in functionality. There's a Regular Expression tester built into it, which makes Regular Expressions suck by about -2.

Test Pattern

ASP.NET MVC and SEO

I noticed a post by Jason Young recently on ASP.NET and SEO (Search Engine Optimization). He's concerned about trailing slashes

Ultimately I don't think it's that big of a deal since the URLs that your application generates are always consistent. Your app is what teaches search engines what to ask for. As long as your application is generating URLs that look the way you want them, you're cool.

The only real problem happens when other humans link to you and they make a mistake. Perhaps they include a trailing slash when you don't want one. Still, not a huge deal, but if you feel strongly about it, that's where a rewrite module comes in useful. I think that the Rewrite module would fit Jason's requirements.

Matt Hawley at eXcentrics World wrote a Legacy Route using ASP.NET Routing which is a clever idea as well. He could have certainly used this Rewrite Module, but ultimately as long as you're returning HTTP 301's (redirect permanent) or HTTP 302 (temporary redirect) as you fine appropriate, then use what makes you happy.

What's really important is that both these guys respect the permalink. A 404 is never a good thing.

Every site is different, but if I add a basic rule like this to my ASP.NET MVC site…

image

…and request http://localhost/rewritetest/Home/Index, the resulting HTTP Headers look like this, as the module forces the trailing backslash (of course you could also force NO backslash if it makes you happy):

GET /rewritetest/Home/Index HTTP/1.1
Accept-Encoding: gzip, deflate
Host: localhost
Connection: Keep-Alive

HTTP/1.1 301 Moved Permanently
Content-Type: text/html; charset=UTF-8
Location: http://localhost/rewritetest/Home/Index/
Server: Microsoft-IIS/7.0
X-Powered-By: ASP.NET

I'm not a regular expression expert, but searching the web for "mod_rewrite" rules will keep you busy for next 50 years. Here my favorite reference for .htaccess and mod_rewrite rules.

Learning the basics of the IIS7 Rewrite Module:

Functionality reference

Video walkthrough

Enjoy.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web
Friday, October 10, 2008 10:40:51 AM UTC
Good stuff Scott. Regarding the aliasing of URLs with and without trailing slashes, this (like choosing or omitting the "www") is mostly an SEO cliche. It's been a while now since Google was tricked up by issues like this. Google Webtools lets you specify which of "www.site.com" and "site.com" is treated as canonical, so it is NOT correct that allowing both still aliases your PageRank across multiple sites. Most people still 301 redirect, but it's not strictly speaking necessary.

The same thing goes for URLs with and without trailing backslashes. If you have two URLs http://www.hanselman.com/blog and http://www.hanselman.com/blog/, the chances of today's Google being "tricked" by this are virtually nil. Provided you are consistent, it is (as you say) a non-issue.
Friday, October 10, 2008 12:00:34 PM UTC
Great information -- I'll have to give it a try.

I'm not an expert with rewrite, but I suspect

RewriteCond Host: ^www.computerzen\.com

should really be

RewriteCond Host: ^www\.computerzen\.com

if you're a purest anyway ;) Have a great time at PDC. I'll be with you in spirit!
Tom Denny
Friday, October 10, 2008 2:24:04 PM UTC
I agree, rewriting solves most of the issues. The main issue that I would like to see fixed is that when you generate links, they don't have a trailing slash. From what I can tell, there is no easy way to add the trailing slash without hard-coding it where you generate the link. That defeats the purpose of generating links based on the routing configuration.

I understand that there may only be a minimal SEO issue, or possibly none at all (however, I don't like to take chances), but why does the link generation code drop the trailing slashes even if they're defined in my route? Take a look at the example in my blog post you linked to. The route URL is defined as "Firefox-Extension/". When the route ultimately gets added to the routing table, the trailing slash is dropped. Is this the desired behavior, or is this a bug?

Thank you for talking about this Scott! I think this is an important issue, and my philosophy is to design for SEO from the start. After all, that's where most people get the majority of their traffic/income.
Friday, October 10, 2008 4:56:51 PM UTC
AWESOME post - thanks a bunch Scott
Friday, October 10, 2008 7:00:11 PM UTC
A simple way to create a rule for URL rewrite module that fixes up the trailing slash problem is to take the Apache mod_rewrite rule from here, which looks like this:

RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+[^/])$ $1/ [R]

And use rule importer in URL rewrite module to convert it to IIS rule:

<rule name="Imported Rule 1">
<match url="^(.+[^/])$" ignoreCase="false" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" pattern="" ignoreCase="false" />
</conditions>
<action type="Redirect" url="{R:1}/" redirectType="Found" />
</rule>

After that you may use the URL rewriter UI to tweak the imported rule further, such as make it case insensitive or change the redirect type to "Permanent".
Friday, October 10, 2008 7:03:00 PM UTC
Hi, I use the following to fix the back slash problem with isapi rewrite:

RewriteRule ^([^.?]+[^.?/])$ $1/ [R=301,L]

It does assume that none of your folders contain period characters which is the case for most websites.

The problem i have had with isapi rewrite in the past (with web forms) is that the form action tag is not rewritten and the physical url is outputted. This same problem exists with the ReturnUrl with asp.net membership. I have used a control adapter to solve the first issue but i have never been able to fix the second. I was wondering if using this module would automatically resolve these issues.
Friday, October 10, 2008 11:01:14 PM UTC
Lee,

We are working with ASP.NET team to resolve the issues in ASP.NET related to URL rewriting, such as incorrectly resolved links with "~", sitemaps and others. Meanwhile, for the form action tag you can use the new property available in the .NET Framework 3.5 SP1 that allows setting of the form action URL. Here is how you can fix the form action url with this property when using URL rewriter:

protected void Page_Load(object sender, EventArgs e)
{
if ( !String.IsNullOrEmpty(Context.Request.ServerVariables["HTTP_X_ORIGINAL_URL"]) )
form1.Action = Context.Request.ServerVariables["HTTP_X_ORIGINAL_URL"];
}
Thursday, October 23, 2008 7:04:37 PM UTC
After reviewing the URL rewrite module for IIS, I could not see anyway to use it in code to generate a friendly URL. Maybe I'm missing something...
jp
Tuesday, October 28, 2008 12:26:55 AM UTC
If you are refering to an ability to generate friendly urls for the links in html pages, then URL rewriter does not provide this functionality in current release. We are evaluating possible ways to enable that in future releases.
Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.