You've been HAACKED中文版

英文原版地址:http://haacked.com

Phil Haack attemts to infuse technology and software development with humor and a pragmatic eye...

随笔 - 43, 评论 - 13, 引用 - 0

导航

关于

Phil Haack先生是著名博客引擎Subtext的主要开发人员,目前在微软总部担任资深程序经理,主要负责MVC架构相关的内容. 博客堂非常高兴成为Phil Haack先生中文版博客的存放站点,将更多关于ASP.NET MVC架构相关的知识与大家分享.为了保证翻译质量,现在面向所有博客堂堂友征集本博客的负责人员以及两名志愿翻译人员.

每月存档

最新留言

广告

【第1页/共5页,43条】
首页
前页
1
2009年10月05日

【原文地址】ASP.NET MVC 2 Preview 2

【原文发表日期】 Oct 01, 2009

今天我们发布了ASP.NET MVC 2预览版 2 (基于Visual Studio 2008 SP1以及ASP.NET 3.5 SP1),这是在两个月前发布的预览版 1 的基础上所做的一些新工作。

- 下载

- 发行注记

- 规划蓝图

- 源代码以及实验性内容(CodePlex)

以下是一些预览版2中新增的很酷的功能:

- 客户端验证(Client-Side Validation)- ASP.NET MVC 2包含了jQuery验证库以便提供基于模型元数据的客户端验证。你也可以通过编写自己的适配器(adapter)来将其他你所习惯的客户端验证库和JSON元数据适配起来,就像xVal验证框架(xVal Validation Framework)所做的那样。

- Areas - 预览版2提供了在单个项目中使用Areas的支持,这允许开发者不必建立多个项目来组织他们的应用程序。Areas的注册方式也已经简化了。

- Model Validation Providers - 这将允许开发者在绑定模型(model binding)的时候提供自己的验证逻辑。默认的验证方式是数据标记(Data Annotation)

- Metadata Provides - 允许开发者为模型对象提供其他的元数据源(metadata source)。默认的元数据提供者使用的是数据标记(Data Annotation)

从上表可以看出预览版2的一个主题。在预览版1中,我们将许多功能直接与数据标记属性联系起来,而在2中,我们在使用数据标记的基础上加入了一个抽象层,这样就可以使开发者可以为的验证方式和元数据提供者引入自定义的实现了。

例如,开发者现在可以使用企业库的验证模块(Enterprise Library Validation Block)来替换默认的验证方式。此外,也只要少量工作,便可以将模型的元数据存放在另外的地方,而不是属性中。

在Visual Studio 2010的进展

本次发布的工具组只能在Visual Studio 2008 SP1中运行。我们打算将ASP.NET MVC Preview 2 for Visual Studio 2010和Visual Studio 2010 Beta 2一起打包发布,这样你就不用四处寻找了独立的安装包了。同样的,ASP.NET MVC 2的正式版也会和Visual Studio 2010正式版一起发布。

因此,如果你想试试在ASP.NET MVC 2 Preview 2中使用新的HTML encoding code blocks功能,那你还得耐心等到Visual Studio 2010 Beta 2发布。不过至少现在你可以去试试VS 2008中的预览版2,并且给我们提供宝贵的反馈意见

posted on 2009-10-05 17:19:24 by demonfox  评论(0) 阅读(2724)

 
2009年07月28日

【原文地址】And Get Rid Of Those Pesky Programmers

【原文发表日期】 Jun 12, 2009

 

【狐言乱语:说实在话,我觉得这篇文章写得很糟糕。从哲学角度而言,这里并没有太深层的见地。从文章的逻辑来看,甚至可以说是有些散乱的… 那些所提及的道理(比如最后一段)也不见得有太大的新意…】

 

时不时地总会有些电子邮件或者网站文章里会提到他们保证能证明Fred Brooks在他的人月神话(强烈推荐阅读!)中所提出的疯狂的“没有银弹”的理论是错误的。如果有“银弹”,那我们在下一个十年中所能取得的在生产效率、可靠性、和简洁性方面的进步将会以十倍计。

这一次,我们所听到的保证也和从前大同小异,不过这次的保证人觉得有必要郑重指出他们革命性的新程序/框架/神奇的发明可以是业务分析师直接以十倍速来开发应用程序而且完全不需要借助专业程序员的工作!

哦,好耶!让我们摆脱这些讨厌的身上有股怪味的程序员吧!我们不需要他们了!”

不过,请看在上帝的份上帮帮忙等那么一下下!你确定么?!

我现在正尽力使自己忘了他们所说的以免无法控制自己最直接的条件反射,那就是直接把对方当成脑残而无视掉。如果我是一个反应过激的人,很显然我最先想到的一个恼人的问题就是:

“为啥这些商务人士如此热衷于摆脱我们这些程序员”

我们很容易把这简单归罪于这些穿西装的家伙不懂软件开发这事儿,从而迫使自己和Tom Smykowski一样开始为我们具体在这儿干些什么进行辩护:

“好吧好吧,你瞧,我已经告诉你了:我和那些该死的客户打交道,这样那些工程师就不必为此伤脑筋了。我有和人打交道的能力;我善于和人打交道。你们怎么就不懂呢?你们这些人到底有什么毛病?”

也许吧,就如Steve “Doc” List在最近一期MSDN杂志的End Bracket article专栏上引用的Cool Hand Luke里的一句关于“有效交流”的台词所说的那样:

“我们所面对的是一种失败的交流”

Leon Bambrick(也就是SecretGeek)最近在他的这篇帖子里谈到了这个现象:The Better You Program, The Worse You Communicate,在文章中,他解释了为什么很多使我们成为高效的软件研发人员的素质却没能在人际交流的方面给予我们同样的帮助。

归根结底,我们有些时候确实会使人觉得很难相处。我们经常全神贯注于技术方面的难题或者解决方案的局限,以致我们会不知不觉地用一大套专用术语把那些利益相关人士(stakeholders)搞得云山雾罩的,或者我们干脆把他们的需求形容为无理取闹从而直接把他们惹恼了。有些时候,我们失职于无法深入理解他们业务于是我们就干脆开始取笑他们而不是真正地区了解他们所需要的。难怪到最后他们会希望能自己来干编程的活了呢!

好吧,好吧。情况并不总是这样的。不是每个程序员都是这般作为,所以如此批评每个开发人员并不公平。我其实也只是想强调并理解支撑这个想法的观点:也就是将程序员排除在外会是件好事。

相当一部分的批评应该归咎于那些兜售蛇油的推销员们(译注:snake oil salespeople,通常指兜售一些无实际效果的所谓神奇药品的江湖骗子;此处指推销上面所提到的快速自动软件开发平台的销售人员),因为在目前的情况下,他们是在推销一个谎言。他们试图使用户相信的是每个普通的业务人员都可以用自己的语言向那个神奇的软件描述他们所面对的业务逻辑,然后那个神奇的软件就会自动生成所需的应用程序了。

前些天,我发了一个内部的电子邮件用很通俗的语言描述了一个我觉得会很有意思的功能。几小时后,我的同事已经有了一个实现的雏形可以演示了。

朋友们,这,才是最牛逼的指令式编程(declarative programming)呢。我只要把自己的意图描述出来,然后稍等一会儿,接着,哗啦一下!代码就出现了!也许这就是那些神奇的软件所想要达成的事,不过这里有个问题。我举的这个例子中,我是把需求提交给了一个人类同胞。如果我的那个电子邮件是发到某个软件那里去了,那它恐怕是不知道应该为我做点什么的。

在将来的某个时候,也许会有软件可能具备上述的一些功能,不过这只有在软件达到相当成熟的人工智能和真正懂得如何处理模糊概念后才有希望。换句话说,只有当软件自己成为程序员时,你才可能摆脱人类程序员。不过我还是要遗憾地指出,你其实还是在和一个程序员打交道,只不过那是一个不会傲慢地对你的需求嗤之以鼻的无机体(至少不会当着你的卖弄如此,当然,它可能私下里正在盘算如何统治全世界呢)。

在那一天到来之前,当一个业务人员使用上面所提及的那个神奇的框架来自己编制出一个如乐高积木般精确的程序时,这个小业务员实际上有成为了现实意义上的程序员了。这样的工作其实和一个真正的开发人员所需掌握的技术已经相去不远。所以在如此情况下,你并没有真正摆脱程序员这个概念,你只是将一个业务人员转职成了一个开发人员,一个正巧也懂得业务规范的开发人员。

归根结底,不论你的系统有多指令化(“declarative”)有多傻瓜式,以至于一个非开发人员也可以通过在屏幕上把一些小控件拖来拖去就拼成一个应用程序,在这套模式中,能够被允许的概略性和模糊性是很少很少的。而概略和模糊的概念,恰恰是电脑所不擅长而人类所擅长处理的,这正如Spock在一集Star Trek中所提到的:

“计算机,请计算PI的最后一位数字” – Spock

除了这些,你还应该再想到在完成一个应用程序的过程中有很大一部分的实际工作并非是撰写代码,而且所有围绕着这个任务所展开的调查研究,正如Udi Dahan在他的“重用的谎言和误区”一文中所提到的。

说了这么多并不说明我认为我们应该停止投资开发更加完善的工具。毕竟,软件开发的历史就是一部不断改进高层工具从而提高开发者生产效率的历史。我所观察到的危险在于那些试图摒弃无论使用何种工具来开发程序都需要用到的原则和特性的所谓方法论。

即使有一天你能够用人类的语言来告诉电脑你所想要的,而且电脑也可以就此工作,我们还是需要重视软件开发的原则,确保质量检查,测试,等等这些不变的标准。

对于我们程序员来说,我觉得我们应该从中学到两点。首先,我们必须向利益相关人士(stakeholders)介绍软件编写的真正流程是如何的。即使他们无心倾听,一点点的了解和理解都会有长远的帮助。我们要有耐心,不要摆出居高临下的姿态,并且要对结果有最好的期待。其次,我们也该要求自己对所面对的业务有更深层的理解和见地,从而我们在别人眼中的就成长为一个有价值的商业伙伴,只是,我们也碰巧写点真正有空的程序罢了。

posted on 2009-07-28 16:36:59 by demonfox  评论(0) 阅读(3587)

 
2009年07月16日

【原文地址】ASP.NET MVC Installer For Visual Studio 2010 Beta 1 And Roadmap

【原文发表日期】 Jun 09, 2009

不久之前我公布了我们就关于ASP.NET MVC与Visual Studio 2010平台的集成的一些计划。ASP.NET MVC并没有包括在日前发布的Beta 1里面,这个决定引起了一些朋友的猜测和关注(甚至还有人怀疑这里有什么阴谋!); )  其实真正的原因就是如我所说明的:

你可能会注意到ASP.NET MVC并没有包含在Beta 1中。主要的原因是Beta 1在MVC 1.0发布之前已经内容锁定了(译注:lock down;微软内部指一个产品只修改bug不增加功能的阶段)。而VS10 Beta 2里会包含ASP.NET MVC。

我们正在努力设法完成一个编外的安装程序来在VS2010 Beta1环境下安装ASP.NET MVC的项目模版和工具,预计会在六月的某个时间通过CodePlex发布。所造成的不便,敬请见谅。我会在第一时间写博客通知大家的。

今天我高兴地向大家宣布,我上面所说的安装程序已经完成了,你可以在CodePlex上找到它并下载。请一定尝试一下这个新东东,因为很多VS10所支持的测试驱动开发(TDD, Test-Drive Development)方面的新功能和ASP.NET MVC有着紧密的联系,关于这点ScottGu会在下一则博客中进行介绍。

如果你在使用过程中遇到任何困难,你可以参考一下Jacques的这篇帮助指南,Jacques是这个安装程序的主要开发人员,所以也请不吝提供您宝贵的反馈意见。

你可能会注意到这个安装程序自称是ASP.NET MVC 1.1版本,但正如ReadMe中所提及的,这个其实只是ASP.NET MVC 1.0针对Visual Stuido 2010重新包装后的版本。1.1这个版本后只是个占位符。我们有意递增了版本号以避免与ASP.NET MVC 1.0有任何运行时的冲突。所有这些以及其他更详细的概况可以在发行注记(Release Notes)里找到。

等到VS10 Beta 2发布的时候,你就不需要再下载一个额外的独立安装程序了(虽然我们还会给VS2008的用户发布一个支持ASP.NET 3.5 SP1的独立安装程序)。Beta 2会包含一个预览版的ASP.NET MVC 2,这也正是我在接下来的产品未来蓝图(Roadmap)中所要介绍的内容:

 

产品规划蓝图

我最近发表了一篇关于ASP.NET MVC 2的产品规划蓝图的文章,主要是从宏观角度介绍我们准备在ASP.NET MVC 2里增加的新功能。这些新功能的介绍很明显地缺少足够的细节,这主要是因为我们当前还在紧张地策划阶段以搜集更详细的用户所遇到的困难和需求。

当下,我们会尽量避免太过关注于实现细节。在设计软件的时候,人们总是很容易有先入为主的想法来决定某个问题的解决方法应该是如何如何的,而事实上,我们常常连究竟需要解决的是什么问题都还没搞清楚呢。

与其试图将人们导向我们所认为的答案所在,我更希望将注意力集中在确保我们能够正确认识我们所面对的问题的领域以及人们想从这个框架中所得到的是什么。这样做是我们有充分的自由区尝试各种不同的方案,有些甚至是通常不会想到去尝试的,比如编写基于表达式的URL帮助函数的其他途径。也许这些额外的尝试是成功的,也许不是。但最理想的,我觉得就是对于每个我们所想实现的功能,我们都能提供多种的设计选择。

在我们进行这些计划的同时,我也会持续地提供规划蓝图中更多的细节与大家分享。

 

快捷代码片段(Snippets,亦称Code Snippets)

VS10有一个很酷的新功能就是现在HTML editor也支持快捷代码片段了。Visual Web Developer team的Jeff King给我发来了我们打算在下一版中发布的那些代码片段。你也可以通过CodePlex的发布页来获取它们。安装也是十分简单的:

安装步骤:

1) Unzip "ASP.NET MVC Snippets.zip" into "C:\Users\<username>\Documents\Visual Studio 10\Code Snippets\Visual Web Developer\My HTML Snippets", where "C:\" is your OS drive.
2) Visual Studio will automatically detect these new files.

敬请各位下载并试用一下这些资源,并将你认为可以更有助于你开发工作的想法反馈给我们。

 

重要链接:

posted on 2009-07-16 15:54:15 by demonfox  评论(0) 阅读(2971)

 
2009年07月14日

【原文地址】An Alternative Approach To Strongly Typed Helpers

【原文发表日期】 Jun 02, 2009

MVC Futures项目有一个特色功能就是它允许开发者利用lambda表达式来生成强类型的动作响应链接(action links)。比如:

<%= Html.ActionLink<HomeController>(c => c.Index()) %>

上面的这行代码会生成一个指向HomeController的Index动作的链接。

这个技巧当然很优美,不过实际上它也有一些小问题。首先,它的语法就不像你高中毕业舞会上的舞伴那么吸引人。我猜你也许可以逐渐地去习惯它,不过很多人看见这段代码的第一反应就是觉得有点头晕。

另一个问题是在这个演示PPT中(是Brad Wilson告诉我的)所提到的效率问题。这组PPT的作者发现以上表达式的编译速度特别慢。

我之前以为我们可以通过某些利用缓存编译后的表达式的方法来缓解效率的问题,不过那也许无法解决一些现实问题。试想有如下的情况:

<% for(int i = 0; i < 20; i++) { %>
 
  <%= Html.ActionLink<HomeController>(c => c.Foo(i)) %>
 
<% } %>

在这个循环中的表达式看起来是不变的:c => c.Foo(i)

但实际上变量"i"的值在每一次循环中都是不同的。如果我们试着缓存编译后的表达式,大家可以想象将会发生的事情。

于是我开始思考能不能找到另一种利用自动代码生成来解决以上问题的方式,于是我写了一封内部的email与微软的同事们开始讨论。一个可行的方法是自动生成特定的动作响应链接的代码。遵循这个思路,那么Home控制器(Home Controller)的about链接(为了演示起见,我们加了一个id参数)就可以如下表示:

<%= HomeAboutLink(123) %>

Brad多次提到虽然他喜欢lambda表达式,但他却不喜欢用它们来表示一个动作响应链接,他更倾向于用上面所提到的这种格式来编写某个特定的动作链接的方法(译注:就是HomeAboutLink(123)这样的写法)。那么如果我们可以帮助开发者来自动生成这样的链接,那不是很棒么?

这个email讨论开始几个小时后,David Ebbo已经完成了一个初步的实现。也许他在此之前就自己考虑过这个问题并尝试过解决了,我不清楚,我那天一直在开会。这可能是世界上最好的表述型编程方法(declarative programming)了,我“表述”了我大致的思路,然后便干其他的事去了,过了一会儿,好,代码就已经有了!

David的方法是利用BuildProvider的来对解决方案(solution)中的控制器(Controllers)和动作(Actions)来进行反射(reflection),然后给每一个都生成各自的动作响应函数。这里当然还有很多可以改进的地方,比如确保自动生成的代码会保证ActionNameAttribute的设置并且生成重载的函数,不过这至少已经是一个很清晰的概念实现(proof of concept)了。

与基于lambda表达式的帮助函数相比这个方法有一个不足之处就是它无法提供对重构的

支持。不过,如果你重命名了一个动作函数,你将会得到一个编译期的错误而不是运行期的做错,因此这至少比什么都没有要强些。这个方法的优势自然是它的效率更快,而且,它也不依靠那看着恼人的lambda表达式的语法了。

以上讨论的内容是我们权衡中的下一个ASP.NET MVC版本里可能包含的一些有趣的改进。

posted on 2009-07-14 16:39:11 by demonfox  评论(0) 阅读(2652)

 
2009年07月01日

【原文地址】Writing A Page To A String

【原文发表日期】 May 29, 2009

ASP.NET页面通常是将它们内容直接输出到一个请求响应流(response stream)中。这对比较大型的页面来说应该是一个巨大的效率优化,因为这样做就不需要为页面显示而建立很大的缓冲区或者分配很大的字符串。而分配大型字符串的操作经常会在“大型对象堆栈”(Large Object Heap)上获取所需的内存,而这也意味着这些内存块不会被很快地资源回收。

 

 

 

然而,很多情况下你可能确实需要将一个页面的内容输出到一个字符串里以便进行一些后处理工作。关于这点,我N久之前也曾经写过一篇blog介绍了一个方法:就是使用response filter

不过,最近我学到了Page类中的一个我从没有注意到过的方法,这个方法提供了以上问题的一个更轻量级的解决方案。

我所说的就是CreateHtmlTextWriter这个方法,它是一个保护(protected)成员函数的,而且也是一个虚(virtual)函数的。

 

 

 

以下是一个页面code-behind的代码示例,其中利用了这个函数来对页面的输出内容进行过滤,经此处理后的内容才最终显示在浏览器中。

public partial class FilterDemo : System.Web.UI.Page
{
  HtmlTextWriter _oldWriter = null;
  StringWriter _stringWriter = new StringWriter();
 
  protected override HtmlTextWriter CreateHtmlTextWriter(TextWriter tw)
  {
    _oldWriter = base.CreateHtmlTextWriter(tw);
    return base.CreateHtmlTextWriter(_stringWriter);
  }
 
  protected override void Render(HtmlTextWriter writer)
  {
    base.Render(writer);
    string html = _stringWriter.ToString();
    html = html.Replace("REPLACE ME!", "IT WAS REPLACED!");
    _oldWriter.Write(html);
  }
}

在CreateHtmlTextWriter方法中,我们首先是调用基类的该函数来创建一个原来的HtmlTextWriter,然后将它暂时存放在一个成员变量中。

然后我们还是调用基类的函数来创建一个新的HtmlTextWriter,不过这个对象实例会使用我们自己的StringWrtier作为底层的TextWriter。被传入到Render函数中的HtmlTextWriter就是这个新创建的实例。(在Render函数中)我们首先对这个新的HtmlTextWriter实例调用基类的方法,然后将底层StringWriter的输出内容取出,这样就可以对该部分内容进行所需的处理了。我们最后将最终的输出内容写到原先的HtmlTextWriter中去,因为原先的这个HtmlTextWriter是真正负责将结果写到请求响应中去的。

使用这个技巧的时候有很多值得特别注意的地方。首先,如我先前所提到的,对于大型的页面,以上所做的这些事可能会大大地影响你网页的运行效率和可伸缩性。而且,我也没有针对输出缓存、异步页面等等的情况下测试过上面的技巧,所以你很可能会遇到意想不到的实际结果。

注意,如果你是需要从一个页面调用另一个页面,然后在第一个页面中得到后者的输出内容,那么你可以将你自己的TextWriter实例传到Server.Execute函数中并得到结果,所以这种情况下你无需借助上面所介绍的这个技巧。

posted on 2009-07-01 15:54:46 by demonfox  评论(0) 阅读(3155)

 
2009年05月21日

【原文地址】ASP.NET MVC For Visual Studio 2010 Beta 1

【原文发表日期】 May 18, 2009

我本打算这个周末写这篇东西的,可是很抱歉那两天的天气实在太棒了,所以我就和我儿子在户外共度了大部分周末时光。

如果你还没听说的话,Visual Studio 2010 Beta 1已经发布了,注册了MSDN的朋友们都可以去下载。而Soma说在周三Beta 1也会向更广泛地向大众开放。

你可以在下载包里找到一份很精彩的介绍ASP 4新功能的白皮书。

你可能会注意到ASP.NET MVC并没有包含在Beta 1中。主要的原因是Beta 1在MVC 1.0发布之前已经内容锁定了(译注:lock down;微软内部指一个产品只修改bug不增加功能的阶段)。而VS10 Beta 2里会包含ASP.NET MVC。

当下,如果你试着在VS 2010 Beta 1中打开一个MVC项目的话,你会看到一些关于不支持该项目类型之类的错误信息。一个简单的解决方法是这个帖子里所介绍的通过移除ASP.NET MVC ProjectTypeGuid的方法。

我们正在努力设法完成一个编外的安装程序来在VS2010 Beta1环境下安装ASP.NET MVC的项目模版和工具,预计会在六月的某个时间通过CodePlex发布。所造成的不便,敬请见谅。我会在第一时间写博客通知大家的。

posted on 2009-05-21 15:17:31 by demonfox  评论(2) 阅读(3729)

 

【原文地址】Donut Hole Caching in ASP.NET MVC

【原文发表日期】 May 12, 2009

译注:原文的题目是Donut Hole Caching in ASP.NET MVC。Donut就是面包圈的意思,Donut Hole就是面包圈中心的那个洞洞。Donut Caching是指:在整个页面中缓存大部分的页面而对一小块要实时更新的内容不进行缓存。而Donut Hole Caching则是指相反的情况,亦即:不缓存大部分的页面而只缓存一小部分特定的内容。既然是仅缓存一部分的内容,我就译成局部缓存了。而Donut Caching似乎在很多地方都译为:“甜圈缓存”,我就沿用了

不久之前,我写了关于ASP.NET MVC中“甜圈缓存”的一些内容,也即,除了一小部分的信息,你需要缓存整个视图的大部分内容的情况。更技术化的用词也许应该是“缓存替换”(cache substitution),因为这里它用到了Response.WriteSubstitution这个方法,不过我觉得“甜圈缓存”确实是蛮形象的描述 -- 因为你需要缓存所有的东西,除了中间那一小部分内容。

不过,如果是反过来的情况应该怎么办呢?也就是说,如果你是想缓存中间那个窟窿,而不是周围那圈面包怎么办?

(我认为我们应该将所有软件工程的概念都用美味的食物来命名,你觉得如何?)

换句话说,假设你是想对视图中的一部分内容采用与其他所有内容不同的缓存策略(比如,不同的缓存有效时限),那该如何做呢?关于如何在ASP.NET MVC中实现这一点至今还没有很明确的介绍。

举例而言,Html.RenderPartial方法会忽略所有视图用户控件上的OutputCache指令。而另一方面,如果你使用MVC Futures包中Html.RenderAction这个方法来显示一个视图中内嵌的一个动作的输出内容时,你就可能会遇到这个问题:就是虽然只有这个动作有一个OutputCacheAttribute的属性,但实际上整个视图都被缓存了。

我今天对这个问题多了一些深入研究,发现当你给一个控件指定一个OutputCache的指令时(或者给一个页面),这个控件的输出缓存不是由它自己来控制的。相反,看起来是ASP.NET页面的编译系统参与了进来,接收了这个这个指令,并相应地做了缓存行为的处理。

用直白的话来说,这意味着下面我将展示的技巧只有在默认的WebFormViewEngine里才能工作,虽然我对于如何使之在所有的视图引擎(view engine)里工作也有些初始的想法。我只是想和ASP.NET产品组里的一些了解ASP.NET深层机制的成员再进一步交流一下以便确认实实在在准确的处理途径。

在使用默认的WebFormViewEngine的情况下,实现局部输出缓存其实还挺简单的。你只需通过直接通过声明(declaratively)往视图里加入一个ViewUserControl,然后将对RenderAction或RenderPartial的调用都放在这个ViewUserControl内部。如果你调用了RenderAction,那你还需要将相应动作的OutputCache属性去掉。

请记住ViewUserControl会继承他们所在的视图的ViewData。所以如果你使用了一个强类型的视图,你也必须在ViewUserControl的泛型类型参数中使用相同的类。

如果上一段东西你读得有点云山雾罩的话,那是时候来看一个实际的示例了。假设你如下的控制器动作:

public ActionResult Index() {
  var jokes = new[] { 
    new Joke {Title = "Two cannibals are eating a clown"},
    new Joke {Title = "One turns to the other and asks"},
    new Joke {Title = "Does this taste funny to you?"}
  };
 
  return View(jokes);
}

假设你是想在视图里显示一系列的笑话标题。通常,你会先创建一个强类型的视图,然后在那个视图内部,我遍历模型(model)中的数据并打印出各个笑话的标题。

现在,我们还是创建一个强类型的视图,但这个视图包含一个ViewUserControl,来代替原来我们写的遍历模型并打印的代码(请注意为了简洁起见,我删去了Inherits属性值里的那些命名空间)

<%@ Page Language="C#" Inherits="ViewPage<IEnumerable<Joke>>" %>
<%@ Register Src="~/Views/Home/Partial.ascx" TagPrefix="mvc" TagName="Partial" 
%>
<mvc:Partial runat="server" />

在这个控件(译注:即Partial.ascx)内部,我们将完成原来要在主视图中完成的工作,并且配置缓存设定。请注意这里我们的ViewUserControl的泛型类型和视图的类型是一致的:IEnumerable<Joke>。这使我们得以将原本在视图中的代码原封不动地移到这个控件中去。我们也同时在此处配置OutputCache指令。

<%@ Control Language="C#" Inherits="ViewUserControl<IEnumerable<Joke>>" %>
<%@ OutputCache Duration="10000" VaryByParam="none" %>
 
<ul>
<% foreach(var joke in Model) { %>
    <li><%= Html.Encode(joke.Title) %></li>
<% } %>
</ul>

现在,这部分的视图将会被缓存,而其余视图中的内容则不会。而在这个ViewUserControl内部,我们可以随意调用RenderPartial或者RenderAction。

请注意如果你想用这个技巧来缓存RenderPartial的输出结果,这不会给你带来太多的效益,除非显示这个局部视图本身(而非其中的数据)的代价很高。

这是因为输出内容的缓存要直到视图显示的阶段才会发生,如果准备该局部视图背后的数据需要很复杂的运算的话,那你实际上并没有节省多少工作,因为给这个局部视图提供数据的动作方法(action method)还是会在每次页面被请求时运行并且重新创建所需的数据。

