Mar262010

T4MVC

    I presented ASP.NET MVC last month at San Diego .Net User group, I think overall it was a successful presentation. I got some good comments after the presentation, and yesterday, one member of the user group asked me my demo code for the T4MVC. Unfortunately I write my demos on the fly during my presentation ( I am not afraid to write code :) ), and usually 2-3 weeks after my presentation I wipe out the virtual pc that I use for the presentation. I don’t like to turn down people, I offered him to write a simple code that utilizes T4MVC, and then writing a blog that explains T4MVC came to my mind :)

While I am writing code, I am trying to avoid literal strings/magic numbers as much as possible and try to use strongly typed helpers/variables/etc instead. Obvious reasons are to have compile time support, intellisense,  easier maintainable code. Sometimes it is not that easy to replace the literal strings, such as if you have a link to a stylesheet, or an image source in the img tag, the strings are not easily replaced. Won’t you like the idea that the compiler will throw a compile time error when the css file is not found, or the image is not found?
Ex:

<link href="../../Content/Site.css" rel="stylesheet" type="text/css" />


The above 1 line of html is taken from the sample mvc application you get, when you go File=>New App=>MVC App..  How are we going to replace the source of the css link with a strongly typed helper? You can do this in a few different ways, but the real easy way is to use an open source project called T4MVC.  You can find more information about this project at Codeplex 
Basically it is a T4 template that helps you to remove the magic strings from your MVC projects, and it runs on Visual Studio 2008 as well as Visual Studio 2010. As a quick example the html line above that adds the css could be converted into:

<link href="<%=Links.Content.Site_css %>" rel="Stylesheet" type="text/css" />


As you can see, we remove the magic string of “../../Content/Site.css” and put a strongly typed helper. Now  let’s download the files from the codeplex, and work on the project that Visual Studio creates when you create a new MVC application. The next thing is drag the the files “T4MVC.settings.t4” and “T4MVC.tt” to the root of your project into the solution explorer. Visual Studio will pop up a warning:
image

As these two files are script files that use using T4 template, the scripts will have full access to your project, and Visual Studio is friendly! warning. Just click OK and skip this window.  Even before you compile, if you check the solution explorer, there are more files generated by the T4 template.

image

T4MVC examined your project, created a list of all the magic strings, and  prepared strongly typed helpers. One of the generated files is T4MVC.cs and it has 2 classes for your use in your project. Scripts and Content classes (it is not a coincidence that you have these folders in the project), both are static classes under the namespace of Links.  These 2 classes are full with const strings. These const strings are used to replace your magic strings in your project, and if you add more magic strings in the code, just compile the project, and T4MVC will create the new const strings too.
Now if you check the html code above one more time, you will see that we use that Links namespace, and Content class. In this Content class, T4MVC converted the magic string to a const string named Site_css. 

Let’s assume we want to add the Jquery-1.3.2.js file to our site.master page, we could either use the old magic string way:

<script src="../../Scripts/jquery-1.3.2.js" 
        type="text/javascript" language="javascript" />    


or, you can use T4MVC to help us and write:

<script src="<%=Links.Scripts.jquery_1_3_2_js %>" 
          type="text/javascript" language="javascript" />


This time we used Links namespace and Scripts class, as you can notice the folder names become the class names.
To display another helper, I added a new image to this project with the name of “hour_glass.jpg”.  To display this image I can either use the magic strings such as:

<img src="../../Content/hour_glass.jpg" alt=""/>


or I can use T4MVC to and write this:

<img src="<%=Links.Content.hour_glass_jpg %>" alt="" />


Up to now we remove the magic strings for the image and scripts, and styles, let’s see what we can do with links. In the default project, we have to links in the master page:

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


Let’s rewrite these with T4MVC helpers:

<li><%=Html.ActionLink("Home",MVC.Home.Index()) %></li>
<li><%=Html.ActionLink("About",MVC.Home.About()) %></li>


So what happened here? T4MVC created a static class called Home, (it also created the static classes for Shared, and Account), and created the function Index() which basically calls the Index action  of HomeController. If the Index action has a parameter such as an integer then T4MVC will generated the code accordingly; an action that has a parameter of int:

public virtual ActionResult Index(int? id)


could be called like:

<li><%=Html.ActionLink("Home",MVC.Home.Index(5)) %></li>


So far, if you changed the signature of Index(), or delete the image , or change the name of the style you will get a compile error as they are all strongly typed helpers. Also Visual Studio helps you with intellisense to fill in those magic strings.
What if we want to remove the magic strings in the controllers too? Such as in the default MVC project, if you open the admin controller Logoff action is:

public virtual ActionResult LogOff()
{
    FormsAuth.SignOut();
    return RedirectToAction("Index", "Home");
}

This function has a magic string of “Index” and “Home”, we can use T4MVC to change these into strongly typed helpers too such as:

public virtual ActionResult LogOff()
{
   FormsAuth.SignOut();
   return RedirectToAction(MVC.Home.Index());
}


How about the routes in the global.asax.cs file? An example route:

routes.MapRoute(
   "Default",                                             
   "{controller}/{action}/{id}",                          
    new { controller = "Home", action = "Index", id = "" } 
 );


and this is how it is replaced using T4MVC:

routes.MapRoute("t4mvc",
  "{controller}/{action}/{id}",
   MVC.Home.Index()
 );

And the form we have in the Logon.aspx page of the AccountController:

<% using (Html.BeginForm()) { %>


could be converted into:

<% using (Html.BeginForm(MVC.Account.LogOn())) { %>


T4MVC works in routes, in views, in controllers, almost anywhere :), it has some problems too such as if you create a new folder, and add content to that folder, T4MVC won’t recognize this new folder, however it has good community support and these small items may be fixed, it also has some other support for MVC 2.0 and you can check these from its codeplex website.



Tags: ,

E-mail | Permalink | Trackback | Post RSSRSS comment feed 4 Responses