ASP.NET MVC 2 has been released (yay). One of the pieces I like about it is in the MvcFutures assembly. MvcFutures is where the MVC team puts code for features that may or may not make it into a future version of the MVC framework – undocumented, somewhat risky, but hey you get all the source code if you find yourself painted into a corner.
One of the long-standing MVC practices has been ‘Shun Magic Strings.’ For example, rather than specifying Controller/Action names in an ActionLink by string, we’ve always used an Expression<Action<TController>> instead to define the Controller class and Action method “in code.” If the action changes in the future, this gives you somewhat better abilities to discover the problem sooner vs. later.
MvcFutures includes a version of this idea, taken to the next level: you provide the expression with the arguments you want passed to the action included – you don’t provide a 2nd anonymous type defining the arguments. This gets rid of the somewhat confusing “null” arguments inside the expression, and just looks better overall. Plus, if the arguments to the action change, you’ll get better warning of that as well.
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Magic Strings are Evil</h2>
<p>
<%= Html.ActionLink<HomeController>(c => c.FavoriteNumber(16), "A Number") %>
<%= Html.ActionLink<HomeController>(c => c.FavoriteNumber(32), "Another Number") %>
<%= Html.ActionLink<HomeController>(c => c.FavoriteNumber(42), "Yet Another Number") %>
</p>
</asp:Content>
I like this method MUCH better.
The implementation that makes this happen is in Microsoft.Web.Mvc.Internal.ExpressionHelper. Which even though it’s in an “Internal” namespace, is neither marked Internal, Sealed, or otherwise made unavailable (hallelujah). So you can use this trick for all sorts of things.
There is also a System.Web.Mvc.ExpressionHelper in the official MVC assembly, which is used to implement the smart Html.TextBoxFor(m => m.Property) functionality. This class is also NOT internal, not sealed, not obfuscated and hidden away. We’ve used it to extend the Html.[control]For() abilities to some other control types. Very useful stuff. Plus its just interesting code to read.
One potentially big caveat: I’m told that the Html.ActionLink<TController>() methods don’t work if you’re using Areas in your MVC application. I haven’t tried this myself, we aren’t using Areas in any of our MVC 2 applications yet. That might be why this functionality is hidden in MvcFutures and not out with the rest of the smart expression code.
This was already in the asp.net mvc 1 futures dll. Another potential problem is that this method becomes unusable slow when you have a lot of routes.
It’s not as useful as you might hope. Here’s the problem: assume you’ve set up a model binder to load entities from the database. Perfectly sensible thing to do, shortens your code and makes everything readable. Problem is, you call the Futures method from the view, and typically you don’t pass database entities to the view.
I don’t think there’s a sensible way of using this method and using entity model binding.
@Julian Birch
Very interesting – could you elaborate on this further? It’s not a problem that we’ve run into (yet) but we’ve been using dedicated ViewModels for the views instead of db entities and then using AutoMapper to do the binding. So perhaps we’ve just been lucky/ignorant.
Another problem with the expression based ActionLinks is that they don’t take the [ActionName] attribute in account when generating the url. A much better idea is to use T4MVC (http://mvccontrib.codeplex.com/wikipage?title=T4MVC).
@Carl Hörberg
Oooo now that is slick. http://mvccontrib.codeplex.com/wikipage?title=T4MVC_doc&referringTitle=T4MVC
Shows some examples of usage.