Thursday, January 20, 2011

Can WebSharper beat ASP.NET MVC at the routing game?

At work we have been having a lot of fun designing WebSharper sitelets lately. A quick recap: WebSharper is our web development framework that is all about cross-compiling F# to neatly interoperating client-side JavaScript and server-side .NET assemblies - a GWT of sorts. Sitelets are the recently introduced server-side abstraction, the new kid on the block where the bully is of course the notorious ASP.NET MVC.

ASP.NET MVC operation is all about controllers and actions: a request comes in, is matched to a controller/action, and then gets handled. At first glance it appears that controllers are classes and actions are methods. But NO! By introducing something they consider an improvement, the MVC team decoupled actions from methods and insists now that both controllers and actions are strings:

http://haacked.com/archive/2008/08/29/how-a-method-becomes-an-action.aspx

If you now want to construct a link to a particular action in a view, you have to know it by its string name. And what if it changes? Bummer, the project compiles fine and then fails at runtime.

This is particularly sad given that they used to offer a safer way:

http://weblogs.asp.net/scottgu/archive/2007/12/03/asp-net-mvc-framework-part-2-url-routing.aspx 

While ASP.NET MVC fans wait for this feature to come back, we can do better with F#. The basic idea is that we model everything first-class: an action is just a value of a user-defined Action data type, and a controller is a value as well. Consider:

Now, a controller is simply a function of type Action –> Response. And a website? A website, or a sitelet, as we call it in WebSharper, is a controller coupled with a router, where a router is a bijection from locations to actions.

While the controller is fun to write, the router is not. One tedious way to write it is to write two F# functions, one pattern-matching a location and returning an Action, and the other doing the reverse. For actions that can be listed in a finite list, a less tedious is to write a table with a 1:1 correspondence between locations and actions. But the easiest is to automate it all:

This little function will automatically infer locations such as “/HomePage”, “/AboutUs”, “/Blog/123”... All the tedious work done, time to write the controller!

And how about safe links in the view? Nothing is easier:

And if anything happens to change, F# compiler will make sure the links are still correct.

Sitelets offer a lot more than this, such as easy embedding of F#-defined client-side (JavaScript) controls or the pre-generation of the static part of the web application as a set of HTML and resource files. But none of it can beat the fun of designing routing the functional way.

1 comment: