Type Safety With ASP.NET MVC Futures

Please note that this post was migrated to my new blog platform. There may be bad formating, broken links, images, downloads and so on. If you need an item on this page, please contact me and I will do my best to get it from my backups.

~E

In this post, I will show you how to strongly type some parts of MVC to get rid of those “magic strings.”  I will also publish a few extension methods that expand upon this concept later on.  So, this is a continuation of my Mvc series that you can subscribe to.

ASP.NET MVC 1.0 Futures

You can download ASP.NET MVC 1.0 RTM from codeplex.  You can even download the source code and step through what the framework is doing.  What a lot of people overlook is an additional assembly available for download at these locations called ASP.NET MVC 1.0 Futures.  You can download it from Codeplex from below:

Download ASP.NET MVC 1.0 Futures from CodePlex

This is a darling of an assembly using the namespace Microsoft.Web.Mvc.  Usually these Microsoft “Futures” releases are developer code that did not get approved for RTM release.  This assembly is no exception and includes a plethora of strongly typed extensions.  The reason some of this code did not get approved was because some of it did not conform to Medium Trust requirements for the 1.0 release.  So if you have a strict medium trust application, you may not be able to use the some of the code contained within the assembly.

I am not going to cover all of the extensions within this assembly.  You can do that on your own with .NET Reflector.  Instead, I am going to cover just a couple that you will be using on a daily basis.

To get started, go ahead and added a reference to the Microsoft.Web.Mvc assembly to your project.  In addition, to make things a lot easier, go ahead and add a few namespaces to your web.config.

<namespaces>
  <add namespace="System.Web.Mvc"/>
<add namespace="System.Web.Mvc.Ajax"/> <add namespace="System.Web.Mvc.Html"/> <add namespace="System.Web.Routing"/> <add namespace="System.Linq"/> <add namespace="System.Collections.Generic"/>

<add namespace="AspNetMvcTypeSafety.Controllers"/> <add namespace="AspNetMvcTypeSafety.Models"/> <add namespace="Microsoft.Web.Mvc"/> <!— Add this assembly —>
</namespaces>

Hit CTRL-SHIFT-B to do a quick compile of your code (so the assembly is copied to your /bin). ASP.NET MVC 1.0 Futures is now available for your project.  You’ll also note that I add my controllers and models’ namespaces.  This is because you want them available from your views and controllers.

Strong Typed Html ActionLink<TController>

If you are already coding in ASP.NET MVC, you are using strings to reference controllers, actions, and views.  An example to access to the MostRecent() action on a PostController would be something like:

<%-- // Old way--%> 
<%= Html.ActionLink(Model.DisplayName, "MostRecent", new { Controller="Post" }) %>

You have to create an anonymous type and reference a controller with “Post”, for the action method “MostRecent”.  Using the Futures assembly, you’ll see a few new extension overloads for Html.ActionLink:

Html.ActionLink<TController>(
Expression<Action<TController>> action, String linkText) Html.ActionLink<TController>(
Expression<Action<TController>> action, String linkText, object attributes)

So, now you can re-write the first example to get the MostRecent() action like so:

<%-- // New way --%>
<%= Html.ActionLink<PostController>(c => c.MostRecent(), Model.DisplayName)%>

Isn’t that much tidier?  To break it down, TController is the controller you want to access an action method for.  With it assigned as the generic type, now you have intellisense for your controller as the image below demonstrates.

9-23-2009 8-14-03 PM

This pattern even supports the parameters on your controller’s actions!  For example, say you want to pass in a username property for a PostController action with the signature of MyPosts(String username).  Using the old method, you have to pass it an anonymous type like so (again, using strings):

<%-- // Old way --%>
<%= Html.ActionLink(Model.DisplayName, "MyPosts", new { Controller="Post", id=Model.Username }) %>

With the Futures assembly, it’s a simple as this:

<%-- // New way --%>
<%= Html.ActionLink<PostController>(c => c.MyPosts(Model.Username), Model.DisplayName)%>

Notice that you pass the Model.Username parameter directly into the method c.MyPosts(), instead as an anonymous type like the old way. You even get the intellisense as well, as shown below:

9-23-2009 8-20-13 PM

Html RenderAction<TController>

This new function works exactly like the ActionLink<TController> above.  No surprises.

<%-- // new way %>
<% Html.RenderAction<PostController>(c => c.MyPosts(Model.Username));%> 

You can read more about RenderAction<TController> here

Strong Typed Html BeginForm<TController>

Again, using the ASP.NET MVC Futures assembly, this is already done for you.  This one is a bit tricky though.  You want to pass your values within the form’s scope, not the BeginForm method itself.  But, if you leave the parameters blank for your method, the view will not render and you will be an exception.  Intelliense actually gives you a hint by the red underline.

9-23-2009 9-01-42 PM

To get by this, you have to trick it and pass in some default values like so:

9-23-2009 9-02-58 PM

Yes, you can still pass a direct value into the method.  And just like normal, if a route’s parameter does not match the name, it will be tacked on as a querystring. 

Summary

That’s it for now.  There are more to capitalize on within the Futures assembly such as the FileCollectionModelBinder for multiple files, the CookieTempDataProvider for setting a temp cookie only for the next request, or even the HtmlHelper extensions for Mailto() that wraps those ever daunting subject, body, multiple emails, etc all into a neat HtmlHelper.

For my next project, I will be developing heavy in Mvc across multiple sites.  At that point, I am sure I will have more strongly typed extensions for things like RedirectToAction() at the controller level.  I will post them as I run across them.

> Revision History
> About the author