英文地址:http://mvccontrib.codeplex.com/wikipage?title=T4MVC_doc&referringTitle=T4MVC
以下是翻译的文档,发现不正确或翻译不到位之处,欢迎指出。
1、介绍
T4MVC是为ASP.NET MVC应用程序创建的强类型T4模板,主要用于消除在使用Controllers、Actions和Views时的字符串。它有助于使你的MVC代码更容易维护,并且能给你在普通状态下输入代码不能提供的智能提示。T4MVC最初是David Ebbo在他博客文章上发表出来的,之后社区的反馈使其增添了许多新的功能。
T4MVC在Visual Studio 2008 SP1和Visual Studio 2010中均可以运行,并同时支持ASP.NET MVC 1.0和2.0。
只需简单地下载zip文件并且将T4MVC.tt和T4MVC.tt.settings.t4同时复制到您的MVC应用程序的根目录下。您应该可以马上看到在T4MVC.tt的作用下Visual Studio产生了一些文件。
这些生成的文件作用于整个应用程序,也就是这些脚本可以实现字符串的强类型替换。下面的文档将给出完整的脚本列表。
2、脚本
下面的文档不同于正式的说明文档,我们只是通过实例来演示在各种情况下T4MVC是如何提高你的代码质量。例子将通过前后的格式对比来指出变化之处。
注:下面给出的例子均是基于Nerd DinnerMVC应用程序。
2.1 使用View Name常量
任何时候,您会使用一个字符串来指向你的View,T4MVC将提供一个强类型的替代。例如,假设您有一个View的代码如下:
<% Html.RenderPartial("DinnerForm"); %>
这么难看的“DinnerForm”字符串让它见鬼去吧!相反,您现在可以这样抒写:
<% Html.RenderPartial(MVC.Dinners.Views.DinnerForm);%>
当您需要使用一个Controller里面的View时,事情变得更加容易。例如,您可以将:
return View("InvalidOwner");
替换成:
return View(Views.InvalidOwner);
注意:因为代码已经在Dinner的controller里面了,所以您可以省略MVC.Dinners前缀。
2.2 关于Controller Actions
许多MVC的API都有这样一个模式,当你需要指向一个Controller Action时需要包含三个信息:
Controller Name (经常会在当前Controller下隐藏Name)
Action Name
传递给Action的参数
这些可以理解为字符串#1、#2和匿名对象#3。例如:
<%= Html.ActionLink("Delete Dinner", "Delete", "Dinners", new { id = Model.DinnerID }, null)%>
在这里,“Delete”和“Dinners”是我们要替换掉的的字符串。但是这还不是全部,因为“id”参数同样和其他两个字符串一样也需要替换掉。即使它看起来并不像一个字符串,这只不过是它的变相而已。可别让那些匿名对象欺骗了你。
有了T4MVC,相反,您应该这样写:
<%= Html.ActionLink("Delete Dinner", MVC.Dinners.Delete(Model.DinnerID))%>
我们基本上替换掉了三个不必要的字符串(“Delete”,“Dinner”和“id”),取代他们的一个看起来比较舒服的方式来调用Controller Action。当然,这不是真的去调用Controller Action,这样是非常错误的。它调用方法的原理是将其转化为正确的路径。
这种方法的另外一个很大的好处是,当你在抒写代码时可以得到完整的智能代码提示。事实上,如果你使用类似ReShaper具有重构功能的工具,你甚至可以得到更多关于重构的支持。
添加额外的路径参数
在某些情况下,您可能需要将Action方法参数不存在的值添加到路径中。您可以这样做:
Html.ActionLink("Delete Dinner", MVC.Dinners.Delete(Model.DinnerID) .AddRouteValue("foo", 17))
您可以用这种方式很顺利的添加多个值。例如:
Html.ActionLink("Delete Dinner", MVC.Dinners.Delete(Model.DinnerID) .AddRouteValue("foo", 17) .AddRouteValue("bar", "abc"))
作为添加多个值的替代,您也可以这样写:
Html.ActionLink("Delete Dinner", MVC.Dinners.Delete(Model.DinnerID) .AddRouteValues(new { foo = 17, bar = "abc"}))
注意到在某些情况下,一些数据并非来自URL而是来自表单,您可能想在这样的路径中省略Action的参数。这时,您可以使用参数覆盖掉T4MVC生成路径参数。例如
Html.ActionLink("Delete Dinner", MVC.Dinners.Delete() .AddRouteValues(new { foo = 17, bar = "abc"}))
现在假设您要在所有T4MVC产生的代码中添加查询字符串,您可以使用AddRouteValues()重载需要的NameValueCollection。例如:
RedirectToAction(MVC.Home.MyAction().AddRouteValues(Request.QueryString));
这些都在现有的API中增加了一套 AddRouteValue / AddRouteValues方法,使其更容易应对各种不同的场景。
这些API使得我们在给路径添加额外的参数时不再需要重载所有的T4MVC helper了(例如上面提到的Html.ActionLink这种情况)。相反地,它会自动应用到任何使用T4MVC模式的方法里。
许多使用T4MVC的地方常常可以看见伪调用Controller Action的方式:
2.2.1 Html.ActionLink
Ok,关于Html.ActionLink的使用方法上面的例子已经涵盖了(这里就不在赘述)。
2.2.2 Url.Action
<%= Url.Action("Delete", "Dinners", new { id = Model.DinnerID })%>
变成:
<%= Url.Action(MVC.Dinners.Delete(Model.DinnerID))%>
2.2.3 Ajax.ActionLink
<%= Ajax.ActionLink( "RSVP for this event", "Register", "RSVP", new { id=Model.DinnerID }, new AjaxOptions { UpdateTargetId="rsvpmsg", OnSuccess="AnimateRSVPMessage" }) %>
变成:
<%= Ajax.ActionLink( "RSVP for this event", MVC.RSVP.Register(Model.DinnerID), new AjaxOptions { UpdateTargetId="rsvpmsg", OnSuccess="AnimateRSVPMessage" }) %>
2.2.4 RedirectToAction(Controller代码)
return RedirectToAction("Details", new { id = dinner.DinnerID });
变成:
return RedirectToAction(MVC.Dinners.Details(dinner.DinnerID));
2.2.5 routes.MapRoute(通常在Global.asax)
routes.MapRoute(
"UpcomingDinners",
"Dinners/Page/{page}",
new { controller = "Dinners", action = "Index" }
);
变成:
routes.MapRoute(
"UpcomingDinners",
"Dinners/Page/{page}",
MVC.Dinners.Index(null)
);
2.2.6 Html.BeginForm
从本质上讲,BeginForm()和ActionLink()的使用方法相同。但要注意,因为表单提交的数据通常都是来自于form,这一点不同于其它数据是来自URL参数。BeginForm()相比其他方法运用起来会比较复杂一些。
下面教你如何使用:
using (Html.BeginForm(MVC.Account.LogOn(), FormMethod.Post)) { ... }
如果您的Action方法有很多参数,您会在调用时提交这些参数。然而,当您这样做时,您要确保您在表单中提交时没有相同名字的参数名。(例如,使用一个文本框)。
一般来说,经验法则告诉我们当您的Action方法参数刚好和URL的一样时,Html.BeginForm()也能处理的相当好。
2.2.7 Html.RenderAction和Html.Action(只在MVC 2或更新版本)
Html.RenderAction和Html.Action对于MVC 2来说是新的东西。更多详细信息可以参考Phil Haack’s post。
<%= Html.Action("Menu", new { options = new MenuOptions { Width=400, Height=500} })%>
变成:
<%= Html.Action(MVC.Home.Menu(new MenuOptions { Width=400, Height=500})); %>
Html.RenderAction同样也是这样使用。
2.3 强类型的脚本链接和静态资源
T4MVC会为您的静态内容和脚本文件生成一些静态的helper。因此,下面代码可以
<img src="/Content/nerd.jpg" />
替换成:
<img src="<%= Links.Content.nerd_jpg %>" />
同样的,脚本链接可以这样替换:
<script src="/Scripts/Map.js" type="text/javascript"></script>
替换成:
<script src="<%= Links.Scripts.Map_js %>" type="text/javascript"></script>
显然,这样做的一个好处是当您在移动或重命名静态资源后,可以尽早地在编译时就能发现这个错误(而不必等到部署之后才发现)。
另一个好处是,您可以得到一个更全面的参考。当您抒写 src=”/Content/nerd.jpg”,它只有在您的网站页面部署在根目录下才会有效。但是您使用了这个helper后,无论您的根目录在哪里,它在服务端执行一些判断后就能正确产生资源的路径。它是通过调用VirtualPathUtility.ToAbsolute(“~/Content/nerd.jpg”)来实现的。
不幸的是,有些原因致使VS在View中抒写代码时不能智能地提示。但有一种变通的方法,您可以在标签外部用智能提示的抒写后再复制到链接中。
重要说明:如果您看到您的<head>标签生成了奇怪的链接,您只需要删除runat=”server”即可。
支持压缩的Javascript文件
通常情况下你运用各种方法来压缩JavaScript文件,再去替换版本,这样做只是为了使它们尽可能的小,比如说去除JavaScript文件中的空白部分。比如在您的MVC应用程序的Script文件夹中通常可以看到两个文件存在jQuery.1.3.2.js和jQuery.1.3.2.min.js。在部署环境中,您通常想使用压缩后的版本,但是在开发环境下喜欢更容易调试的原版本。
T4MVC可以根据场景自动地使用一个版本。例如,假设您有:
<script src="<%= Links.Scripts.jquery_1_2_6_js %>" type="text/javascript"></script>
您不需要改变任何代码,T4MVC根据您正在运行Production环境来决定将做过标记的jquery_1_2_6_js自动指向jQuery.1.3.2.js或jQuery.1.3.2.min.js。它是如何知道您是否是在Production环境下呢?它是通过调用了一个在T4MVC.tt.settings.t4定义好的方法来判断的。在默认情况下,它会先判断下这个方法:
// Logic to determine if the app is running in production or dev environment public static bool IsProduction() { return (HttpContext.Current != null && !HttpContext.Current.IsDebuggingEnabled); }
如果您对“Production”有另外的环境定义,也可以很容易地改变这个判断。
2.4 在MVC 2 的“Areas”使用T4MVC
MVC 2中的主要新功能之一是将一个大型应用程序分解成许多的“Areas”。这种结构可以这样来描述:
T4MVC会自动作用于“Areas”并且使得他们同样存在于Model中。下面是一个例子:
<%= Html.ActionLink("Delete Dinner", MVC.NerdDinner.Dinners.Delete(Model.DinnerID))%>
请注意我们是如何引用MVC.NerdDinner.Dinners Controller的。如果您碰巧有一个和“Areas”名称一样的顶层Controller,这样的命名模式将会导致冲突。在这种情况下,T4MVC会在名字后面追加“Area”关键字来避免冲突。例如,如果您同时有一个Home Area和一个Home Controller(顶级的),您应该使用MVC.HomeArea.Hello来指向Area。
您可以在设置文件中可选地设置IncludeAreasToken为true。这样的命名方式就变成:
<%= Html.ActionLink("Delete Dinner", MVC.Areas.NerdDinner.Dinners.Delete(Model.DinnerID))%>
注意到在上面这种情况下,上述的冲突就不会发生了。但是这样做需要付出在更多的地方使用分段的代价。我也在考虑是否要保持这种方式,但是现在的默认方式已经很好了。
3、调整行为的T4MVC
当您下载T4MVC,您不仅获得了它主要的T4MVC.tt模板,同时您也获得了名为T4MVC.tt.settings.t4的文件。这个文件包含了T4MVC的各种设置,您可以用它来调整T4MVC生成的代码。本节将介绍它的各种设置:
Set AlwaysKeepTemplateDirty to false to turn on the always-dirty behavior
// If true, the template marks itself as unsaved as part of its execution. // This way it will be saved and update itself next time the project is built. // Basically, it keeps marking itself as unsaved to make the next build work. // Note: this is certainly hacky, but is the best I could come up with so far. bool AlwaysKeepTemplateDirty = true;
Set SplitIntoMultipleFiles to false to generate a single file with everything
// If true,the template output will be split into multiple files. bool SplitIntoMultipleFiles = true;
Use HelpersPrefix to change the MVC prefix of the genrated classes
// The prefix used for things like MVC.Dinners.Name and MVC.Dinners.Delete(Model.DinnerID) const string HelpersPrefix = "MVC";
Use ControllersFolder and ViewsRootFolder to rename the Controllers and Views folders
// 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";
Use LinksNamespace the generated links’ namespace
// The namespace that the links are generated in (e.g. "Links", as in Links.Content.nerd_jpg) const string LinksNamespace = "Links";
Use StaticFilesFolders to tweak the list of folders from which links are generated
// Folders containing static files for which links are generated (e.g. Links.Scripts.Map_js) readonly string[] StaticFilesFolders = new string[] { "Scripts", "Content", };
4、相关资源
David Ebbo has written a series of blog posts on T4MVC
Scott Hanselman also blogged about it here
Last edited Aug 14 2011 at 4:09 PM by davidebbo, version 5
原文地址:http://mvccontrib.codeplex.com/wikipage?title=T4MVC_doc&referringTitle=T4MVC