Thursday, November 20, 2008

ASP.Net MVC Hyperlinks and Suboptimal Design

I never thought that after 8 years of professsionally programing I would be stumped at how to create a hyperlink. Well with ASP.Net's MVC framework there are a lot of ways to create links, and I want to share an experience I am having.

I want to create a link to my Product controller, calling a ListProductsByCategory action passing in a single parameter which is the id of the category. This should be a very simple pattern, and while yes I could hardcode the link such as:

<a href="Product/ListProductsByCategory/1">Widgets</a>


However, there should be a better way, and in fact there is. The ViewPage has a property called Html which has helper methods to help rendering a view. One of the methods is ActionLink, which sounds like what we need. So if we look at all the overloads we see two in particular:

  1. string linkText, string actionName, string controllerName, object values, object htmlAttribute
  2. string linkText, string actionName, string controllerName, RouteValueDictionary values, RouteValueDictionary htmlAttributes


Option 2 is fairly self explanatory based on the signature of the API. It looks like it takes a collection of parameters that is probally name value (I've not had the time to dig into what a RouteValueDictionary actually is). The problem I have with this is I really don't want to clutter up my markup with the syntax of building a dictionary. So seeing option 1 I figued I could do:

 <%=Html.ActionLink("Accessories",
"ListProductsByCategory", "Product", 3, null)%>


This resulted in the following html being generated:


<a href="Product/ListProductsByCategory">Accessories</a>


The problem is we have lost the value portion of the url. After reading Oren's post on some of his issues with the API Design I figured this was something more then a simple object that they were expecting but what? The API provides no hint as to what it might be (and the intellisense doesn't have the documentation yet so there were no tooltips).

Firing up google I came accross this post which showed me what I was missing. The object is actually an anonymous type, which surprises me since I had thought you couldn't pass anonymous types around. Well so anyways our code now looks like:


<%=Html.ActionLink("Accessories", "ListProductsByCategory", "Product", new { id = 3 }, null)%>



The only reason I feel this is suboptimal is that the API signature doesn't provide any hint as to what is expected. I prefer an API where I don't have to google to figure out the parameters, and with in most modern development environments this can be accomplished using good names mixed with intellisense. In this case, I wish the intellisense for the parameters would have been available and it could have explained what I needed. But I understand this is a beta version. I wonder why anonymous types don't have a base type other then object, that would have also made this more discoverable.

This works like a charm!

-Josh

No comments: