每周源代码43 – ASP.NET T4以及NerdDinner


[原文发表地址] The Weekly Source Code 43 – ASP.NET MVC and T4 and NerdDinner

[原文发表时间] 2009-06-25 15:38

更新:David已将改良升级后的T4模板发布在CodePlex,此处最后一次提供下载

我十分提倡大家尽可能多地阅读源代码,因为如果要提升自我,使自己成为一名更好的作者,就必须勤读勤练笔。这也是《每周源代码》的初衷——勤读代码,有助于成为更高水准的开发者。

在开源项目中读代码是一种很好的学习方法,尤其是在项目趋于成熟和成功,或者你钦佩工作在项目上的团队。至少,通过检索和共享代码,你能找到一些代码片段。

David Ebbo惊人的聪明。你知道有人很聪明,他们遇到什么问题的时候可以迎刃而解,虽然你知道你处于同样位置的时候就一筹莫展了,但你还是会懊恼为什么自己不能先想到这样的方法。

David一直在反复试验,寻找优化ASP.NET MVC的方法,尤其是在强类型的helpers。他试着要去掉strings, magic或其他形式。

他从BuildProvider着手(不是很多人了解BuildProviders,因为这是个强大的秘密)。David不喜欢ASP.NET MVC里的这些链接:

 1: <%= Html.ActionLink("Home", "Index", "Home")%>

所以他的BuildProvider被加进web.config:

 1: <buildProviders>

 2: <add extension=".actions" type="MvcActionLinkHelper.MvcActionLinkBuildProvider" />

 3: </buildProviders>

这会帮你找到一些更好的方法,围绕你的项目动态生成helper方法:

 1: <%= Html.ActionLinkToHomeIndex("Home")%>

几天后,David有了T4的信念我说过我们在推动它这个方面做得不佳,所以我正将此告诉给我认识的每个人)而你应该也尝试。David探索了CodeDom 与CodeGen的 T4的利弊,然后用T4重设了ASP.NET MVC的Helpers

image_7他不仅优化了ActionLinks,还优化了Action Url Helpers,视图名称常量以及一个很聪明的事,视图模型的helpers,简直是David Fowler创造的奇迹。

我觉得这太酷了,因为这是个很棒的例子,当你怀着设计时的初衷,开始探索编译时所获知的信息,这个例子就告诉了你使用代码生成可以做什么。它还提示我们这不只是 编译/测试/运行, 通过检查/代码生成/编译/测试/运行 你的程序将变得更“元”。

比如,如果你有一个ViewModel,含有一个字符串:

 1: <label for="Name">Name:</label>

 2: <%= Html.TextBox("Name", Model.Name) %>

 3: <%= Html.ValidationMessage("Name", "*") %>

为什么不用这样的呢:

 1: <%= ViewModel.Name.Label() %>

 2: <%= ViewModel.Name.TextBox() %>

 3: <%= ViewModel.Name.Validation() %>

这个ViewModel是早期的CodeDom模板,但不是T4模板。我希望我们能再次看到,你也一样吧?亲爱的读者们,你们怎么认为呢,这种方法和”Opinionated Input Builder“方法,哪个更好呢?

就在前不久,David公布了他“最新优化”的MVC T4模板,我觉得你不容错过。我极力地劝他把这个模板放到CodePlex上去,让更多人获益。(快去告诉他Phil!)

他在运行时做了些工作,但是也回到了纯粹的设计时方案。

David EbboASP.NET MVC T4模板应用在Nerd Dinner

David 把NerdDinner作为基础,在其上安装了他的T4模板。只是把它拖进去,魔法生成了。不过这是怎么做到的呢?

image_d417b977-3d4c-4d3c-88e6-438b7a32582c以前他用的是reflection,但由于这是Design Time Code Generation进程,他必须进一步深入*gasp* COM-based VS File Code Model API。但这真的秀出了T4本身的强大和灵活性。David直面COM而不退缩,真是无比的荣誉。

下载他的模板直接下载ZIP)并打开

T4文件在文本编辑器里看起来很恐怖,因为它们不停地在<% code blocks %>和生成的代码间切换。我用Notepad2来阅读,(有趣的是)XML Document选项会提供给我简单的语法高亮。

如果你想认真研究T4,下载Clarius的Visual T4 社区版本,以获得half-way 语法高亮,或者付费购得Professional Edition。他们会通过Visual Studio自动注册,比起全黑文本,它会给你更好的体验。

David的T4模板里,第一句让我忍俊不禁的是执行的第一行:

 1: <# PrepareDataToRender(this); #>

就像他们所说的,这个很有趣因为它是真的。这在各种代码生成模板中都很典型。正是”DoIt()”方法提取了左手边的代码(the COM crap)并将右手边的准备就绪(模板本身)。

为了使David的模板更整洁,有很好的抽象的整洁感:

 1: <# foreach (var controller in Controllers.Where(c=>c.IsPartialClass)) { #>

 2: namespace <#= controller.Namespace #> {

 3: public partial class <#= controller.ClassName #> {

 4: protected RedirectToRouteResult RedirectToAction(ControllerActionCallInfo callInfo) {

 5: return RedirectToAction(callInfo.Action, callInfo.Controller, callInfo.RouteValues);

 6: }

 7: ...snip...

…他不得不准备一个对象模型,而那就是PrepareDataToRender的工作。这也很好玩,因为它是被隐藏在最后面,应该是的。介于它只是个415行的模板,读代码或者做其他的都不费力。

他有很多可爱的小帮手们,像这个一行helper函数,。使用Visual Studio API,结合了COM、LINQ和magic等各种方法来辅助他的模板。我觉得”functionFunction” 枚举很好笑,“你喜欢她吗?或者你喜欢她喜欢她吗?”

 1: // Return all the CodeFunction2 in the CodeElements collection

 2: public static IEnumerable<CodeFunction2> GetMethods(CodeClass2 codeClass) {

 3: // Only look at regular method (e.g. ignore things like contructors)

 4: return codeClass.Members.OfType<CodeFunction2>()

 5: .Where(f => f.FunctionKind == vsCMFunction.vsCMFunctionFunction);

 6: }

David显然还在不断深入探索,而且非常需要你对此设计的看法。我鼓励你们给他源源不断的反馈,或者直接在我这儿留言,我可以帮忙转告他。;)


Comments (0)

Skip to main content