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

S#arp Arch & MSTest

I have just started a new project, and as such I took this chance to further my exploration into alternative models then standard ASP.Net Webforms. I have been curious to learn more about ASP.Net MVC, and I wanted to continue exploring nHibernate.

When I first implemented nHibermate I used a model which was basically based upon Billy McCafferty's work; however, during this I found severe limitations one of which I blogged about here. Billy has been hard at work at developing a new set of patterns which are encapsulated in an architecure called S#arp.

One small glitch I ran into related to my use of MSTest. Billy has created a base class that all Respository test classes can inherit from. This class will setup and tear down nHibernate session and roll back any transactions which should help keep your database at a known state.

However, this class assumes the use of nUnit. Which when you try and use this from within MSTest it causes a null reference exception when you try and access the repository. If your like me and want to ue MSTest a real simple solution is this:

  1. Inherit from the RepositoryUnitTestsBase class.
  2. Explitly call the Setup and Tear down methods

So your class should basically look like:


    [TestClass]
    public class ProductRepositoryTest : RepositoryUnitTestsBase
    {
        [TestInitialize()]
        public void MyTestInitialize()
        {
            this.SetUp();
        }
 
        [TestCleanup()]
        public void MyTestCleanup()
        {
            this.TearDown();
        }
    }


I'd love to see these methods moved out into a seperate utility type class.

Enjoy
-Josh

Friday, November 14, 2008

Wordle

I ran into a site that is a lot of fun to play with. Wordle is a small java applet which will build one of those word clouds based on text you enter, or given a URL it will build the cloud based on the page. You can check out my cloud here



They also give you html you can use to link the image right into your blog. Which I have done with this post:




If you've had success with this service, or know of any other like it leave a comment. Thanks!

The joy in the smallest of things, that we might take for granted

Our production server, has been a VM using VMWare sitting on some type of non-windows platform. This server wasn't gen'ed by me and it has historically caused me pain (.Net was installed before IIS so I had to manually register everything for example). I've been axiously waiting for us to get a second box, ramped up, and now after months of waiting (And yes if my boss read this I admit I was part of the bottle neck for the last two months). We have a new server, and I was able to shut down the old server.

What does this have to do with the smallest of things that might take for granted? Well in the last three months, I have caused two different outages of our application on two occasions for roughly 10 minutes at a time. What was I doing you might ask? To take down a server, I must have done serious like reboot, or killed IIS, maybee I messed with the configuration files?

Nope none of that. All I did was empty the stinking recycle bin, and neither of those times did I ever let it finish it took me 10 minutes to get the status window focused so I could click the cancel button.

Now if you'll excuse me I'm going to create a couple thousand files, so I can delete them and empty the recycle bin....Ahhh the small things in life!

- Josh