Ok, after a slight push from Travis, I decided to put aside some time to live up to my promise and post an entry on how to enable extensionless requests on the new ASP.NET MVC framework using IIS 5.1 & 6.
I'm starting where my last post, ASP.NET MVC on IIS 5.1 (XP Pro), left off. So if you haven't got the MVC framework working on IIS 5.1 or 6 with extensions, have a gander at my last post and make sure its all working.
What we currently have (following after my last post) is links like /Home.mvc/About which are working because we've mapped the .mvc extension to the ASP.NET application, so IIS knows it's for ASP.NET and can fire it off in that direction, but what we'd ideally want is just having the link look like /Home/About (without any extension). Currently if you try an extensionless request like that, IIS just doesn't know what to do with the request or where to send it, so it returns a 404.
Enter URL rewriting!
I'm going to use Helicon Tech's ISAPI_Rewrite 3. The lite version, which I'm going to use, is free but has limitations (which you can read about here) but should be fine for what we want to do. The full version is only $99 US per server... cheap as chips if you ask me!
ISAPI_Rewrite offers the same syntax and behavior as mod_rewrite on Apache (which is a good thing :-). If you don't know anything about mod_rewrite or are completely new to the whole URL Rewriting idea, I would recommend you read up on some material - here would be a good place to start, or good old wikipedia.
Anyway, lets start.
First off you'll want to download ISAPI_Rewrite 3 from here (just grab the lite version) and install it. You shouldn't run into any problems... touch wood. If you do, go back to their documentation for troubleshooting advice.
Once it's installed, open up the httpd.conf file in your favourite text editor (Notepad++ is my fav :-)) and add the following lines. Note that if you used the .msi installer, the httpd.conf file should be in the Program Files\Helicon\ISAPI_Rewrite3\ directory.
RewriteEngine on
RewriteBase
RewriteRule ^Home/(.*?)$ Home.mvc/$1
What this RewriteRule is doing is intercepting any request that starts with "Home/" and replaces the "Home/" part with "Home.mvc/". Once it's done this, IIS handles the request and sees the .mvc extension, so it fires that request off to ASP.NET.
Brilliant.
So go back to your browser and try and visit the http://localhost/Home/About address on your local machine. Hopefully you should be met with the same page as if you would have written http://localhost/Home.mvc/About. Yay! Now do that for all your different controllers... Just make sure none of your controllers are called Styles, CSS, Scripts etc etc ;-)
But there is still a problem... anyone picked it yet?
You see, our incoming request, "/Home/About", is being rewritten, by ISAPI_Rewrite, to "/Home.mvc/About" and is then being passed to ASP.NET and it's then being handled by the ASP.NET MVC routing engine. It should then match the following routing rule:
RouteTable.Routes.Add(new Route
{
Url = "[controller].mvc/[action]/[id]",
Defaults = new { action = "Index", id = (string)null },
RouteHandler = typeof(MvcRouteHandler)
});
So this will go off to the "About" action on the "Home" controller. Fantastic... but what happens when you go the other way? What happens when you get the ASP.NET MVC routing engine to write the links for you? That's right, it'll have the .mvc extension thrown onto the end of any requests that match the rule.
Hmmm, not cool because it basically renders all of what we've done with the URL rewriting useless!
Not all is lost though. You see, the ASP.NET MVC routing engine tests each incoming and outgoing URL against the RouteTable from top to bottom (which is why you need to write them from most specific to least specific)... So if we throw in a different rule, say the exact same rule without the .mvc part, that should be evaluated first and find it as a match and then the outbound links shouldn't have .mvc in them.
Something like this:
protected void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.Add(new Route
{
Url = "[controller]/[action]/[id]",
Defaults = new { action = "Index", id = (string)null },
RouteHandler = typeof(MvcRouteHandler)
});
RouteTable.Routes.Add(new Route
{
Url = "[controller].mvc/[action]/[id]",
Defaults = new { action = "Index", id = (string)null },
RouteHandler = typeof(MvcRouteHandler)
});
RouteTable.Routes.Add(new Route
{
Url = "Default.aspx",
Defaults = new { controller = "Home", action = "Index", id = (string)null },
RouteHandler = typeof(MvcRouteHandler)
});
}
Glorious.
So, that's a start... it's nice and simple and hopefully a good place to get you going. I'm open to suggestion as to different ways of going about it... I'm no mod_rewrite or regex guru by a long shot!
Technorati Tags:
asp.net-mvc,
iis