在这种情况下,你需要手动缓存这个局部视图的数据,从而免去每次都必须重新创建它们的工作。有一个可以考虑的疯狂的想法是(先公开下想法而已)是允许将输出缓存的元数据(metadata)和一部分视图的数据关联起来。这样,你就可以只创建一小部分专属于那个局部视图的数据,然后这个局部视图就会自动在此之上进行输出缓存。

这个思路可以进一步的优化联合起来使用,也就是通过某些方法声明那一小部分专属于局部视图的数据只需在输出缓存过期(expire)后才需要被重新创建,如此我们就不必在每个请求响应中反复创建它们了。

而在使用RenderAction的情况下,你确实可以得到所有输出缓存的好处,因为如果你的ViewUserControl已经被缓存了的话,你所使用的这个内联的动作方法就不会再被调用了。

我这里编写了一个小小的程序来演示这些概念的实现,以免我上文的介绍不够明了。Enjoy!

posted on 2009-05-21 15:16:25 by demonfox  评论(0) 阅读(3695)

 
2009年05月14日

【原文地址】I’m a Web Developer At Heart

【原文发表日期】 May 7, 2009

曾经有一位年轻的程序员写email问我说如何能成为一个成功的开发人员。我一开始是这样回答的:

我不清楚.你为什么不去问一个成功的开发人员呢?

但而后我想,这样的回答其实仅仅是机巧有余,不是么?我这么老虚伪地故作谦逊是和谁在故弄玄虚呢?毕竟,“clever hack”这个概念就是以我来命名的(译注:注意Phil Haack的姓氏),而显然发明这个词汇的人还及不上我1/10的魅力,这点从他创造这个词组的时候故意地漏掉了一个字母a这件事上也更加可见一斑。当然,这个,还只是发生在我发明了Test-Driven Design,因特网,以及大家所呼吸的空气之前的一些小打小闹。

(对那些幽默理解不能的朋友们,请注意,我并没有真正发明Test-Drive Design)

于是我开始仔细考虑这个问题并对自己说:“假设我是一个成功的软件程序员,那我应该会做哪些事来达到那个目标呢?”然后当我开始思索各种学习提高的方法时,有一件事是显而易见的,那就是参与一些开源软件的项目。

如果说我的职业生涯中有一件事年复一年地使我获益良多,那就是我参与了很多开源的项目。参与开源项目使我有机会广泛地接触各类的问题和技术,而这些问题和技术在日常的工作中我通常不会面对。

在我进一步进行探讨前,我必须声明这个帖子不是我用来回答年轻的程序员们的问题的帖子。不,那样的帖子还是等其他的场合吧。而且我也许会起个陈词滥调又莫测高深的名字比如:“给年轻的开发者们的一些意见”。我的意思是,这样的题目是不是听上去真的既无聊又自大?我对着镜子严肃地说:“拜托你还是冷静点吧。”不过镜子里的那个家伙也许最终还是会这么来一篇的,没办法…

只是,这篇不是那样的帖子。相反,这篇与好为人师的话题很不相干,因为我很擅长一件事,那就是跑题。

在聊到关于开源软件的话题时,我很自然地想到了我参与的第一个开源项目 – RSS Bandit (w00t w00t!) RSS Bandit是一个由Dare ObasanjoTorsten Rendelmann开发的一流的RSS聚合软件。我那时候才刚刚开始接触博客之类的概念,然后一下子就被Dare的直爽而又有深度的博客以及他的可爱的孩子,RSS Bandit(他现在有一个真正的孩子了,祝贺你,老兄)吸引住了。

那时候我还没怎么做过Windows客户端的程序开发。我主要是用老版本的ASP以及早期的ASP.NET在开发网络应用。我于是想通过RSS Bandit来磨练下自己并顺便学习一下Winform的开发。Winform这种状态持续化(stateful)的编程模型让我觉得很新鲜(译注:因为那时基于HTTP的网络应用基本都是stateless的,当然后来有了ViewState等等的技术)。这将是很有趣的一个尝试。

很多新人程序员接触一个开源项目时都梦想着自己很立马开发出引人注目令人惊奇的新功能,由此博得群众的欢呼喝彩,总统因此以你来命名一个国定假日,而且你所有的敌人都立刻自惭形秽并把他们的孩子改名跟你姓了。

但一个真正好的贡献者会收起他/她的骄傲感然后扎扎实实地从一些小事,甚至是琐事开始做起。比如很多开源项目都很需要很好的帮助文档,一部分原因也是因为最吸引眼球的是开发那些新的功能于是没人有兴趣来写那些个劳什子的文档了。

我就是这么开始的。我先开始写了一篇文章:getting started with RSS Bandit.  Dare注意到了,于是问我愿不愿意参与完善文档的建设,我欣然同意了。他给了我提交的权限(我想我应该是Dare和Torsten后第三个有提交权限的人),于是我很努力地编写各式的文档。事实上,很多我当年写的内容仍然在那里,比如这个我当年用过的巨自恋的程序截图。; )

慢慢地,我得到了越来越多的信任,并被允许做一些bug的修正和一些小的功能块。我负责的第一个主要的功能是实现可配置的键盘快捷键,还挺不错。

小小逸事一则。我和这两位在RSS Bandit上合作了多年,但却从没有亲自面会过Dare一直到刚刚在Las Vegas举行的今年度的Mix大会上。真的!而我早先在德国于Torsten见过面。

(译注:我和Phil不同,两年前加入微软的时候,我就和Dare有过几面之缘,也和他的group合作过不短的时间。不过我一直都没有意识到他就是我用过的第一个聚合阅读器的作者,直到看到Phil的这篇文章,呵呵)

我那时真的很喜欢RSS Bandit方面的工作,那几乎成了我的一个爱好,占去了我不多的业余时间里的剩余空闲。我想你可以说RSS Bandit的工作使我免受了洛杉矶街头流氓团伙的不良影响,当然我也没试过去加入那些团伙,而估计他们也不会要我。不过渐渐地,我意识到了一些事。尽管起初的那种学习了解状态持续化编程模型的兴奋感犹在眼前……

我意识到我并不喜欢这种模型。

事实上,我发现这个模式很陌生也很难掌握。我总是遇到一些奇怪的使我脑筋打结的怪问题,比如用户单击了一个按钮后,此按钮仍然保留了它之前的状态。那时我就会想,“为什么我需要手动清除按钮的状态呢?为什么在用户进行一个动作之后这个状态不自行消失呢?”我开始意识到我的问题在于我的思维一直还是遁寻着网络应用程序员的模式,而不是客户端应用程序员的模式。

就与一个客户端程序开发者转向网络程序开发时感觉相似(比如网络程序中,因为状态不是持续化(stateless)的,所以你必须在响应每个请求后都重设所有控件的状态),一个此前专注于网络程序的开发者会发现客户端程序的开发是一件很费脑筋的事,因为所有的系统状态都像那个酒吧里最漂亮的小妞身边的那个跟屁虫一样 ---- 他就是赖在那里不从你眼前消失。

于是我才意识到,从骨子里来说,我其实是一个网络应用程序员并且我情愿Make web, not war译注:这个我实在不想翻译,译了也没意思,呵呵,太搞了,你自己看video吧)。所以大概就是在那个时候,我开始了Subtext项目,因为我内心里还是更希望做一个网络的应用。最终,我不再使用RSS Bandit,而是转向了在线的聚合阅读工具,就是Google Reader(有点讽刺,呵呵),而其中最主要的原因,就是在线的阅读工具使我可以随时随地看到我订阅的内容,并且一直保持最近更新的状态,而我也不需要在每一台新的电脑上进行同步或者安装一个程序。

所以说我虽然更喜欢(或者说也许是更习惯于)网络应用的状态非持续化的编程模式,我同时也为网络应用本身的状态持续化的特性所吸引,也即,我所拥有的数据的状态不是绑定在任何一台特定的终端上的而是存储在一个无所不在的网络平台上,而我又可以随时随地地使用这个平台(当然,网络应用也有它自身的问题和课题,比如网络服务当机的问题)

与此同时,我也会不时地抽空关心一下RSS Bandit的最新进展。它确实也有很多Google Reader所没有的很酷的功能,比如它可以从聚合器客户端直接通过Comment API来发表评论,还有它可以订阅需要身份验证的聚合。而且我觉得Dare正在努力把RSS Bandit引向一个全新的更有竞争力的方向

所有我说的这些其实只是想说明,如果你想成为一个更好的程序员,那就找一个你感兴趣的开源项目,然后参与进去(比如这个,:) ,因为也许它就会引导你发现自己的本质是何种类型的开发者。就如我所最终了然的,我从内心深处是一个网络应用的程序员。

posted on 2009-05-14 16:47:00 by demonfox  评论(0) 阅读(3762)

 
2009年05月08日

【原文地址】Put Your Pages and Views on Lockdown

【原文发表日期】 May 5, 2009

我相信你一定了解,我们程序开发人员是一群老顽固的人而且我们就喜欢周遭的东西和我们理想中的情况保持一致。不然你怎么解释那经年不停众说纷纭的关于大括号应该放在哪个位置的讨论?

所以我们应该也不会惊讶于开发人员对那些aspx文件里面(以及后台)的内容的锱铢必较,无论是对那些Web Forms的网页还是对ASP.NET MVC里的视图。

举例说,有些程序员坚持一个网页里不应该包含服务器端的脚本程序段落,而另一些则认为MVC的视图中不应该含有任何Web Form的控件。那如果你可以事先规定你的视图将拒绝任何带有控件实例的代码段,那不是很棒么?

幸运的是,ASP.NET里提供了大量的不为大众所知的可扩展组件来帮助你实现这样的功能,比如PageParseFilter这个类。MSDN是这样描述它的:

Provides an abstract base class for a page parser filter that is used by the ASP.NET parser to determine whether an item is allowed in the page at parse time.

也就是说,通过实现这个类,你可以在页面分析器分析.aspx文件的时候有机会插入你自定义的处理逻辑。

比如,下面是一个很简单的滤子类,它屏蔽了所有带有runat=”server”属性的脚本代码段:

using System;
using System.Web.UI;
 
public class MyPageParserFilter : PageParserFilter {
  public override bool ProcessCodeConstruct(CodeConstructType codeType
    , string code) {
    if (codeType == CodeConstructType.ScriptTag) {
      throw new InvalidOperationException("Say NO to server script blocks!");
    }
    return base.ProcessCodeConstruct(codeType, code);
  }
 
  public override bool AllowCode {
    get {
      return true;
    }
  }
 
  public override bool AllowControl(Type controlType, ControlBuilder builder)   {
    return true;
  }
 
  public override bool AllowBaseType(Type baseType) {
    return true;
  }
 
  public override bool AllowServerSideInclude(string includeVirtualPath) {
    return true;
  }
 
  public override bool AllowVirtualReference(string referenceVirtualPath
    , VirtualReferenceType referenceType) {
    return true;
  }
 
  public override int NumberOfControlsAllowed {
    get {
      return -1;
    }
  }
 
  public override int NumberOfDirectDependenciesAllowed {
    get {
      return -1;
    }
  }
}

请注意我们必须重置一些我们并不感兴趣的属性的默认值,比如NumberOfControlsAllowed,否则这些属性值返回将是默认的值“1”,这当然不是我们想要的。

如果想应用这个滤子,你只需在web.config文件的<pages />标签里加上如下声明即可:

<pages 
  pageParserFilterType="Namespace.MyPageParserFilter, AssemblyName">

要想在ASP.NET MVC的视图上应用分析滤子则更麻烦一些,因为MVC的视图都已经有一个分析滤子应用其上了:ViewTypeParserFilter。我以前提到,在使用泛型的模式(model)类的时候,我们可以免去在视图中用到code-behind的烦恼 (还记得我上文提到的那些开发者么?他们就是不喜欢在视图类中用到code-behind。),而提供如此灵活性的背后是很多如黑巫术般的诡异工作,这个滤子类就是这些工作的一部分。

假定我们希望防止开发者使用在ASP.NET MVC框架中毫无意义的那些服务器端控件。理想化的情况是,我们就继承一下ViewTypeParserFilter类,然后加入我们想定义的逻辑,这样原来的ViewTypeParserFilter的那些功能我们也保留了。

但问题是这个滤子类是internal的,我们无法继承。幸运的是,我们可以找到这个类的ASP.NET MVC源代码,重命名一下它的类型和命名空间,然后就按我们的需要来修改好了。完成了以后,我们还可以和其他人分享这些改动。这就是ASP.NET MVC开源协议的好处之一。

警告:ViewTypeParserFilter的存在是ASP.NET MVC这个框架实现中的一个内部细节。未来我们最理想的目标应该是不必通过这个滤子类,我们也可以提供优美的泛型语法。所以我下面马上要介绍的东西也许在未来就作废了,所以你自己得承担起未来维护的责任。It’s definitely running with scissors (译注:这就是翻译所不能的地方了,“Running with Scissors”是一部美国的电影,多译为“夹缝求生”。也是ALT.NET的徽标上的也有一个“带着剪刀奔跑”的图形暗喻,意指程序员所应具备的灵活性和处理不确定性的能力。我还是不强行翻译好了,做个注解就是。)

在我的演示程序中,我将下列文件拷贝到了自己的项目中:

  • ViewTypeParserFilter
  • ViewTypeControlBuilder
  • ViewPageControlBuilder
  • ViewUserControlControlBuilder

然后我定义了一个新的分析器滤子,它继承自ViewTypeParserFilter并重载了AllowControl这个方法,如下:

public override bool AllowControl(Type controlType, ControlBuilder builder) {
  return (controlType == typeof(HtmlHead) 
    || controlType == typeof(HtmlTitle)
    || controlType == typeof(ContentPlaceHolder)
    || controlType == typeof(Content)
    || controlType == typeof(HtmlLink));
}

除了那些典型的视图中必须要用到的几个控件外,这个新的滤子会阻止开发者加入任何其他的控件。当然,也很容易想到接下来我们可以提供一些简单的方法来允许开发者配置这个可用控件列表。

实现完这个新的滤子类后,我们可以修改Views文件夹下的Web.config文件来指定新的分析器滤子。

上文介绍的是允许开发者往网页分析流程中插入自定义逻辑的一个强大的方法,所以请大家谨慎使用。如你所愿的,我这里有一个很简单演示程序可供参考。

posted on 2009-05-08 17:09:27 by demonfox  评论(0) 阅读(3795)

 
2009年05月03日

译注:本篇为09年3月的补全

【原文地址】I’m Speaking At Mix 2009

【原文发表日期】 Mar 1, 2009

终于把注册登记的事情搞定了,我正式准备出席今年的Mix 09喽! Woohoo! 而且我不仅仅是参加本次大会,我还将第一次在Mix上做主题演讲,所以如果各位朋友也准备参加的话,届时请一定过来寒暄几句。

我以前也提过,Mix是我最喜爱的微软举办的大会之一。Jeff Atwood概括得好:

“参加过'06和'07年的MIX后,它就成为了我最锺意的微软技术会议…

我喜欢Mix是因为…

- Mix的规模相对较小而有亲和力,一般出席的人数在2,000人左右

- 无缝地整合了软件工程和设计方面的内容

- 汇集了很多非微软的人士,甚至那些传统上对微软有敌意的人,所以你可以听到各方面的意见

我参加了Mix创建以来的每一届大会:

- Mix 06 第一届Mix大会,Atwood, Galloway, 和我的处女行

- Mix 07 我遇到了Miguel,见证了Moonlight的横空出世,然后决定加入微软

- Mix 08 第一次有了关于ASP.NET MVC的专题演讲,由Scott Hanselman主讲

- Mix 09 让我们拭目以待

今年的Mix上我将主讲以下两个专题:

MIX09-T50F ASP.NET MVC: America’s Next Top Model View Controller Framework(译注:这里其实是一个双关幽默,取义于美国的一个蛮收欢迎的电视真人秀:America’s Next Top Model,当然两个Model的意义不同,后者是模特的意思)

介绍如何创建一个简单的ASP.NET MVC的应用程序,并以此演示该框架的一些关键特性。同时,你可以了解到如果利用一些新的很酷的工具来提高开发效率。

MIX09-T44F Microsoft ASP.NET Model View Controller (MVC): Ninjia on Fire Black Belt Tips

介绍一些实用的技巧和窍门,使你能最充分地利用ASP.NET MVC框架

第一个讲座是概括性的介绍,第二个则允许我更深入地进行一些讨论。

我最近一直努力地在准备一些实例演示,所以希望到时候能给大家看一些十分有趣的东西。无论如何,如果你打算参加本次大会,那请给我留个言,过来聊几句,互相问个好。

同时,如果你对某些内容特别感兴趣,也可以事先告诉我。这将会是一次很令人期待的盛会。

posted on 2009-05-03 18:31:55 by demonfox  评论(0) 阅读(3785)

 
【第1页/共5页,43条】
首页
前页
1

Powered by: Joycode.MVC引擎 0.5.2.0