Update: Please see this newer post for the latest and greatest MVC T4 template

 

One downside of using Html.ActionLink in your views is that it is late bound.  e.g. say you write something like this:

<%= Html.ActionLink("Home", "Index", "Home")%>

The second parameter is the Action name, and the third is the Controller name.  Note how they are both specified as plain strings.  This means that if you rename either your Controller or Action, you will not catch the issue until you actually run your code and try to click on the link.

Now let’s take the case where you Action takes parameters, e.g.:

public ActionResult Test(int id, string name) {
    return View();
}

Now your ActionLink calls looks something like this:

<%= Html.ActionLink("Test Link", "Test", "Home", new { id = 17, name = "David" }, null) %>

So in addition to the Controller and Action names changing, you are vulnerable to the parameter names changing, which again you won’t easily catch until runtime.

One approach to solving this is to rely on Lambda expressions to achieve strong typing (and hence compile time check).  The MVC Futures project demonstrates this approach.  It certainly has merits, but the syntax  of Lambda expressions in not super natural to most.

Here, I’m exploring an alternative approach that uses an ASP.NET BuildProvider to generate friendlier strongly typed helpers.  With those helpers,  the two calls below become simply:

<%= Html.ActionLinkToHomeIndex("Home")%>

<%= Html.ActionLinkToHomeTest("Test Link", 17, "David")%>

Not only is this more concise, but it doesn’t hard code any of the problematic strings discussed above: the Controller and Action names, and the parameter names.

Steps to enable the ActionLink helpers in your MVC app

You can easily integrate these helpers in any ASP.NET MVC app by following three steps:

1. First, add a reference to MvcActionLinkHelper.dll in your app (build the project  in the zip file attached to this post to get it)

2. Then, register the build provider in web.config.  Add the following lines in the <compilation> section:

      <buildProviders>
        <add extension=".actions" type="MvcActionLinkHelper.MvcActionLinkBuildProvider" />
      </buildProviders>

3. The third step is a little funky, but still easy.  You need to create an App_Code folder in your app, and add a file with the .actions extension in it.  It doesn’t matter what’s in the file, or what its full name is.  e.g. add an empty file named App_Code/generate.actions.  This file is used to trigger the BuildProvider.

How does it all work?

I included all the sources in the zip, so feel free to look and debug through it to see how it works.  In a nutshell:

  • When the first request is made at runtime, ASP.NET needs to build the App_Code assembly
  • It finds our .actions file, which triggers the registered BuildProvider
  • The BuildProvider goes through all the reference assemblies and looks for Controller classes
  • It then generates a static class with extension methods for each action
  • Since every aspx page is built with a reference to the App_Code assembly, all  the views are able to use the generated helpers.

Where is this going?

At this point, this is just a quick proof of concept.  There are certainly other areas of MVC where the same idea can be applied.  e.g. currently it only covers Html.ActionLink, but could equally cover Url.Action(), or HTML form helpers (standard and AJAX).

Please send feedback whether you find this direction interesting as an alternative to the Lambda expression approach.