To get the latest build of T4MVC:

Go to T4MVC page on CodePlex

This post is a continuation of various previous posts on the T4MVC template for ASP.NET MVC:

I last blogged about version 2.2, and there have been a number of changes since that (you can get the full history at the top of the T4MVC.tt file).  This post describes some of those changes.

T4MVC now uses a separate settings file

Previously, if you wanted to customize T4MVC, you’d have to change T4MVC.tt directly.  This is fine until you want to grab the next build, and have to hand merge the changes.

Instead, it is now using a separate settings file called T4MVC.settings.t4.  The idea is that you can tweak some behavior by changing this file, without changing the main file.  Make sure that you copy both files when you grab 2.4 or later!

Note: it uses a .t4 extension instead of .tt, because we don’t want VS to process it directly.  Instead, it’s included by the main .tt file.  What’s nice is that the .t4 extension is also recognized by Clarius’ Visual T4.

Currently, it doesn’t support all that many settings, but it’s only a first step.  The idea is that as more customization scenarios come up, new things will appear there.  Of course, you may need some small hand merging of the settings files when you update to newer versions, but that’s a lot less painful than merging the main .tt file.

Here is what it contains in 2.4.00:

// The prefix used for things like MVC.Dinners.Name and MVC.Dinners.Delete(Model.DinnerID)
const string HelpersPrefix = "MVC";

// The folder under the project that contains the controllers
const string ControllersFolder = "Controllers";

// The folder under the project that contains the views
const string ViewsRootFolder = "Views";

// Folders containing static files for which links are generated (e.g. Links.Scripts.Map_js)
readonly string[] StaticFilesFolders = new string[] {
    "Scripts",
    "Content",
};

Support for views in sub folders

I have had a few users mention that they sometimes don’t put their views directly under Views\CtrlName, but instead put them in a subfolder.  e.g. you might have Views\Dinners\Sub\Details.aspx.

Previously, T4MVC was ignoring those.  Now, it finds them and makes them available using a matching hierarchy.

So when you have Views\Dinners\Sub\Details.aspx, you can refer to it as

MVC.Dinners.Views.Sub.Details

or if you’re within the Dinners controller, you can just write:

Views.Sub.Details

And this will evaluate to "Sub/Details".

Support for [ActionName] attribute

Suppose you have an action method that looks like:

public virtual ActionResult Details(int id) {

By default, the action name is just the method name: “Details”.  That is, this is what normally shows up in your URLs, e.g. /Dinners/Details/2.

But sometimes, you want your action name to be different from the method name, and that’s when you would use the MVC ActionName attribute.  e.g.

[ActionName("NewActionName")]
public virtual ActionResult Details(int id) {

And now your URLs start looking like /Dinners/NewActionName/2.

Except that previously, T4MVC was ignoring this attribute, causing it to still generate the old URL!  Now, it correctly locates and honors the attribute.

The beauty is that T4MVC completely shields your code from those changes.  Without it, you’d have written:

<%= Html.ActionLink(dinner.Title, "Details", new { id=dinner.DinnerID }) %>

And you would have had to change “Details'” to “NewActionName”.  But with T4MVC, you just write:

<%= Html.ActionLink(dinner.Title, MVC.Dinners.Details(dinner.DinnerID)) %>

And it keeps on doing the right thing no matter what the ActionName is set to!

New parameter-less overload for all actions

Previously, T4MVC was only offering pseudo-action calls that had the exact same signature as the real action method.  This usually works well, but in some POST scenarios, the parameters comes from the form and not the URL.

To solve this, T4MVC now always generates a parameter-less overloads.  e.g. suppose your action looks like:

[AcceptVerbs(HttpVerbs.Post), Authorize]
public virtual ActionResult Edit(int id, FormCollection collection) {

Where both the id and the FormCollection are things that you don’t want to pass explicitly, you can write:

<% using (Html.BeginForm(MVC.Dinners.Edit())) { %>

So you still get the benefit of not hard coding the controller and action names (what T4MVC is all about), even though you’re not using the signature that matches your real action.

Support for placing T4MVC.tt below the root of the app

Previously, T4MVC.tt had to be at the root of the MVC web application.  Some users mentioned that they preferred to have it in some other folder, like ‘Templates’.  So I made a change so it can be anywhere under the project root.

Bug fixes

There are also a number of bug fixes that are not interesting enough to discuss individually.  Please see the history at the top of T4MVC.tt for details.