<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>裁纸刀下 &#187; MVC</title>
	<atom:link href="http://ofcss.com/tags/mvc/feed" rel="self" type="application/rss+xml" />
	<link>http://ofcss.com</link>
	<description>独立 自由 诚信 宽容 责任 平常心</description>
	<lastBuildDate>Fri, 20 Apr 2012 04:08:47 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>ASP.NET MVC 最佳实践（四）</title>
		<link>http://ofcss.com/2009/07/08/asp-net-mvc-best-practices-part-4.html</link>
		<comments>http://ofcss.com/2009/07/08/asp-net-mvc-best-practices-part-4.html#comments</comments>
		<pubDate>Tue, 07 Jul 2009 17:34:45 +0000</pubDate>
		<dc:creator>小李刀刀</dc:creator>
				<category><![CDATA[所谓技术]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[开发]]></category>
		<category><![CDATA[最佳实践]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://wukangrui.net/2009/07/08/asp-net-mvc-best-practices-part-4.html</guid>
		<description><![CDATA[本系列翻译自 Kazi Manzur Rashid 的博客，由于篇幅关系，原文中的一篇文章在本系列中将拆解成多篇发布。本篇包括原文第二部分第18-21节。]]></description>
			<content:encoded><![CDATA[<p><em>本系列翻译自 </em><a href="http://weblogs.asp.net/rashid/default.aspx"><em>Kazi Manzur Rashid</em></a><em> 的博客，由于翻译水平有限，本系列可能存在误解偏差或者翻译不准的地方，建议对比<a href="http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx">原文</a>进行阅读。由于篇幅关系，原文中的一篇文章在本系列中将拆解成多篇发布。本篇包括原文第二部分第18-21节。如果你没有看过之前的第一部分，也许你想先看看 <a href="http://wukangrui.net/2009/06/28/asp-net-mvc-best-practices-part-1.html">《ASP.NET MVC 最佳实践（一）》</a>、《<a href="http://wukangrui.net/2009/06/28/asp-net-mvc-best-practices-part-1.html">ASP.NET MVC 最佳实践（二）</a>》和《<a href="http://wukangrui.net/2009/07/07/asp-net-mvc-best-practices-part-1-2.html" rel="prev" target="_blank">ASP.NET MVC 最佳实践（三）</a>》。</em></p>
</p>
<p><em></em></p>
</p>
<p> <span id="more-858"></span>
</p>
<h4>18. HtmlHelper 扩展</h4>
<p>首先，参考一下 <a href="http://blog.wekeroad.com/" rel="external" target="_blank">Rob Conery</a> 的<a href="http://blog.wekeroad.com/blog/asp-net-mvc-avoiding-tag-soup/" rel="external" target="_blank">这篇文章</a>，我完全同意他的观点，你应该为每种情况创建 Helper 方法，此外我还建议你像 <a href="http://www.asp.net/mvc/" rel="tag" target="_blank">ASP.NET MVC</a> 团队那样为可重用的 UI 元素创建 Helper 方法，但是对于在哪里放置我们正在实践的这些方法，我有不同的建议。</p>
<h6>应用程序开发者</h6>
<p>只为你需要在多个视图中重复使用的HtmlHealper创建单独的扩展方法。对于只在一个视图中使用的帮助方法，你可以为整个视图创建一个Helper类，然后创建一个HtmlHelper来返回这个视图Helper类，而把只在这个视图中使用的扩展方法作为类内部的方法。（这部分未按原文翻译，请自行参照原文）例如：</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">DashboardHtmlHelper </span>{
    <span style="color: blue">private readonly </span><span style="color: #2b91af">HtmlHelper </span>_htmlHelper;

    <span style="color: blue">public </span>DashboardHtmlHelper(<span style="color: #2b91af">HtmlHelper </span>htmlHelper) {
        _htmlHelper = htmlHelper;
    }

    <span style="color: blue">public string </span>DoThis() {
        <span style="color: green">//Your Code
    </span>}

    <span style="color: blue">public string </span>DoThat() {
        <span style="color: green">//Your Code
    </span>}
}

<span style="color: blue">public static class </span><span style="color: #2b91af">HtmlHelperExtension </span>{
    <span style="color: blue">public static </span><span style="color: #2b91af">DashboardHtmlHelper </span>Dashboard(<span style="color: blue">this </span><span style="color: #2b91af">HtmlHelper </span>htmlHelper) {
        <span style="color: blue">return new </span><span style="color: #2b91af">DashboardHtmlHelper</span>(htmlHelper);
    }
}</pre>
<p>然后在视图中这样调用：</p>
<pre class="code"><span style="background: #ffee62">&lt;%</span><span style="color: blue">= </span>Html.Dashboard().DoThis() <span style="background: #ffee62">%&gt;</span></pre>
<h6>UI 组件开发人员</h6>
<p>如果你在开发的是可以在多个 <a href="http://www.asp.net/mvc/" rel="tag" target="_blank">ASP.NET MVC</a> 应用程序中重用的 UI 组件系列，你可以像上面那样为你的整个系列组件创建一个单一名字的Helper。假如你开发的是商业组件，那你可以用你的公司名字来为这个单一的Helper命名，然后在这个Helper中添加方法。否则很容易出现方法的命名冲突。</p>
<p>要是你正在学习 <a href="http://mvccontrib.codeplex.com" rel="external" target="_blank">MVCContrib.org</a> 的做法，为 IViewDataContainer 做扩展的话，道理也是一样的。</p>
<h4>19. Html编码</h4>
<p>在从用户端获取信息的任何情况下，总是使用 Html.Encode(“User Input”) 来编码文本节点，用 Html.AttributeEncode(“User Input”) 来编码Html 元素属性。</p>
<h4>20. 不要把Javascript脚本放在你的视图中</h4>
<p>不要把你的javascript脚本和html混杂在一起，创建一个单独的 js 文件，把脚本代码放在里面。有时候你可能需要在你的 javascript 代码中传递视图数据，这种特殊的情况下，也只把初始化代码放在视图中。例如，你正在开发 web 2.0 风格的应用，你需要在这个应用中传递 ajax 方法的url，并且需要在 javascript 脚本中传递一些其它的模型数据，这种情况下，你可以参考下面的方式：</p>
<p>视图：</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">=&quot;sideBar&quot; </span><span style="color: red">class</span><span style="color: blue">=&quot;column&quot;&gt;&lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">script </span><span style="color: red">type</span><span style="color: blue">=&quot;text/javascript&quot;&gt;
            </span>$(document).ready(<span style="color: blue">function</span>(){
                Story.init(<span style="color: #a31515">'&lt;%= Model.UrlFormat %&gt;'</span>, <span style="color: #a31515">'&lt;%= Url.NoIcon() %&gt;'</span>, &lt;%= Model.PageCount %&gt;, &lt;%= Model.StoryPerPage %&gt;, &lt;%= Model.CurrentPage %&gt;, <span style="color: #a31515">'&lt;%= Model.SelectedTab %&gt;'</span>, <span style="color: #a31515">'&lt;%= Model.SelectedOrderBy %&gt;'</span>);
            });
        <span style="color: blue">&lt;/</span><span style="color: #a31515">script</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">asp</span><span style="color: blue">:</span><span style="color: #a31515">Content</span><span style="color: blue">&gt;</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Javascript：</p>
<pre class="code"><span style="color: blue">var </span>Story = {
    _urlFormat: <span style="color: #a31515">''</span>,
    _noIconUrl: <span style="color: #a31515">''</span>,
    _pageCount: 0,
    _storyPerPage: 0,
    _currentPage: 0,
    _currentTab: <span style="color: #a31515">''</span>,
    _currentOrderBy: <span style="color: #a31515">''</span>,

    init: <span style="color: blue">function</span>(urlFormat, noIconUrl, pageCount, storyPerPage, currentPage, currentTab, currentOrderBy) {
        Story._urlFormat = urlFormat;
        Story._noIconUrl = noIconUrl;
        Story._pageCount = pageCount;
        Story._storyPerPage = storyPerPage;
        Story._currentPage = currentPage;
        Story._currentTab = currentTab;
        Story._currentOrderBy = currentOrderBy;

        <span style="color: green">//More Codes
    </span>}
}</pre>
<p>这里要为不太熟悉上面的 javascript 的同学解释一下，这是一个在javascript中创建静态类的示例代码。对了，我还差点忘了提一点，永远不要在你的javascript文件中硬编码 ajax 方法的url，虽然 <a href="http://videos.visitmix.com/MIX09/T62F" rel="external" target="_blank">Rob Conery</a> 和 <a href="http://aspnetpodcast.com/CS11/blogs/asp.net_podcast/archive/2008/07/28/asp-net-podcast-show-121-phil-haack-with-an-asp-net-mvc-demo-video.aspx" rel="external" target="_blank">Phil Haack</a> 在他们的教程中是这样干的。这是一个很不好的方式，它破坏了 ASP.NET 路径重写的优雅性。</p>
<h4>21. 使用 jQuery 和 jQuery UI</h4>
<p>使用 jQuery 和 jQuery UI，它是最好的js库，并且可以使用 Google CDN 托管服务来加载这些库（对于国内用户，如果使用 google 托管的库一定要有承担风险的准备，具体原因嘛，看看国内6月24日左右的IT新闻就知道了）。</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">link </span><span style="color: red">type</span><span style="color: blue">=&quot;text/css&quot; </span><span style="color: red">href</span><span style="color: blue">=&quot;http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/themes/{YOUR Prefered Theme}/jquery-ui.css&quot; </span><span style="color: red">rel</span><span style="color: blue">=&quot;stylesheet&quot;/&gt;
&lt;</span><span style="color: #a31515">script </span><span style="color: red">type</span><span style="color: blue">=&quot;text/javascript&quot; </span><span style="color: red">src</span><span style="color: blue">=&quot;http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js&quot;&gt;&lt;/</span><span style="color: #a31515">script</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">script </span><span style="color: red">type</span><span style="color: blue">=&quot;text/javascript&quot; </span><span style="color: red">src</span><span style="color: blue">=&quot;http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/jquery-ui.js&quot;&gt;&lt;/</span><span style="color: #a31515">script</span><span style="color: blue">&gt;</span></pre>
<p>还有一种更好的方式：</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">link </span><span style="color: red">type</span><span style="color: blue">=&quot;text/css&quot; </span><span style="color: red">href</span><span style="color: blue">=&quot;http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/themes/{YOUR Prefered Theme}/jquery-ui.css&quot; </span><span style="color: red">rel</span><span style="color: blue">=&quot;stylesheet&quot;/&gt;
&lt;</span><span style="color: #a31515">script </span><span style="color: red">type</span><span style="color: blue">=&quot;text/javascript&quot; </span><span style="color: red">src</span><span style="color: blue">=&quot;http://www.google.com/jsapi&quot;&gt;&lt;/</span><span style="color: #a31515">script</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">script </span><span style="color: red">type</span><span style="color: blue">=&quot;text/javascript&quot;&gt;
    </span>google.load(<span style="color: #a31515">&quot;jquery&quot;</span>, <span style="color: #a31515">&quot;1.3.2&quot;</span>);
    google.load(<span style="color: #a31515">&quot;jqueryui&quot;</span>, <span style="color: #a31515">&quot;1.7.1&quot;</span>);
<span style="color: blue">&lt;/</span><span style="color: #a31515">script</span><span style="color: blue">&gt;</span></pre>
<p>以上就是这一次的全部内容。</p>
<p>最后，我要祝贺 <a href="http://www.asp.net/mvc/" rel="tag" target="_blank">ASP.NET MVC</a> 团队开发了如此杰出的框架，尤其是他们从社区接受反馈的方式。我希望能用这个框架开发出<a href="http://dotnetshoutout.com/" rel="external" target="_blank">更多</a>杀手级的应用（注：杀手级的应用程序，一般指极其优秀的应用程序，这类程序超越了语言本身，比语言更有吸引力而且能增加语言的吸引力）。</p>
<h3  class="related_post_title">相关日志</h3><ul class="related_post"><li>2009-07-07 -- <a href="http://ofcss.com/2009/07/07/asp-net-mvc-best-practices-part-3.html" title="ASP.NET MVC 最佳实践（三）">ASP.NET MVC 最佳实践（三）</a></li><li>2009-07-01 -- <a href="http://ofcss.com/2009/07/01/asp-net-mvc-best-practices-part-2.html" title="ASP.NET MVC 最佳实践（二）">ASP.NET MVC 最佳实践（二）</a></li><li>2009-06-28 -- <a href="http://ofcss.com/2009/06/28/asp-net-mvc-best-practices-part-1.html" title="ASP.NET MVC 最佳实践（一）">ASP.NET MVC 最佳实践（一）</a></li><li>2009-04-13 -- <a href="http://ofcss.com/2009/04/13/aspnetmvc-hands-on-labs-develop-application.html" title="[翻译]ASP.NET MVC动手实验1-3：开发ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-3：开发ASP.NET MVC应用</a></li><li>2009-04-09 -- <a href="http://ofcss.com/2009/04/09/aspnetmvc-hands-on-labs-create-application.html" title="[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用</a></li><li>2009-04-09 -- <a href="http://ofcss.com/2009/04/09/aspnetmvc-hands-on-labs-introduction.html" title="[翻译]ASP.NET MVC动手系列1-1：ASP.NET MVC概述">[翻译]ASP.NET MVC动手系列1-1：ASP.NET MVC概述</a></li><li>2011-03-14 -- <a href="http://ofcss.com/2011/03/14/browser-rendering-optimizer-translation-extra.html" title="对《优化浏览器渲染》的补充【译】">对《优化浏览器渲染》的补充【译】</a></li><li>2011-03-10 -- <a href="http://ofcss.com/2011/03/10/css-border-tricks-with-collapsed-boxes-translation.html" title="CSS边框实现&ldquo;无图化&rdquo;设计【译】">CSS边框实现&ldquo;无图化&rdquo;设计【译】</a></li><li>2010-10-31 -- <a href="http://ofcss.com/2010/10/31/prevent-a-float-drop-in-ie6-translation.html" title="CSS技巧:如何避免IE6中的&quot;浮动下坠&quot;【译】">CSS技巧:如何避免IE6中的&quot;浮动下坠&quot;【译】</a></li><li>2010-10-25 -- <a href="http://ofcss.com/2010/10/25/understanding-user-behavior-google-analytics-event-tracking-jquer.html" title="借助jQuery和Google分析服务的事件追踪深入了解用户行为【译】">借助jQuery和Google分析服务的事件追踪深入了解用户行为【译】</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ofcss.com/2009/07/08/asp-net-mvc-best-practices-part-4.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>ASP.NET MVC 最佳实践（三）</title>
		<link>http://ofcss.com/2009/07/07/asp-net-mvc-best-practices-part-3.html</link>
		<comments>http://ofcss.com/2009/07/07/asp-net-mvc-best-practices-part-3.html#comments</comments>
		<pubDate>Mon, 06 Jul 2009 17:21:16 +0000</pubDate>
		<dc:creator>小李刀刀</dc:creator>
				<category><![CDATA[所谓技术]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[开发]]></category>
		<category><![CDATA[最佳实践]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://wukangrui.net/2009/07/07/asp-net-mvc-best-practices-part-1-2.html</guid>
		<description><![CDATA[本系列翻译自 Kazi Manzur Rashid 的博客，由于翻译水平有限，本系列可能存在误解偏差或者翻译不准的地方，建议对比原文进行阅读。由于篇幅关系，原文中的一篇文章在本系列中将拆解成多篇发布。本篇包括原文第二部分。如果你没有看过之前的第一部分，也许你想先看看 《ASP.NET MVC 最佳实践（一）》和《ASP.NET MVC 最佳实践（二）》。]]></description>
			<content:encoded><![CDATA[<p><em>本系列翻译自 </em><a href="http://weblogs.asp.net/rashid/default.aspx"><em>Kazi Manzur Rashid</em></a><em> 的博客，由于翻译水平有限，本系列可能存在误解偏差或者翻译不准的地方，建议对比<a href="http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx">原文</a>进行阅读。由于篇幅关系，原文中的一篇文章在本系列中将拆解成多篇发布。本篇包括原文第二部分。如果你没有看过之前的第一部分，也许你想先看看 <a rel="prev" href="http://wukangrui.net/2009/06/28/asp-net-mvc-best-practices-part-1.html">《ASP.NET MVC 最佳实践（一）》</a>和《<a rel="prev" href="http://wukangrui.net/2009/06/28/asp-net-mvc-best-practices-part-2.html">ASP.NET MVC 最佳实践（二）</a>》。</em> <span id="more-848"></span><em></em></p>
<h4>15. 关于路由的思考</h4>
<p>如果你在开发的是一个纯 ASP.NET MVC 的应用程序，可以先关闭已有的路由文件检查，这样可以去除不必要的文件系统检查。如果你这样做了，那么就还需要考虑另外的一些事情。请记住如果你的应用程序运行于 IIS 7集成模式，那么 ASP.NET 应用程序将会拦截所有的请求，不管文件的后缀名是什么。所以你必须要在过滤列表中加一些东西，以便让 <a rel="tag" href="http://www.asp.net/mvc/" target="_blank">ASP.NET MVC</a> 应用程序不处理它们。这其中可能包括静态文件，例如 html、htm、文本文件(尤其是robots.txt)、favicon.ico、脚本、图片和css等等。这也是我在<a rel="prev" href="http://wukangrui.net/2009/06/28/asp-net-mvc-best-practices-part-1.html">第一部分第2节</a>中提到不喜欢默认文件结构的原因之一。以下是我为 IIS7 定制的路由定义标准模板：</p>
<pre class="code">_routes.Clear();

<span style="color: green">// Turns off the unnecessary file exists check
</span>_routes.RouteExistingFiles = <span style="color: blue">true</span>;

<span style="color: green">// Ignore text, html, files.
</span>_routes.IgnoreRoute(<span style="color: #a31515">"{file}.txt"</span>);
_routes.IgnoreRoute(<span style="color: #a31515">"{file}.htm"</span>);
_routes.IgnoreRoute(<span style="color: #a31515">"{file}.html"</span>);

<span style="color: green">// Ignore axd files such as assest, image, sitemap etc
</span>_routes.IgnoreRoute(<span style="color: #a31515">"{resource}.axd/{*pathInfo}"</span>);

<span style="color: green">// Ignore the assets directory which contains images, js, css &amp; html
</span>_routes.IgnoreRoute(<span style="color: #a31515">"assets/{*pathInfo}"</span>);

<span style="color: green">// Ignore the error directory which contains error pages
</span>_routes.IgnoreRoute(<span style="color: #a31515">"ErrorPages/{*pathInfo}"</span>);

<span style="color: green">//Exclude favicon (google toolbar request gif file as fav icon which is weird)
</span>_routes.IgnoreRoute(<span style="color: #a31515">"{*favicon}"</span>, <span style="color: blue">new </span>{ favicon = <span style="color: #a31515">@"(.*/)?favicon.([iI][cC][oO]|[gG][iI][fF])(/.*)?" </span>});

<span style="color: green">//Actual routes of my application</span></pre>
<p>接下来是我的一些不同于手册指南的个人偏好。默认情况下 <a rel="tag" href="http://www.asp.net/mvc/" target="_blank">ASP.NET MVC</a> 产生的 url 形如 {controller}/{action}，在你开发一个多模块的应用程序是这是不错的选择，但是对于一些很小的应用程序，我通常喜欢从 url 中去掉控制器(controller)只留下方法名(action name)。如此一来，原来的“www.yourdomain.com/Story/Dashboard” 及 “www.yourdomain.com/Membership/Signin” 就会变成 “www.yourdomain.com/Dashboard” 和“www.yourmain.com/Signin”。所以我要添加一些新路由：</p>
<pre class="code">_routes.MapRoute(<span style="color: #a31515">"SignUp"</span>, <span style="color: #a31515">"SignUp"</span>, <span style="color: blue">new </span>{ controller = <span style="color: #a31515">"Membership"</span>, action = <span style="color: #a31515">"SignUp" </span>});
_routes.MapRoute(<span style="color: #a31515">"SignIn"</span>, <span style="color: #a31515">"SignIn"</span>, <span style="color: blue">new </span>{ controller = <span style="color: #a31515">"Membership"</span>, action = <span style="color: #a31515">"SignIn" </span>});
_routes.MapRoute(<span style="color: #a31515">"ForgotPassword"</span>, <span style="color: #a31515">"ForgotPassword"</span>, <span style="color: blue">new </span>{ controller = <span style="color: #a31515">"Membership"</span>, action = <span style="color: #a31515">"ForgotPassword" </span>});
_routes.MapRoute(<span style="color: #a31515">"SignOut"</span>, <span style="color: #a31515">"SignOut"</span>, <span style="color: blue">new </span>{ controller = <span style="color: #a31515">"Membership"</span>, action = <span style="color: #a31515">"SignOut" </span>});
_routes.MapRoute(<span style="color: #a31515">"Profile"</span>, <span style="color: #a31515">"Profile"</span>, <span style="color: blue">new </span>{ controller = <span style="color: #a31515">"Membership"</span>, action = <span style="color: #a31515">"Profile" </span>});
_routes.MapRoute(<span style="color: #a31515">"ChangePassword"</span>, <span style="color: #a31515">"ChangePassword"</span>, <span style="color: blue">new </span>{ controller = <span style="color: #a31515">"Membership"</span>, action = <span style="color: #a31515">"ChangePassword" </span>});

_routes.MapRoute(<span style="color: #a31515">"Dashboard"</span>, <span style="color: #a31515">"Dashboard/{tab}/{orderBy}/{page}"</span>, <span style="color: blue">new </span>{ controller = <span style="color: #a31515">"Story"</span>, action = <span style="color: #a31515">"Dashboard"</span>, tab = StoryListTab.Unread.ToString(), orderBy = OrderBy.CreatedAtDescending.ToString(), page = 1 });
_routes.MapRoute(<span style="color: #a31515">"Update"</span>, <span style="color: #a31515">"Update"</span>, <span style="color: blue">new </span>{ controller = <span style="color: #a31515">"Story"</span>, action = <span style="color: #a31515">"Update" </span>});
_routes.MapRoute(<span style="color: #a31515">"Submit"</span>, <span style="color: #a31515">"Submit"</span>, <span style="color: blue">new </span>{ controller = <span style="color: #a31515">"Story"</span>, action = <span style="color: #a31515">"Submit" </span>});

_routes.MapRoute(<span style="color: #a31515">"Home"</span>, <span style="color: #a31515">"{controller}/{action}/{id}"</span>, <span style="color: blue">new </span>{ controller = <span style="color: #a31515">"Home"</span>, action = <span style="color: #a31515">"Index"</span>, id = <span style="color: blue">string</span>.Empty });</pre>
<h4> </h4>
<h4>16. 如果需要的话，创建新的ActionResult</h4>
<p><a rel="tag" href="http://www.asp.net/mvc/" target="_blank">ASP.NET MVC</a> 包含有很多种用于不同目的的 ActionResult，但我们仍有可能会需要新的 ActionResult。例如xml、rss、atom等等。在这种情况下，我的建议是不要使用通用的 ContentResult， 而是创建一种新的 ActionResult. <a rel="external" href="http://mvccontrib.codeplex.com" target="_blank">MVCContrib</a> 项目中有一个 XmlResult，你可以用它来返回 xml，但是不支持 feed。显然依靠它来将未知对象转换为 rss/atom 是很困难的，这时你就可以创建一个定义ActionResult的模型。例如：</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">AtomResult </span>: <span style="color: #2b91af">ActionResult </span>{
    <span style="color: blue">public </span>AtomResult(<span style="color: blue">string </span>siteTitle, <span style="color: blue">string </span>feedTitle, <span style="color: #2b91af">IEnumerable</span>&lt;IStory&gt; stories) {
        SiteTitle = siteTitle;
        FeedTitle = feedTitle;
        Stories = stories;
    }

    <span style="color: blue">public string </span>SiteTitle {
        <span style="color: blue">get</span>;
        <span style="color: blue">private set</span>;
    }

    <span style="color: blue">public string </span>FeedTitle {
        <span style="color: blue">get</span>;
        <span style="color: blue">private set</span>;
    }

    <span style="color: blue">public </span><span style="color: #2b91af">IEnumerable</span>&lt;IStory&gt; Stories {
        <span style="color: blue">get</span>;
        <span style="color: blue">private set</span>;
    }

    <span style="color: blue">public override void </span>ExecuteResult(<span style="color: #2b91af">ControllerContext </span>context) {
        <span style="color: blue">string </span>xml = Build(context);

        <span style="color: #2b91af">HttpResponseBase </span>response = context.HttpContext.Response;
        response.ContentType = <span style="color: #a31515">"application/atom+xml"</span>;
        response.Write(xml);
    }
}</pre>
<p>然后在控制器中就可以这样写：<a href="http://11011.net/software/vspaste"></a></p>
<pre class="code">[<span style="color: #2b91af">AcceptVerbs</span>(<span style="color: #2b91af">HttpVerbs</span>.Get), <span style="color: #2b91af">OutputCache</span>(CacheProfile = <span style="color: #a31515">"Atom"</span>)]
<span style="color: blue">public </span><span style="color: #2b91af">ActionResult </span>Shared() {
    <span style="color: #2b91af">IEnumerable</span>&lt;stories&gt; stories = GetSharedStories();

    <span style="color: blue">return new </span><span style="color: #2b91af">AtomResult</span>(<span style="color: #a31515">"My Site"</span>, <span style="color: #a31515">"My shared stories in atom"</span>, stories);
}</pre>
<h4>17. 把你的视图拆分为多个视图控件</h4>
<p>如果你的视图文件变得越来越大，那你可以考虑把它拆分为多个视图控件。至于视图空间是否在多个页面中重用，并没有关系。因为这样做可以让真正的视图文件变得更加具有可读性。考虑一下下面的视图：</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">asp</span><span style="color: blue">:</span><span style="color: #a31515">Content </span><span style="color: red">ID</span><span style="color: blue">="Content1" </span><span style="color: red">ContentPlaceHolderID</span><span style="color: blue">="TitleContent" </span><span style="color: red">runat</span><span style="color: blue">="server"&gt;
    </span>My Secret App : Dashboard
<span style="color: blue">&lt;/</span><span style="color: #a31515">asp</span><span style="color: blue">:</span><span style="color: #a31515">Content</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">asp</span><span style="color: blue">:</span><span style="color: #a31515">Content </span><span style="color: red">ID</span><span style="color: blue">="Content2" </span><span style="color: red">ContentPlaceHolderID</span><span style="color: blue">="MainContent" </span><span style="color: red">runat</span><span style="color: blue">="server"&gt;
    &lt;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="heading"&gt;&lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">div </span><span style="color: red">class</span><span style="color: blue">="columns"&gt;
        &lt;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="main" </span><span style="color: red">class</span><span style="color: blue">="column"&gt;
            &lt;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="storyListTabs" </span><span style="color: red">class</span><span style="color: blue">="ui-tabs ui-widget ui-widget-content ui-corner-all"&gt;
                </span><span style="background: #ffee62">&lt;%</span> Html.RenderPartial(<span style="color: #a31515">"TabHeader"</span>, Model);<span style="background: #ffee62">%&gt;
</span>                <span style="color: blue">&lt;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="tabContent" </span><span style="color: red">class</span><span style="color: blue">="ui-tabs-panel ui-widget-content ui-corner-bottom"&gt;
                    &lt;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="storyList"&gt;
                        </span><span style="background: #ffee62">&lt;%</span> Html.RenderPartial(<span style="color: #a31515">"SortBar"</span>, Model);<span style="background: #ffee62">%&gt;
</span>                        <span style="color: blue">&lt;</span><span style="color: #a31515">div </span><span style="color: red">class</span><span style="color: blue">="clear"&gt;&lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
                        </span><span style="background: #ffee62">&lt;%</span> Html.RenderPartial(<span style="color: #a31515">"NoLinkMessage"</span>, Model);<span style="background: #ffee62">%&gt;
</span>                        <span style="color: blue">&lt;</span><span style="color: #a31515">form </span><span style="color: red">id</span><span style="color: blue">="update" </span><span style="color: red">action</span><span style="color: blue">="</span><span style="background: #ffee62">&lt;%</span>= Url.Update()<span style="background: #ffee62">%&gt;</span><span style="color: blue">" </span><span style="color: red">method</span><span style="color: blue">="post"&gt;
                            </span><span style="background: #ffee62">&lt;%</span> Html.RenderPartial(<span style="color: #a31515">"List"</span>, Model);<span style="background: #ffee62">%&gt;
</span>                            <span style="background: #ffee62">&lt;%</span> Html.RenderPartial(<span style="color: #a31515">"ActionBar"</span>, Model);<span style="background: #ffee62">%&gt;
</span>                            <span style="background: #ffee62">&lt;%</span> Html.RenderPartial(<span style="color: #a31515">"Pager"</span>, Model);<span style="background: #ffee62">%&gt;
</span>                        <span style="color: blue">&lt;/</span><span style="color: #a31515">form</span><span style="color: blue">&gt;
                    &lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
                &lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
            &lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
            </span><span style="background: #ffee62">&lt;%</span>Html.RenderPartial(<span style="color: #a31515">"Submit"</span>, <span style="color: blue">new </span>StorySubmitViewModel());<span style="background: #ffee62">%&gt;
</span>        <span style="color: blue">&lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="sideBar" </span><span style="color: red">class</span><span style="color: blue">="column"&gt;&lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">asp</span><span style="color: blue">:</span><span style="color: #a31515">Content</span><span style="color: blue">&gt;</span></pre>
<p>继续阅读：《<a rel="next" href="http://wukangrui.net/2009/07/08/asp-net-mvc-best-practices-part-4.html">ASP.NET MVC 最佳实践（四）</a>》</p>
<h3  class="related_post_title">相关日志</h3><ul class="related_post"><li>2009-07-08 -- <a href="http://ofcss.com/2009/07/08/asp-net-mvc-best-practices-part-4.html" title="ASP.NET MVC 最佳实践（四）">ASP.NET MVC 最佳实践（四）</a></li><li>2009-07-01 -- <a href="http://ofcss.com/2009/07/01/asp-net-mvc-best-practices-part-2.html" title="ASP.NET MVC 最佳实践（二）">ASP.NET MVC 最佳实践（二）</a></li><li>2009-06-28 -- <a href="http://ofcss.com/2009/06/28/asp-net-mvc-best-practices-part-1.html" title="ASP.NET MVC 最佳实践（一）">ASP.NET MVC 最佳实践（一）</a></li><li>2009-04-13 -- <a href="http://ofcss.com/2009/04/13/aspnetmvc-hands-on-labs-develop-application.html" title="[翻译]ASP.NET MVC动手实验1-3：开发ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-3：开发ASP.NET MVC应用</a></li><li>2009-04-09 -- <a href="http://ofcss.com/2009/04/09/aspnetmvc-hands-on-labs-create-application.html" title="[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用</a></li><li>2009-04-09 -- <a href="http://ofcss.com/2009/04/09/aspnetmvc-hands-on-labs-introduction.html" title="[翻译]ASP.NET MVC动手系列1-1：ASP.NET MVC概述">[翻译]ASP.NET MVC动手系列1-1：ASP.NET MVC概述</a></li><li>2011-03-14 -- <a href="http://ofcss.com/2011/03/14/browser-rendering-optimizer-translation-extra.html" title="对《优化浏览器渲染》的补充【译】">对《优化浏览器渲染》的补充【译】</a></li><li>2011-03-10 -- <a href="http://ofcss.com/2011/03/10/css-border-tricks-with-collapsed-boxes-translation.html" title="CSS边框实现&ldquo;无图化&rdquo;设计【译】">CSS边框实现&ldquo;无图化&rdquo;设计【译】</a></li><li>2010-10-31 -- <a href="http://ofcss.com/2010/10/31/prevent-a-float-drop-in-ie6-translation.html" title="CSS技巧:如何避免IE6中的&quot;浮动下坠&quot;【译】">CSS技巧:如何避免IE6中的&quot;浮动下坠&quot;【译】</a></li><li>2010-10-25 -- <a href="http://ofcss.com/2010/10/25/understanding-user-behavior-google-analytics-event-tracking-jquer.html" title="借助jQuery和Google分析服务的事件追踪深入了解用户行为【译】">借助jQuery和Google分析服务的事件追踪深入了解用户行为【译】</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ofcss.com/2009/07/07/asp-net-mvc-best-practices-part-3.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>ASP.NET MVC 最佳实践（二）</title>
		<link>http://ofcss.com/2009/07/01/asp-net-mvc-best-practices-part-2.html</link>
		<comments>http://ofcss.com/2009/07/01/asp-net-mvc-best-practices-part-2.html#comments</comments>
		<pubDate>Tue, 30 Jun 2009 21:03:41 +0000</pubDate>
		<dc:creator>小李刀刀</dc:creator>
				<category><![CDATA[所谓技术]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[开发]]></category>
		<category><![CDATA[最佳实践]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://wukangrui.net/2009/07/01/asp-net-mvc-best-practices-part-2.html</guid>
		<description><![CDATA[本系列翻译自 Kazi Manzur Rashid 的博客，由于翻译水平有限，本系列可能存在误解偏差或者翻译不准的地方，建议对比原文进行阅读。由于篇幅关系，原文中的一篇文章在本系列中将拆解成多篇发布。本篇包括原文第一部分中的7-14节。如果你没有看过之前的第一部分，也许你想先看看 《ASP.NET MVC 最佳实践（一）》。]]></description>
			<content:encoded><![CDATA[<p><em>本系列翻译自 </em><a href="http://weblogs.asp.net/rashid/default.aspx"><em>Kazi Manzur Rashid</em></a><em> 的博客，由于翻译水平有限，本系列可能存在误解偏差或者翻译不准的地方，建议对比<a href="http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx">原文</a>进行阅读。由于篇幅关系，原文中的一篇文章在本系列中将拆解成多篇发布。本篇包括原文第一部分中的7-14节。如果你没有看过之前的第一部分，也许你想先看看 <a rel="prev" href="http://wukangrui.net/2009/06/28/asp-net-mvc-best-practices-part-1.html">《ASP.NET MVC 最佳实践（一）》</a>。</em></p>
<p><span id="more-829"></span></p>
<h4>7. 不要在控制器中使用HttpContext类及其派生类</h4>
<p>在你的控制器中不要引用到HttpContext以及它的派生类。这让你能比较容易地进行控制器的单元测试。如果你需要访问与HttpContext相关的对象比如User、QueryString、Cookie等，你可以使用自定义的行为过滤器（<a rel="external" href="http://www.cnblogs.com/" target="_blank">博客园</a>的<a rel="external" href="http://www.cnblogs.com/JeffreyZhao/" target="_blank">老赵</a>有<a rel="external" href="http://www.cnblogs.com/JeffreyZhao/archive/2009/03/09/no-dependency-to-httpcontext.html" target="_blank">一篇文章</a>对这一条进行了深入的论述，并提出了自己的解决方案，建议阅读）或者创建一些接口和容器，并把它传入控制器的构造函数。例如，下面的路由：</p>
<pre class="code">routes.MapRoute(
    <span style="color: #a31515">"Dashboard"</span>,
    <span style="color: #a31515">"Dashboard/{tab}/{orderBy}/{page}"</span>,
    <span style="color: blue">new </span>{
        controller = <span style="color: #a31515">"Story"</span>,
        action = <span style="color: #a31515">"Dashboard"</span>,
        tab = StoryListTab.Unread.ToString(),
        orderBy = OrderBy.CreatedAtDescending.ToString(),
        page = 1
    }
);</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>而控制器的行为方法则定义为：</p>
<pre class="code">[<span style="color: #2b91af">AcceptVerbs</span>(<span style="color: #2b91af">HttpVerbs</span>.Get),<span style="color: #2b91af">OutputCache</span>(CacheProfile = <span style="color: #a31515">"Dashboard"</span>),UserNameFilter]
<span style="color: blue">public </span><span style="color: #2b91af">ActionResult </span>Dashboard(<span style="color: blue">string </span>userName, StoryListTab tab, OrderBy orderBy, <span style="color: blue">int</span>? page) {
}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>UserNameFilter这个过滤器负责传递UserName：</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">UserNameFilter </span>: <span style="color: #2b91af">ActionFilterAttribute </span>{
    <span style="color: blue">public override void </span>OnActionExecuting(<span style="color: #2b91af">ActionExecutingContext </span>filterContext) {
        <span style="color: blue">const string </span>Key = <span style="color: #a31515">"userName"</span>;

        <span style="color: blue">if </span>(filterContext.ActionParameters.ContainsKey(Key)) {
            <span style="color: blue">if </span>(filterContext.HttpContext.User.Identity.IsAuthenticated) {
                filterContext.ActionParameters[Key] = filterContext.HttpContext.User.Identity.Name;
            }
        }

        <span style="color: blue">base</span>.OnActionExecuting(filterContext);
    }
}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p><strong>[更新：一定要明确你已经对控制器或者是对控制器中的行为添加了 Authorize 属性，参见<a rel="external" href="http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx#comments" target="_blank">原文评论</a>。]</strong></p>
<h4>8. 用行为控制器来转换行为方法参数</h4>
<p>用行为过滤器来把传入值转换为你的控制器行为方法参数，再看一下 Dashboard方法的代码，我们以 Enum 类型接受 tab 和 orderBy这两个参数。</p>
<pre class="code">[<span style="color: #2b91af">AcceptVerbs</span>(<span style="color: #2b91af">HttpVerbs</span>.Get), <span style="color: #2b91af">OutputCache</span>(CacheProfile = <span style="color: #a31515">"Dashboard"</span>), StoryListFilter]
<span style="color: blue">public </span><span style="color: #2b91af">ActionResult </span>Dashboard(<span style="color: blue">string </span>userName, StoryListTab tab, OrderBy orderBy, <span style="color: blue">int</span>? page) {
}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p> </p>
<p>过滤器 StoryListFilter 将负责把它由 路由的值/查询字符串 转换为适当的数据类型。</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">StoryListFilter </span>: <span style="color: #2b91af">ActionFilterAttribute </span>{
    <span style="color: blue">public override void </span>OnActionExecuting(<span style="color: #2b91af">ActionExecutingContext </span>filterContext) {
        <span style="color: blue">const string </span>TabKey = <span style="color: #a31515">"tab"</span>;
        <span style="color: blue">const string </span>OrderByKey = <span style="color: #a31515">"orderBy"</span>;

        NameValueCollection queryString = filterContext.HttpContext.Request.QueryString;

        StoryListTab tab = <span style="color: blue">string</span>.IsNullOrEmpty(queryString[TabKey]) ?
                            filterContext.RouteData.Values[TabKey].ToString().ToEnum(StoryListTab.Unread) :
                            queryString[TabKey].ToEnum(StoryListTab.Unread);

        filterContext.ActionParameters[TabKey] = tab;

        OrderBy orderBy = <span style="color: blue">string</span>.IsNullOrEmpty(queryString[OrderByKey]) ?
                            filterContext.RouteData.Values[OrderByKey].ToString().ToEnum(OrderBy.CreatedAtDescending) :
                            queryString[OrderByKey].ToEnum(OrderBy.CreatedAtDescending);

        filterContext.ActionParameters[OrderByKey] = orderBy;

        <span style="color: blue">base</span>.OnActionExecuting(filterContext);
    }
}</pre>
<p>你也可以用自定义模型绑定器来达到同样的目的。如果要那样做的话，你需要为每个枚举创建一个独立的模型绑定器，而不是用一个行为过滤器来处理所有的枚举参数。用模型绑定器还有一个问题，一旦你注册了一个类型，在行为中它就总是被使用，而行为过滤器则是可以根据需要选择使用的。</p>
<h4>9. 行为过滤器的位置</h4>
<p>如果你要对你的控制器的所有行为方法应用同一个行为过滤器，你可以把这个过滤器放在控制器的定义上而不必给每个行为方法应用。如果你要对你的所有控制器应用同一个行为过滤器，你应该创建一个基控制器，对它应用该过滤器，并让所有的控制器继承这个基控制器。例如 story 控制器应该只在用户已经登陆的情况下才可以使用，并且我们需要把当前用户的用户名传入 story 控制器下的方法，另外Story控制器应该压缩返回的数据：</p>
<pre class="code">[<span style="color: #2b91af">Authorize</span>, <span style="color: #2b91af">UserNameFilter</span>]
<span style="color: blue">public class </span><span style="color: #2b91af">StoryController </span>: <span style="color: #2b91af">BaseController </span>{
}

[CompressFilter]
<span style="color: blue">public class </span><span style="color: #2b91af">BaseController </span>: <span style="color: #2b91af">Controller </span>{
}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>但是如果继承的层次达到或者高于2层，应该另找方法来应用过滤器。最新的 <a rel="external" href="http://oxite.codeplex.com/" target="_blank">Oxite</a> 代码里有一些非常出色的动态应用过滤器的方法，我强烈推荐你去看一下。</p>
<h4>10. 小心使用UpdateModel</h4>
<p>我要再次强调 Justin Ethredge 在他的文章中已经提过的这个问题，开发中一定小心，避免陷进UpdateModel的陷阱里去。</p>
<h4>11.控制器不要包含任何域逻辑</h4>
<p>控制器应该只负责：</p>
<ul>
<li>验证输入</li>
<li>调用Model层来为显示视图准备数据</li>
<li>返回视图或者跳转到另一个行为</li>
</ul>
<p>如果你在控制器中坐了其它的事情，那就说明你把它们放错了地方。你在控制器中坐的这些事情或许更应该交给模型去处理。只要你遵守了这条规则，你的每个控制器方法代码应该不会超过20到25行。 <a rel="external" href="http://codebetter.com/blogs/ian_cooper/default.aspx" target="_blank">Ian Cooper</a> 有一篇很棒的文章《<a rel="external" href="http://codebetter.com/blogs/ian_cooper/archive/2008/12/03/the-fat-controller.aspx" target="_blank">Skin Controller Fat Model</a>》，有空的时候你一定要读一下。</p>
<h4>12. 避免使用 ViewData，尽量使用ViewData.Model</h4>
<p>依赖于数据字典不仅使你的代码难以重构，而且你还不得不在试图中编写转换代码。实际上即使你给你的控制器的每个方法都单独编写一个类作为数据模型，那也是完全可以的。如果你觉得编写这些视图数据模型类是一项非常乏味的工作的话，你可以使用 MVCContrib 项目中 ViewDataExtensions，它包含一些用于返回强类型对象的不错的扩展。但是如果你的视图数据的数据字典中包含了多个数据类型的话，你还是没办法摆脱数据字典和他的字符串名。</p>
<h4>13. 用 PRG 模式来修改数据</h4>
<p>Tim Barcz, Matt Hawley, Stephen Wather 甚至 Scott Gu 都写了这方面的文章，你可以在 <a rel="external" href="http://devlicio.us/blogs/tim_barcz/archive/2008/08/22/prg-pattern-in-the-asp-net-mvc-framework.aspx" target="_blank">这里</a>、<a rel="external" href="http://blog.eworldui.net/post/2008/05/ASPNET-MVC---Using-Post2c-Redirect2c-Get-Pattern.aspx" target="_blank">这里</a>、<a rel="external" href="http://stephenwalther.com/blog/archive/2008/06/20/asp-net-mvc-tip-6-call-redirecttoaction-after-submitting-a-form.aspx" target="_blank">这里</a>和<a rel="external" href="http://weblogs.asp.net/scottgu/archive/2008/09/02/asp-net-mvc-preview-5-and-form-posting-scenarios.aspx" target="_blank">这里</a>找到它们。这个模式的一个问题是当一项验证失败或者发生任何错误的时候，你不得不把ModelState复制到TempData里面。如果你是手动来做这件事，请不要再那样做了，你可以用行为过滤器自动处理它，就像下面这样：</p>
<pre class="code">[<span style="color: #2b91af">AcceptVerbs</span>(<span style="color: #2b91af">HttpVerbs</span>.Get), <span style="color: #2b91af">OutputCache</span>(CacheProfile = <span style="color: #a31515">"Dashboard"</span>), StoryListFilter, ImportModelStateFromTempData]
<span style="color: blue">public </span><span style="color: #2b91af">ActionResult </span>Dashboard(<span style="color: blue">string </span>userName, StoryListTab tab, OrderBy orderBy, <span style="color: blue">int</span>? page)
{
    <span style="color: green">//Other Codes
    </span><span style="color: blue">return </span>View();
}

[<span style="color: #2b91af">AcceptVerbs</span>(<span style="color: #2b91af">HttpVerbs</span>.Post), ExportModelStateToTempData]
<span style="color: blue">public </span><span style="color: #2b91af">ActionResult </span>Submit(<span style="color: blue">string </span>userName, <span style="color: blue">string </span>url)
{
    <span style="color: blue">if </span>(ValidateSubmit(url))
    {
        <span style="color: blue">try
        </span>{
            _storyService.Submit(userName, url);
        }
        <span style="color: blue">catch </span>(Exception e)
        {
            ModelState.AddModelError(ModelStateException, e);
        }
    }

    <span style="color: blue">return </span>Redirect(Url.Dashboard());
}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>还有行为过滤器的代码：</p>
<pre class="code"><span style="color: blue">public abstract class </span><span style="color: #2b91af">ModelStateTempDataTransfer </span>: <span style="color: #2b91af">ActionFilterAttribute </span>{
    <span style="color: blue">protected static readonly string </span>Key = <span style="color: blue">typeof</span>(<span style="color: #2b91af">ModelStateTempDataTransfer</span>).FullName;
}

<span style="color: blue">public class </span><span style="color: #2b91af">ExportModelStateToTempData </span>: <span style="color: #2b91af">ModelStateTempDataTransfer </span>{
    <span style="color: blue">public override void </span>OnActionExecuted(<span style="color: #2b91af">ActionExecutedContext </span>filterContext) {
        <span style="color: green">//Only export when ModelState is not valid
        </span><span style="color: blue">if </span>(!filterContext.Controller.ViewData.ModelState.IsValid) {
            <span style="color: green">//Export if we are redirecting
            </span><span style="color: blue">if </span>((filterContext.Result <span style="color: blue">is </span><span style="color: #2b91af">RedirectResult</span>) || (filterContext.Result <span style="color: blue">is </span><span style="color: #2b91af">RedirectToRouteResult</span>)) {
                filterContext.Controller.TempData[Key] = filterContext.Controller.ViewData.ModelState;
            }
        }

        <span style="color: blue">base</span>.OnActionExecuted(filterContext);
    }
}

<span style="color: blue">public class </span><span style="color: #2b91af">ImportModelStateFromTempData </span>: <span style="color: #2b91af">ModelStateTempDataTransfer </span>{
    <span style="color: blue">public override void </span>OnActionExecuted(<span style="color: #2b91af">ActionExecutedContext </span>filterContext) {
        <span style="color: #2b91af">ModelStateDictionary </span>modelState = filterContext.Controller.TempData[Key] <span style="color: blue">as </span><span style="color: #2b91af">ModelStateDictionary</span>;

        <span style="color: blue">if </span>(modelState != <span style="color: blue">null</span>) {
            <span style="color: green">//Only Import if we are viewing
            </span><span style="color: blue">if </span>(filterContext.Result <span style="color: blue">is </span><span style="color: #2b91af">ViewResult</span>) {
                filterContext.Controller.ViewData.ModelState.Merge(modelState);
            } <span style="color: blue">else </span>{
                <span style="color: green">//Otherwise remove it.
                </span>filterContext.Controller.TempData.Remove(Key);
            }
        }

        <span style="color: blue">base</span>.OnActionExecuted(filterContext);
    }
}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p><a rel="external" href="http://mvccontrib.codeplex.com" target="_blank">MVCContrib</a> 项目也有这个功能，但是我不喜欢他们在用一个单独类来处理的方式，我喜欢对“哪个方法输出”和“哪个方法输入”有更多的控制权。</p>
<h4>14. 为你的视图模型创建父类层并用行为过滤器来构成公共部分</h4>
<p>为你的视图模型类编写一个父类层，并用过滤器来构成它的公共部分。例如我正在开发的这个非常小的应用程序，我需要知道用户是否已经认证，已及用户名。</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">ViewModel </span>{
    <span style="color: blue">public bool </span>IsUserAuthenticated {
        <span style="color: blue">get</span>;
        <span style="color: blue">set</span>;
    }

    <span style="color: blue">public string </span>UserName {
        <span style="color: blue">get</span>;
        <span style="color: blue">set</span>;
    }
}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>还有行为过滤器的代码：</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">UserNameFilter </span>: <span style="color: #2b91af">ActionFilterAttribute </span>{
    <span style="color: blue">public override void </span>OnActionExecuting(<span style="color: #2b91af">ActionExecutingContext </span>filterContext) {
        <span style="color: blue">const string </span>Key = <span style="color: #a31515">"userName"</span>;

        <span style="color: blue">if </span>(filterContext.ActionParameters.ContainsKey(Key)) {
            <span style="color: blue">if </span>(filterContext.HttpContext.User.Identity.IsAuthenticated) {
                filterContext.ActionParameters[Key] = filterContext.HttpContext.User.Identity.Name;
            }
        }

        <span style="color: blue">base</span>.OnActionExecuting(filterContext);
    }
}

<span style="color: blue">public class </span><span style="color: #2b91af">ViewModelUserFilter </span>: <span style="color: #2b91af">ActionFilterAttribute </span>{
    <span style="color: blue">public override void </span>OnActionExecuted(<span style="color: #2b91af">ActionExecutedContext </span>filterContext) {
        ViewModel model;

        <span style="color: blue">if </span>(filterContext.Controller.ViewData.Model == <span style="color: blue">null</span>) {
            model = <span style="color: blue">new </span>ViewModel();
            filterContext.Controller.ViewData.Model = model;
        } <span style="color: blue">else </span>{
            model = filterContext.Controller.ViewData.Model <span style="color: blue">as </span>ViewModel;
        }

        <span style="color: blue">if </span>(model != <span style="color: blue">null</span>) {
            model.IsUserAuthenticated = filterContext.HttpContext.User.Identity.IsAuthenticated;

            <span style="color: blue">if </span>(model.IsUserAuthenticated) {
                model.UserName = filterContext.HttpContext.User.Identity.Name;
            }
        }

        <span style="color: blue">base</span>.OnActionExecuted(filterContext);
    }
}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>正如你所看到的，如果在控制器里预先设定它的话，它并没有替换模型，而是在它发现模型与它符合的时候，才作为控制器的公共部分起作用。另一个好处是，由于视图只依赖于父类层，你可以不必返回具体的model，而只需要返回 View()。</p>
<p>继续阅读：《<a rel="prev" href="http://wukangrui.net/2009/07/07/asp-net-mvc-best-practices-part-1-2.html">ASP.NET MVC 最佳实践（三）</a>》</p>
<h3  class="related_post_title">相关日志</h3><ul class="related_post"><li>2009-07-08 -- <a href="http://ofcss.com/2009/07/08/asp-net-mvc-best-practices-part-4.html" title="ASP.NET MVC 最佳实践（四）">ASP.NET MVC 最佳实践（四）</a></li><li>2009-07-07 -- <a href="http://ofcss.com/2009/07/07/asp-net-mvc-best-practices-part-3.html" title="ASP.NET MVC 最佳实践（三）">ASP.NET MVC 最佳实践（三）</a></li><li>2009-06-28 -- <a href="http://ofcss.com/2009/06/28/asp-net-mvc-best-practices-part-1.html" title="ASP.NET MVC 最佳实践（一）">ASP.NET MVC 最佳实践（一）</a></li><li>2009-04-13 -- <a href="http://ofcss.com/2009/04/13/aspnetmvc-hands-on-labs-develop-application.html" title="[翻译]ASP.NET MVC动手实验1-3：开发ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-3：开发ASP.NET MVC应用</a></li><li>2009-04-09 -- <a href="http://ofcss.com/2009/04/09/aspnetmvc-hands-on-labs-create-application.html" title="[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用</a></li><li>2009-04-09 -- <a href="http://ofcss.com/2009/04/09/aspnetmvc-hands-on-labs-introduction.html" title="[翻译]ASP.NET MVC动手系列1-1：ASP.NET MVC概述">[翻译]ASP.NET MVC动手系列1-1：ASP.NET MVC概述</a></li><li>2011-03-14 -- <a href="http://ofcss.com/2011/03/14/browser-rendering-optimizer-translation-extra.html" title="对《优化浏览器渲染》的补充【译】">对《优化浏览器渲染》的补充【译】</a></li><li>2011-03-10 -- <a href="http://ofcss.com/2011/03/10/css-border-tricks-with-collapsed-boxes-translation.html" title="CSS边框实现&ldquo;无图化&rdquo;设计【译】">CSS边框实现&ldquo;无图化&rdquo;设计【译】</a></li><li>2010-10-31 -- <a href="http://ofcss.com/2010/10/31/prevent-a-float-drop-in-ie6-translation.html" title="CSS技巧:如何避免IE6中的&quot;浮动下坠&quot;【译】">CSS技巧:如何避免IE6中的&quot;浮动下坠&quot;【译】</a></li><li>2010-10-25 -- <a href="http://ofcss.com/2010/10/25/understanding-user-behavior-google-analytics-event-tracking-jquer.html" title="借助jQuery和Google分析服务的事件追踪深入了解用户行为【译】">借助jQuery和Google分析服务的事件追踪深入了解用户行为【译】</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ofcss.com/2009/07/01/asp-net-mvc-best-practices-part-2.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>ASP.NET MVC 最佳实践（一）</title>
		<link>http://ofcss.com/2009/06/28/asp-net-mvc-best-practices-part-1.html</link>
		<comments>http://ofcss.com/2009/06/28/asp-net-mvc-best-practices-part-1.html#comments</comments>
		<pubDate>Sun, 28 Jun 2009 06:18:23 +0000</pubDate>
		<dc:creator>小李刀刀</dc:creator>
				<category><![CDATA[所谓技术]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[开发]]></category>
		<category><![CDATA[最佳实践]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://wukangrui.net/2009/06/28/asp-net-mvc-best-practices-part-1.html</guid>
		<description><![CDATA[本系列翻译自 Kazi Manzur Rashid 的博客，由于翻译水平有限，本系列可能存在误解偏差或者翻译不准的地方，建议对比原文进行阅读。由于篇幅关系，原文中的一篇文章在本系列中将拆解成多篇发布。本篇包括原文第一部分中的1-6节。]]></description>
			<content:encoded><![CDATA[<p><em>本系列翻译自 </em><a rel="external" href="http://weblogs.asp.net/rashid/default.aspx" target="_blank"><em>Kazi Manzur Rashid</em></a><em> 的博客，由于翻译水平有限，本系列可能存在误解偏差或者翻译不准的地方，建议对比<a rel="external" href="http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx" target="_blank">原文</a>进行阅读。由于篇幅关系，原文中的一篇文章在本系列中将拆解成多篇发布。本篇包括原文第一部分中的1-6节。</em></p>
<p><span id="more-821"></span></p>
<h4>1. 创建UrlHelper的扩展方法来生成url</h4>
<p>尽量避免以字符串方式直接传递controller, action 或者 route name，最好是为创建为UrlHelper创建扩展方法来封装url。例如：</p>
<pre class="code"><span style="color: blue">public static class </span><span style="color: #2b91af">UrlHelperExtension </span>{
    <span style="color: blue">public static string </span>Home(<span style="color: blue">this </span>UrlHelper helper) {
        <span style="color: blue">return </span>helper.Content(<span style="color: #a31515">"~/"</span>);
    }

    <span style="color: blue">public static string </span>SignUp(<span style="color: blue">this </span>UrlHelper helper) {
        <span style="color: blue">return </span>helper.RouteUrl(<span style="color: #a31515">"Signup"</span>);
    }

    <span style="color: blue">public static string </span>Dashboard(<span style="color: blue">this </span>UrlHelper helper) {
        <span style="color: blue">return </span>Dashboard(helper, StoryListTab.Unread);
    }

    <span style="color: blue">public static string </span>Dashboard(<span style="color: blue">this </span>UrlHelper helper, StoryListTab tab) {
        <span style="color: blue">return </span>Dashboard(helper, tab, OrderBy.CreatedAtDescending, 1);
    }

    <span style="color: blue">public static string </span>Dashboard(<span style="color: blue">this </span>UrlHelper helper, StoryListTab tab, OrderBy orderBy, <span style="color: blue">int </span>page) {
        <span style="color: blue">return </span>helper.RouteUrl(<span style="color: #a31515">"Dashboard"</span>, <span style="color: blue">new </span>{ tab = tab.ToString(), orderBy = orderBy.ToString(), page });
    }

    <span style="color: blue">public static string </span>Update(<span style="color: blue">this </span>UrlHelper helper) {
        <span style="color: blue">return </span>helper.RouteUrl(<span style="color: #a31515">"Update"</span>);
    }

    <span style="color: blue">public static string </span>Submit(<span style="color: blue">this </span>UrlHelper helper) {
        <span style="color: blue">return </span>helper.RouteUrl(<span style="color: #a31515">"Submit"</span>);
    }
}</pre>
<p>这样，如果在你的视图中有类似这样的代码：</p>
<pre class="code">    <span style="background: #ffee62">&lt;%</span><span style="color: blue">= </span>Html.ActionLink(<span style="color: #a31515">"Dashboard"</span>, <span style="color: #a31515">"Dashboard"</span>, <span style="color: #a31515">"Story"</span>) <span style="background: #ffee62">%&gt;
</span>    <span style="color: blue">&lt;</span><span style="color: #a31515">a </span><span style="color: red">href</span><span style="color: blue">="</span><span style="background: #ffee62">&lt;%</span>= Url.RouteUrl("Profile")<span style="background: #ffee62">%&gt;</span><span style="color: blue">"&gt;</span>Profile<span style="color: blue">&lt;/</span><span style="color: #a31515">a</span><span style="color: blue">&gt;</span></pre>
<p>你就可以用下面的这种方式来代替它们：</p>
<p><a href="http://11011.net/software/vspaste"></a></p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">a </span><span style="color: red">href</span><span style="color: blue">="</span><span style="background: #ffee62">&lt;%</span>= Url.Dashboard() <span style="background: #ffee62">%&gt;</span><span style="color: blue">"&gt;</span>Dashboard<span style="color: blue">&lt;/</span><span style="color: #a31515">a</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">a </span><span style="color: red">href</span><span style="color: blue">="</span><span style="background: #ffee62">&lt;%</span>= Url.Profile() <span style="background: #ffee62">%&gt;</span><span style="color: blue">"&gt;</span>Profile<span style="color: blue">&lt;/</span><span style="color: #a31515">a</span><span style="color: blue">&gt;</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>在控制器里也可以用，原来的代码：</p>
<pre class="code"><span style="color: blue">return </span>RedirectToAction(
    <span style="color: #a31515">"Dashboard"</span>,
    <span style="color: #a31515">"Story"</span>,
    <span style="color: blue">new </span>{
        tab = StoryListTab.Favorite,
        orderBy = OrderBy.CreatedAtAscending,
        page = 1
    }
);</pre>
<p>可以写成：</p>
<pre class="code"><span style="color: blue">return </span>Redirect(Url.Dashboard(StoryListTab.Favorite,
                                OrderBy.CreatedAtAscending, 1));</pre>
<p>当然了，你也可以使用 <a rel="external" href="http://www.tampadev.org/News/Details/DownloadASPNETMVCFuturesMicrosoftWebMvcAssembly" target="_blank">future assembly</a> 中的强类型版本来获得控制器、方法以及参数值，或者创建你自己的强类型版本以免将来进行重构时太过于痛苦，但是请一定记住，它没有官方支持并且将来有可能会发生改变。上面的方式也可以和强类型版本搭配使用。当然“另外增加一个间接层”（Scott Ha 喜欢用的引语）有一些好处，在编写单元测试的时候还有一个好处是你只需处理 <a rel="tag" href="http://msdn.microsoft.com/zh-cn/library/system.web.mvc.redirectresult.aspx" target="_blank">RedirectResult</a> 而无须同时处理 RedirectResult 和 <a rel="tag" href="http://msdn.microsoft.com/zh-cn/library/system.web.mvc.redirecttorouteresult.aspx" target="_blank">RedirectToRouteResult</a>。</p>
<h4>2. Create Extension Method of UrlHelper to map your JavaScript, Stylesheet and Image Folder</h4>
<p>默认情况下 <a rel="tag" href="http://www.asp.net/mvc/" target="_blank">ASP.NET MVC</a> 创建Content、Scripts文件夹来做这些事，这一点我不喜欢，我更喜欢下面的这种文件夹结构，这样在IIS里我可以只让静态文件缓存在Assets文件夹而不是多个文件夹：</p>
<ul>
<li>Assets</li>
<li>+images</li>
<li>+scripts</li>
<li>+stylesheets</li>
</ul>
<p>无论是结构是什么样的，还是要为UrlHelper创建一些扩展方法来映射这些文件夹，以便你在视图中可以很方便地指向它们，这样以后如果你要改变目录结构，你就无须做大量查找替换的工作。我还建议你为所有经常在视图中用到的资源创建UrlHelper的扩展方法。例如：</p>
<pre class="code"><span style="color: blue">public static string </span>Image(<span style="color: blue">this </span>UrlHelper helper, <span style="color: blue">string </span>fileName) {
    <span style="color: blue">return </span>helper.Content(<span style="color: #a31515">"~/assets/images/{0}"</span>.FormatWith(fileName));
}

<span style="color: blue">public static string </span>Stylesheet(<span style="color: blue">this </span>UrlHelper helper, <span style="color: blue">string </span>fileName) {
    <span style="color: blue">return </span>helper.Content(<span style="color: #a31515">"~/assets/stylesheets/{0}"</span>.FormatWith(fileName));
}

<span style="color: blue">public static string </span>NoIcon(<span style="color: blue">this </span>UrlHelper helper) {
    <span style="color: blue">return </span>Image(helper, <span style="color: #a31515">"noIcon.png"</span>);
}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>然后当需要用到这些路径的时候，原来的代码</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">link </span><span style="color: red">href</span><span style="color: blue">="../../Content/Site.css" </span><span style="color: red">rel</span><span style="color: blue">="stylesheet" </span><span style="color: red">type</span><span style="color: blue">="text/css" /&gt;</span></pre>
<p>就可以写成这样：<a href="http://11011.net/software/vspaste"></a></p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">link </span><span style="color: red">href</span><span style="color: blue">="</span><span style="background: #ffee62">&lt;%</span>= Url.Stylesheet("site.css")<span style="background: #ffee62">%&gt;</span><span style="color: blue">" </span><span style="color: red">rel</span><span style="color: blue">="stylesheet" </span><span style="color: red">type</span><span style="color: blue">="text/css" /&gt;</span></pre>
<h4>3. 中使用启动加载器</h4>
<p>我在<a rel="prev" href="http://weblogs.asp.net/rashid/archive/2009/02/17/use-bootstrapper-in-your-asp-net-mvc-application-and-reduce-code-smell.aspx" target="_blank">以前的文章</a>中已经提到过这一点，总的来说就是：如果你要在 Global.asax 的 Application_Start 中做很多处理，比如 注册路由规则(Routers)、注册控制器工厂(Controller Factory)、模型绑定(Model Binders)、视图引擎(View Engine)、启动程序级的特定<a rel="external" href="http://weblogs.asp.net/rashid/archive/2009/03/05/use-event-aggregator-to-make-your-application-more-extensible.aspx" target="_blank">后台服务</a>或者为特定部分创建独立任务等，那就用<a rel="prev" href="http://weblogs.asp.net/rashid/archive/2009/03/05/use-event-aggregator-to-make-your-application-more-extensible.aspx" target="_blank">启动加载器</a>来执行这些操作。这会让你的代码更简洁，更可测。这一点在用 <a rel="tag" href="http://www.asp.net/mvc/" target="_blank">ASP.NET MVC</a> 构建门户级应用时尤其有用，因为这类应用中的每个模块都可能有一些不影响到其他模块的启动初始化操作。但是如果你只是开发一个小应用，上面提到的这些对你来说都不是问题，你当然也可以继续用默认的 global.asax。</p>
<h4>4. 不要硬编码对依赖注入容器的调用，用通用服务定位器来代替。</h4>
<p>不要让任何特定的依赖注入容器(DI Container)打乱你的代码，更好的办法是使用通用服务定位器(<a rel="external" href="http://commonservicelocator.codeplex.com/" target="_blank">Common Service Locator</a>)，它是对底层依赖注入进行的抽象，已经支持几乎所有流行的依赖注入容器，它让你可以任意替换底层的依赖注入对象而无须修改代码，因为每个依赖注入容器都具有一些不同于其它容器的特性。<a rel="external" href="http://devlicio.us/blogs/tim_barcz/" target="_blank">Tim Barcz</a> 最近写了一篇关于这个话题的<a rel="external" href="http://devlicio.us/blogs/tim_barcz/archive/2009/03/29/your-ioc-container-choice-is-not-a-feature-of-your-application.aspx" target="_blank">很棒的文章</a>，我不太明白他为什么没有提到我们对我们偏爱的依赖注入容器有多痴迷。通用服务定位器对绝大部分常用情景都提供了支持，而对一些特殊情况比如对已实体化对象的依赖注入，我印象里有 <a rel="external" href="http://codebetter.com/blogs/jeremy.miller/archive/2009/01/16/quot-buildup-quot-existing-objects-with-structuremap.aspx" target="_blank">StructureMap</a>、<a rel="external" href="http://codeclimber.net.nz/archive/2009/02/10/how-to-use-ninject-to-inject-dependencies-into-asp.net-mvc.aspx" target="_blank">Ninject</a> 和 Unity，你可以调用静态方法 ServiceLocator.Current.GetInstance 来代替。 通用服务定位器 是 <a rel="external" href="http://codebetter.com/blogs/jeremy.miller/archive/2008/08/16/it-s-time-for-ioc-container-detente.aspx" target="_blank">Jeremy D Miller</a> 发起的 依赖注入容器开发者(the DI Containers creators)的集体作品。</p>
<p>用通用服务定位器创建控制器工厂非常容易：</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">CommonServiceLocatorControllerFactory </span>: <span style="color: #2b91af">DefaultControllerFactory </span>{
    <span style="color: blue">protected override </span><span style="color: #2b91af">IController </span>GetControllerInstance(<span style="color: #2b91af">Type </span>controllerType) {
        <span style="color: blue">return </span>(controllerType == <span style="color: blue">null</span>) ? <span style="color: blue">base</span>.GetControllerInstance(controllerType) : ServiceLocator.Current.GetInstance(controllerType) <span style="color: blue">as </span><span style="color: #2b91af">IController</span>;
    }
}</pre>
<p>我希望 MVCContrib 的成员们也用这样的方式，而不是为每个容器创建一个独立的控制器工厂。</p>
<h4>5. 用恰当的的AcceptVerbs属性来修饰你的控制器方法</h4>
<p><a rel="tag" href="http://www.asp.net/mvc/" target="_blank">ASP.NET MVC</a> 比 Web Forms 更容易遭受攻击。所以务必让对数据进行修改的控制器方法只接受 Post 方式请求（HttpVerbs.Post）。如果安全对你来说至关重要，你还可以用 ValidateAntiForgeryToken 或者 Captcha。我强烈推荐 <a rel="external" href="http://devlicio.us/blogs/derik_whittaker/" target="_blank">Derik Whittaker</a> 写的一篇 <a rel="external" href="http://devlicio.us/blogs/derik_whittaker/archive/2008/12/02/using-recaptcha-with-asp-net-mvc.aspx" target="_blank">很好的文章</a> 以及<a rel="external" href="http://www.dimecasts.net/Casts/CastDetails/76" target="_blank">视频</a>介绍了怎么把 reCaptcha 整合到 <a rel="tag" href="http://www.asp.net/mvc/" target="_blank">ASP.NET MVC</a> 应用程序（作者注：不要错过了 <a rel="external" href="http://www.dimecasts.net/" target="_blank">DimeCasts.net</a> 的另一个短片，我从中学到了很多）。我的经验法则是对所有数据修改方法使用 HttpVerbs.Post，对所有数据读取操作使用 HttpVerbs.Get。</p>
<h4>6. 用OutputCache修饰你的频繁调用的操作方法</h4>
<p>当你需要返回不频繁更新的数据时使用 OutputCache 属性，最常见的例子是首页、Feed等。你在返回Html以及Json数据类型的方法中都可以使用这个属性。在使用的时候，注意只指定CacheProfile参数，不要指定任何其它东西，用 web.config 输出缓存控制节可以很好地调整它。例如：</p>
<pre class="code">[<span style="color: #2b91af">AcceptVerbs</span>(<span style="color: #2b91af">HttpVerbs</span>.Get), <span style="color: #2b91af">OutputCache</span>(CacheProfile = <span style="color: #a31515">"Dashboard"</span>)]
<span style="color: blue">public </span><span style="color: #2b91af">ActionResult </span>Dashboard(<span style="color: blue">string </span>userName, StoryListTab tab, OrderBy orderBy, <span style="color: blue">int</span>? page) {
}</pre>
<p>在 web.config 文件中的配置：<a href="http://11011.net/software/vspaste"></a></p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">system.web</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">caching</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">outputCacheSettings</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">outputCacheProfiles</span><span style="color: blue">&gt;
                &lt;</span><span style="color: #a31515">clear</span><span style="color: blue">/&gt;
                &lt;!-- </span><span style="color: green">15 Seconds </span><span style="color: blue">--&gt;
                &lt;</span><span style="color: #a31515">add
                    </span><span style="color: red">name</span><span style="color: blue">=</span>"<span style="color: blue">Dashboard</span>"
                    <span style="color: red">duration</span><span style="color: blue">=</span>"<span style="color: blue">15</span>"
                    <span style="color: red">varyByParam</span><span style="color: blue">=</span>"<span style="color: blue">*</span>"
                    <span style="color: red">location</span><span style="color: blue">=</span>"<span style="color: blue">Client</span>"
                    <span style="color: blue">/&gt;
            &lt;/</span><span style="color: #a31515">outputCacheProfiles</span><span style="color: blue">&gt;
        &lt;/</span><span style="color: #a31515">outputCacheSettings</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">caching</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">system.web</span><span style="color: blue">&gt;</span></pre>
<p>请继续阅读：《<a rel="next" href="http://wukangrui.net/2009/07/01/asp-net-mvc-best-practices-part-2.html">ASP.NET MVC 最佳实践（二）</a>》</p>
<h3  class="related_post_title">相关日志</h3><ul class="related_post"><li>2009-07-08 -- <a href="http://ofcss.com/2009/07/08/asp-net-mvc-best-practices-part-4.html" title="ASP.NET MVC 最佳实践（四）">ASP.NET MVC 最佳实践（四）</a></li><li>2009-07-07 -- <a href="http://ofcss.com/2009/07/07/asp-net-mvc-best-practices-part-3.html" title="ASP.NET MVC 最佳实践（三）">ASP.NET MVC 最佳实践（三）</a></li><li>2009-07-01 -- <a href="http://ofcss.com/2009/07/01/asp-net-mvc-best-practices-part-2.html" title="ASP.NET MVC 最佳实践（二）">ASP.NET MVC 最佳实践（二）</a></li><li>2009-04-13 -- <a href="http://ofcss.com/2009/04/13/aspnetmvc-hands-on-labs-develop-application.html" title="[翻译]ASP.NET MVC动手实验1-3：开发ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-3：开发ASP.NET MVC应用</a></li><li>2009-04-09 -- <a href="http://ofcss.com/2009/04/09/aspnetmvc-hands-on-labs-create-application.html" title="[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用</a></li><li>2009-04-09 -- <a href="http://ofcss.com/2009/04/09/aspnetmvc-hands-on-labs-introduction.html" title="[翻译]ASP.NET MVC动手系列1-1：ASP.NET MVC概述">[翻译]ASP.NET MVC动手系列1-1：ASP.NET MVC概述</a></li><li>2011-03-14 -- <a href="http://ofcss.com/2011/03/14/browser-rendering-optimizer-translation-extra.html" title="对《优化浏览器渲染》的补充【译】">对《优化浏览器渲染》的补充【译】</a></li><li>2011-03-10 -- <a href="http://ofcss.com/2011/03/10/css-border-tricks-with-collapsed-boxes-translation.html" title="CSS边框实现&ldquo;无图化&rdquo;设计【译】">CSS边框实现&ldquo;无图化&rdquo;设计【译】</a></li><li>2010-10-31 -- <a href="http://ofcss.com/2010/10/31/prevent-a-float-drop-in-ie6-translation.html" title="CSS技巧:如何避免IE6中的&quot;浮动下坠&quot;【译】">CSS技巧:如何避免IE6中的&quot;浮动下坠&quot;【译】</a></li><li>2010-10-25 -- <a href="http://ofcss.com/2010/10/25/understanding-user-behavior-google-analytics-event-tracking-jquer.html" title="借助jQuery和Google分析服务的事件追踪深入了解用户行为【译】">借助jQuery和Google分析服务的事件追踪深入了解用户行为【译】</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ofcss.com/2009/06/28/asp-net-mvc-best-practices-part-1.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>[翻译]ASP.NET MVC动手实验1-3：开发ASP.NET MVC应用</title>
		<link>http://ofcss.com/2009/04/13/aspnetmvc-hands-on-labs-develop-application.html</link>
		<comments>http://ofcss.com/2009/04/13/aspnetmvc-hands-on-labs-develop-application.html#comments</comments>
		<pubDate>Mon, 13 Apr 2009 17:41:50 +0000</pubDate>
		<dc:creator>小李刀刀</dc:creator>
				<category><![CDATA[所谓技术]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[Visual Studio]]></category>
		<category><![CDATA[动手实验]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://wukangrui.net/2009/04/13/aspnetmvc-hands-on-labs-develop-application.html</guid>
		<description><![CDATA[在这次的练习中，你将学习如何开发一个 ASP.NET 应用，整个练习过程包括创建控制器、视图和模型。 通过这次练习，要创建一个分页显示用户列表的 ASP.NET MVC应用。具有显示用户资料，以及创建、修改、删除用户地址的功能。该应用共有三个控制器：用户控制器处理用户信息列表和显示用户信息；地址控制器负责用户地址的创建、编辑和删除；主页控制器负责显示站点的欢迎页面。 提示：为了确保每个步骤都正常运行，最好在每个任务结束的时候都编译整个解决方案。 任务1 &#8211; 创建实体数据模型 在本任务中你要用 实体数据模型（Entity Data Model）创建可编程实体类到数据存储结构（通常是SQL Server数据库或者其他数据库）的映射。Entity Data Model (EDM) 是在 实体框架 (Entity Framework）中专门设计来作为程序中的数据定义的。 点击 开始 &#124; 所有程序 &#124; Microsoft Visual Studio 2008 &#124; Microsoft Visual Studio 2008 启动 VS 2008。 打开 AspNetMvcEx02-DevelopingMvcAppbegin 目录下的解决方案文件 MvcSampleApp.sln。 在 解决方案浏览器 中， 打开 Views 目录下的 Shared 目录。步骤：点击目录名字前面的加号图标，选择 Site.Master 文件， 右键点击它并选择 删除 [...]]]></description>
			<content:encoded><![CDATA[<p>在这次的练习中，你将学习如何开发一个 ASP.NET 应用，整个练习过程包括创建控制器、视图和模型。</p>
<p>通过这次练习，要创建一个分页显示用户列表的 ASP.NET MVC应用。具有显示用户资料，以及创建、修改、删除用户地址的功能。该应用共有三个控制器：用户控制器处理用户信息列表和显示用户信息；地址控制器负责用户地址的创建、编辑和删除；主页控制器负责显示站点的欢迎页面。</p>
<p>提示：为了确保每个步骤都正常运行，最好在每个任务结束的时候都编译整个解决方案。</p>
<p> <span id="more-474"></span>
<p><b>任务1 &#8211; 创建实体数据模型</b></p>
<p>在本任务中你要用 <strong>实体数据模型</strong>（<strong>Entity Data Model</strong>）创建可编程实体类到数据存储结构（通常是SQL Server数据库或者其他数据库）的映射。<strong>Entity Data Model</strong> (EDM) 是在 实体框架 (Entity Framework）中专门设计来作为程序中的数据定义的。</p>
<ol>
<li>点击 <strong>开始 | 所有程序 | Microsoft Visual Studio 2008 | Microsoft Visual Studio 2008</strong> 启动 VS 2008。</li>
<li> 打开 <strong>AspNetMvcEx02-DevelopingMvcAppbegin</strong> 目录下的解决方案文件 <strong>MvcSampleApp.sln</strong>。</li>
<li>在 <strong>解决方案浏览器</strong> 中， 打开 <strong>Views</strong> 目录下的 <strong>Shared</strong> 目录。步骤：点击目录名字前面的加号图标，选择 <strong>Site.Master</strong> 文件， 右键点击它并选择 <strong>删除 </strong>。</li>
<li>导入提供的 Site.Master。 步骤：右键点击 <strong>Shared</strong> 文件夹， 指向 <strong>添加</strong> 然后选择 <strong>现有项</strong>。在 <strong>添加现有项</strong> 对话框中，转到 <strong>AspNetMvcAssetsShared</strong> 目录，然后选中该目录下的所有文件（实际就只有一个 Site.Master 文件），点 <strong>添加</strong>。&#160;
<p>提示：与传统的 ASP.NET Web 页面一样， ASP.NET 页面视图 (.aspx 文件)可以使用母版页来为站点的通用部分提供统一的样式。</p>
</li>
<li>
<p>创建 <strong>AdventureWorks</strong> 实体数据模型。步骤：在 解决方案浏览器 中， 在 <strong>MvcSampleApp</strong> 项目中右键点击 <strong>Models</strong> 文件夹， 指向 <strong>添加</strong>， 然后点击 <strong>新建项</strong>。</p>
</li>
<li>在 <strong>新建项</strong> 对话框里选择 <strong>ADO.NET Entity Data Model</strong>。将要创建的项命名为 <strong>AdventureWorks.edmx</strong>，然后点 <strong>添加</strong>。&#160;
<p><a href="http://file.wukangrui.com/attachments/2009/04/image7.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://file.wukangrui.com/attachments/2009/04/image-thumb7.png" width="644" height="437" /></a>        <br /><em><strong>图一</strong> 添加 ADO.NET Entity Data Model</em></p>
</li>
<li>在 <strong>实体模型数据向导</strong> 打开后， 选择 <strong>从数据库生成</strong> 然后点击 <strong>下一步</strong>。</li>
<li>点击 <strong>新建连接</strong> 定义数据库连接。 </li>
<li>In the <b>Choose Data Source</b> dialog, select <b>Microsoft SQL Server</b> as <b>Data Source</b> and click <b>Continue</b>. 在 <strong>选择数据库</strong> 对话框中，选择<strong> Microsoft SQL Server</strong> 作为数据源，然后点 <strong>继续</strong>。（这一步在大部分情况下默认不出现）</li>
<li>In the <b>Connection Properties</b> dialog window, enter <b>AspNetMvcLabs</b> as <b>Server Name</b>, then select <b>AdventureWorksLT</b> database and click <b>OK</b>.在 <strong>连接属性</strong> 对话框里，输入你的 <strong>本地 SQL Server 安装实例 </strong>名称（例如“.”或者“.SQLEXPRESS”），然后在下方选择 <strong>AdventureWorksLT</strong> 数据库 （没有安装 SQL Server 2005 示例数据库的可以从网上下载安装），然后点击 <strong>OK</strong>。
<p>Note:<b>AspNetMvcLabs</b> is the default alias for the database server installed when the <b>SetupEx.cmd</b> script was run at the beginning of this lab.</p>
<p><a href="http://file.wukangrui.com/attachments/2009/04/image8.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://file.wukangrui.com/attachments/2009/04/image-thumb8.png" width="455" height="733" /></a>&#160; <br /><em><b>图二 </b>定义数据连接</em></p>
</li>
<li>回到 <strong>实体数据模型向导</strong>， 点击 <strong>下一步</strong>。</li>
<li>在 <strong>选择数据库对象</strong> 这一步，只需要选择以下三个表：&#160;
<ul>
<li><b>Address (SalesLT)Address </b></li>
<li><b>Customer (SalesLT)</b></li>
<li><b>CustomerAddress (SalesLT)</b></li>
</ul>
</li>
<li>保持 <strong>模型命名空间</strong> 这一项为默认值，点击 <strong>完成</strong>。&#160;
<p><a href="http://file.wukangrui.com/attachments/2009/04/image9.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://file.wukangrui.com/attachments/2009/04/image-thumb9.png" width="484" height="484" /></a>&#160; <br /><strong>图三 </strong><i>选择要包含在模型中的数据库对象</i></p>
</li>
<li>
<p>创建数据容器类 AdventureWorksRepository，这个容器类向其它类暴露数据访问方法，通过这些方法从底层数据模型获取数据实体。在 MvcSampleApp 项目中右击 Models 目录，指向 添加 然后点击 现有项。转到 AspNetMvcAssets 目录， 选择 AdventureWorksRepository.cs 文件，然后点击 添加。       <br />提示：更多详细信息，参见 <a href="http://msdn2.microsoft.com/zh-cn/library/bb387122.aspx" target="_blank">实体数据模型</a> 。</p>
</li>
</ol>
<p>（未完待续）</p>
<h3  class="related_post_title">相关日志</h3><ul class="related_post"><li>2009-04-09 -- <a href="http://ofcss.com/2009/04/09/aspnetmvc-hands-on-labs-create-application.html" title="[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用</a></li><li>2009-04-09 -- <a href="http://ofcss.com/2009/04/09/aspnetmvc-hands-on-labs-introduction.html" title="[翻译]ASP.NET MVC动手系列1-1：ASP.NET MVC概述">[翻译]ASP.NET MVC动手系列1-1：ASP.NET MVC概述</a></li><li>2009-07-08 -- <a href="http://ofcss.com/2009/07/08/asp-net-mvc-best-practices-part-4.html" title="ASP.NET MVC 最佳实践（四）">ASP.NET MVC 最佳实践（四）</a></li><li>2009-07-07 -- <a href="http://ofcss.com/2009/07/07/asp-net-mvc-best-practices-part-3.html" title="ASP.NET MVC 最佳实践（三）">ASP.NET MVC 最佳实践（三）</a></li><li>2009-07-01 -- <a href="http://ofcss.com/2009/07/01/asp-net-mvc-best-practices-part-2.html" title="ASP.NET MVC 最佳实践（二）">ASP.NET MVC 最佳实践（二）</a></li><li>2009-06-28 -- <a href="http://ofcss.com/2009/06/28/asp-net-mvc-best-practices-part-1.html" title="ASP.NET MVC 最佳实践（一）">ASP.NET MVC 最佳实践（一）</a></li><li>2009-04-30 -- <a href="http://ofcss.com/2009/04/30/solution-for-js-intellisense-error.html" title="VS2008 中 JS IntelliSense出错的解决">VS2008 中 JS IntelliSense出错的解决</a></li><li>2011-03-14 -- <a href="http://ofcss.com/2011/03/14/browser-rendering-optimizer-translation-extra.html" title="对《优化浏览器渲染》的补充【译】">对《优化浏览器渲染》的补充【译】</a></li><li>2011-03-10 -- <a href="http://ofcss.com/2011/03/10/css-border-tricks-with-collapsed-boxes-translation.html" title="CSS边框实现&ldquo;无图化&rdquo;设计【译】">CSS边框实现&ldquo;无图化&rdquo;设计【译】</a></li><li>2010-10-31 -- <a href="http://ofcss.com/2010/10/31/prevent-a-float-drop-in-ie6-translation.html" title="CSS技巧:如何避免IE6中的&quot;浮动下坠&quot;【译】">CSS技巧:如何避免IE6中的&quot;浮动下坠&quot;【译】</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ofcss.com/2009/04/13/aspnetmvc-hands-on-labs-develop-application.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用</title>
		<link>http://ofcss.com/2009/04/09/aspnetmvc-hands-on-labs-create-application.html</link>
		<comments>http://ofcss.com/2009/04/09/aspnetmvc-hands-on-labs-create-application.html#comments</comments>
		<pubDate>Thu, 09 Apr 2009 15:08:09 +0000</pubDate>
		<dc:creator>小李刀刀</dc:creator>
				<category><![CDATA[所谓技术]]></category>
		<category><![CDATA[Ajax]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[Visual Studio]]></category>
		<category><![CDATA[动手实验]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://wukangrui.net/2009/04/09/aspnetmvc-hands-on-labs-create-application.html</guid>
		<description><![CDATA[在这个练习中你将学习如何在 Visual Studio 中创建一个 ASP.NET MVC 应用。并初步了解默认项目结构和一些开发约定。 ASP.NET MVC 框架分为 Model， View 和 Controller 三个部分。模型组件（Model）一般用于维护数据库中的持久数据层的状态。视图组件（View）由控制器挑选并渲染到适当的用户界面。默认状态下， ASP.NET MVC 框架用ASP.NET已有的 ASP.NET 页面（.aspx）、 母版页（.master）以及用户控件（.ascx）等类型来作为浏览器呈现。控制器组件（Controller）组件将用户请求定位到适当的控制器（Controller）行为（Action）和方法（Method），从请求中获取用于行为方法运行的参数值， 并处理行为和方法执行中可能产生的错误。 然后控制器用该请求对应的视图进行渲染。 默认状况下，每个组件存放在 MVC WEB 应用工程的一个独立目录下。 任务1 &#8211; 创建一个 ASP.NET MVC Web 应用工程 在这个任务中你将通过Visual Studio的MVC模板创建和配置一个空的 ASP.NET MVC 应用工程。 打开 Microsoft Visual Studio 2008：依次点击 开始&#124;所有程序&#124;Microsoft Visual Studio 2008&#124;Microsoft Visual Studio 2008. 点击 文件 菜单， 指向 [...]]]></description>
			<content:encoded><![CDATA[<p>在这个练习中你将学习如何在 Visual Studio 中创建一个 ASP.NET MVC 应用。并初步了解默认项目结构和一些开发约定。</p>
<p>ASP.NET MVC 框架分为 Model， View 和 Controller 三个部分。模型组件（Model）一般用于维护数据库中的持久数据层的状态。视图组件（View）由控制器挑选并渲染到适当的用户界面。默认状态下， ASP.NET MVC 框架用ASP.NET已有的 ASP.NET 页面（.aspx）、 母版页（.master）以及用户控件（.ascx）等类型来作为浏览器呈现。控制器组件（Controller）组件将用户请求定位到适当的控制器（Controller）行为（Action）和方法（Method），从请求中获取用于行为方法运行的参数值， 并处理行为和方法执行中可能产生的错误。 然后控制器用该请求对应的视图进行渲染。 默认状况下，每个组件存放在 MVC WEB 应用工程的一个独立目录下。</p>
<p><span id="more-444"></span></p>
<p><strong>任务1 &#8211; 创建一个 ASP.NET MVC Web 应用工程</strong></p>
<p>在这个任务中你将通过Visual Studio的MVC模板创建和配置一个空的 ASP.NET MVC 应用工程。</p>
<ol>
<li>打开 Microsoft Visual Studio 2008：依次点击 <strong>开始</strong>|<strong>所有程序</strong>|<strong>Microsoft Visual Studio 2008</strong>|<strong>Microsoft Visual Studio 2008</strong>.</li>
<li>点击 <strong>文件</strong> 菜单， 指向 <strong>新建</strong>， 然后点击 <strong>项目</strong>。</li>
<li>在 <strong>新建项目</strong> 对话框中，确保右上角选中的版本为 <strong>.NET Framework 3.5</strong>，在 <strong>项目类型</strong> 下选择 <strong>Visual C#</strong>，然后在 <strong>Visual Studio 已安装的模板</strong> 中选择 <strong>ASP.NET MVC Web Application</strong> 类型。你可以设置项目位置为 <strong>你的路径AspNetMvcEx01-CreatingMvcAppbegin </strong>作为项目目录。</li>
<li>修改 <strong>名称</strong> 为 <strong>MvcSampleApp</strong> 然后点击 确定 。 <a href="http://file.wukangrui.com/attachments/2009/04/image.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" src="http://file.wukangrui.com/attachments/2009/04/image-thumb.png" border="0" alt="image" width="605" height="484" /> </a><em>图一：创建新项目对话框<br />
</em>在点击 确定 按钮之后，Visual Studio 会问你是否同时创建测试项目（would you like to create a test project）。选择 <strong>Yes</strong>， 输入 <strong>MvcSampleApp.Test</strong> 作为<strong>项目名称</strong>（<strong>Name</strong> of the Project）， 然后点击 <strong>确定</strong>（<strong>OK</strong>）。注：我安装的是Visual Studio 2008 SP1 简体中文版 + ASP.NET MVC 1.0，在我的系统上，创建测试项目的对话框为英文，因此这里加上英文对照。<br />
提示：当你创建一个新的MVC Web应用时， Visual Studio 会为你提供同时创建两个项目的选择，第一个项目是Web项目用来实现你的应用，第二个项目是一个测试项目，你可以在其中为你的MVC组件编写单元测试。<br />
<a href="http://file.wukangrui.com/attachments/2009/04/image2.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" src="http://file.wukangrui.com/attachments/2009/04/image-thumb2.png" border="0" alt="image" width="552" height="367" /></a><br />
<em>图二：创建 MVC 单元测试项目<br />
</em>提示：测试项目对话框中的 测试框架（Test Framework） 下拉列表现在只有一个 Visual Studio Unit Test，这个列表是可扩展的，在你的机器上安装了其他测试框架的时候，它将会包含其他的测试框架供你选择。由此你可以容易地用你喜欢的单元测试框架来为你的 ASP.NET MVC 应用编写单元测试。</li>
<li>在Visual Studio 中配置站点使用端口 50000。这一步是为了和本动手实验中的后续联系保持一致所必须的。
<ol type="a">
<li>在 <strong>解决方案浏览器</strong> 中，右击 <strong>MvcSampleApp</strong> 项目，并在上下文菜单中选择 <strong>属性</strong> 。</li>
<li>在 <strong>属性</strong> 页中，打开 <strong>Web</strong> 标签。</li>
<li>In the <strong>Servers</strong> section select <strong>Specific Port</strong>. 在 <strong>服务器</strong> 设置项下面，选择 <strong>使用Visual Studio开发服务器</strong>，并选中 <strong>特定端口</strong> 。</li>
<li>设置端口号为 <strong>50000</strong> 。</li>
<li>按下 <strong>Ctr + S</strong> 保存所做的改动。</li>
</ol>
<p><a href="http://file.wukangrui.com/attachments/2009/04/image3.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" src="http://file.wukangrui.com/attachments/2009/04/image-thumb3.png" border="0" alt="image" width="635" height="480" /></a><br />
<em>图三：配置本地测试属性</em></li>
</ol>
<h3  class="related_post_title">相关日志</h3><ul class="related_post"><li>2009-04-13 -- <a href="http://ofcss.com/2009/04/13/aspnetmvc-hands-on-labs-develop-application.html" title="[翻译]ASP.NET MVC动手实验1-3：开发ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-3：开发ASP.NET MVC应用</a></li><li>2009-04-09 -- <a href="http://ofcss.com/2009/04/09/aspnetmvc-hands-on-labs-introduction.html" title="[翻译]ASP.NET MVC动手系列1-1：ASP.NET MVC概述">[翻译]ASP.NET MVC动手系列1-1：ASP.NET MVC概述</a></li><li>2009-07-08 -- <a href="http://ofcss.com/2009/07/08/asp-net-mvc-best-practices-part-4.html" title="ASP.NET MVC 最佳实践（四）">ASP.NET MVC 最佳实践（四）</a></li><li>2009-07-07 -- <a href="http://ofcss.com/2009/07/07/asp-net-mvc-best-practices-part-3.html" title="ASP.NET MVC 最佳实践（三）">ASP.NET MVC 最佳实践（三）</a></li><li>2009-07-01 -- <a href="http://ofcss.com/2009/07/01/asp-net-mvc-best-practices-part-2.html" title="ASP.NET MVC 最佳实践（二）">ASP.NET MVC 最佳实践（二）</a></li><li>2009-06-28 -- <a href="http://ofcss.com/2009/06/28/asp-net-mvc-best-practices-part-1.html" title="ASP.NET MVC 最佳实践（一）">ASP.NET MVC 最佳实践（一）</a></li><li>2011-03-14 -- <a href="http://ofcss.com/2011/03/14/browser-rendering-optimizer-translation-extra.html" title="对《优化浏览器渲染》的补充【译】">对《优化浏览器渲染》的补充【译】</a></li><li>2009-06-22 -- <a href="http://ofcss.com/2009/06/22/whatever-hover-pseudo-class-without-javascript.html" title="Whatever:hover &#8211; 无需javascript让IE支持丰富伪类">Whatever:hover &#8211; 无需javascript让IE支持丰富伪类</a></li><li>2009-04-30 -- <a href="http://ofcss.com/2009/04/30/solution-for-js-intellisense-error.html" title="VS2008 中 JS IntelliSense出错的解决">VS2008 中 JS IntelliSense出错的解决</a></li><li>2011-03-10 -- <a href="http://ofcss.com/2011/03/10/css-border-tricks-with-collapsed-boxes-translation.html" title="CSS边框实现&ldquo;无图化&rdquo;设计【译】">CSS边框实现&ldquo;无图化&rdquo;设计【译】</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ofcss.com/2009/04/09/aspnetmvc-hands-on-labs-create-application.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[翻译]ASP.NET MVC动手系列1-1：ASP.NET MVC概述</title>
		<link>http://ofcss.com/2009/04/09/aspnetmvc-hands-on-labs-introduction.html</link>
		<comments>http://ofcss.com/2009/04/09/aspnetmvc-hands-on-labs-introduction.html#comments</comments>
		<pubDate>Thu, 09 Apr 2009 14:41:35 +0000</pubDate>
		<dc:creator>小李刀刀</dc:creator>
				<category><![CDATA[所谓技术]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[Visual Studio]]></category>
		<category><![CDATA[动手实验]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://wukangrui.net/2009/04/09/aspnetmvc-hands-on-labs-introduction.html</guid>
		<description><![CDATA[MVC(Model View Controller) 架构模式通常分为三个主要部分： 模型（Models）：模型对象一般是在应用中实现逻辑域的部分。通常情况下，模型对象用于在数据库中取得和存储模型状态。 视图（Views）：视图是应用中显示用户界面（UI）的组件。典型状况下，用户界面是根据模型数据创建。比如一个产品表的编辑视图中可能包括基于当前产品对象状态的文本框、下拉列表以及单选、复选框等。 控制器（Controllers）：控制器是处理用户交互，操作对应模型、最后选择相应视图来渲染用户界面的组件。在一个MVC架构的应用中，视图只用于显示信息；控制器对用户的输入和交互行为进行处理和响应。 MVC模式可以帮助你将应用拆分的不同方面拆分以形成多层结构（输入逻辑、商业逻辑和用户界面逻辑等），并为这些不同的层提供宽松的耦合关系。这样你就能在开发过程中一次只将精力集中于实现其中的一个方面。除了在处理复杂事务的优势外，调试基于MVC模式的应用也比调试传统ASP.NET WEB应用程序更容易， 因此MVC模式鼓励使用测试驱动开发（TDD: Test-driven development）来创建应用程序。 ASP.NET MVC 框架为ASP.NET Web Forms开发人员提供了创建基于MVC的WEB应用的选择。ASP.NET MVC 框架是一个轻量级的、高可测试性的框架，它与基于Web Forms的应用程序一样，结合了现有的ASP.NET特性，例如母版页和基于用户（Membership-based）的认证等。 除此之外，MVC应用程序三个主要组件之间的宽耦合更方便进行多人并行开发。例如，一个开发人员开发试图，另一个开发人员开发逻辑控制器，与此同时还有一个开发人员在模型层进行商业逻辑开发。 目标 在这个动手实验室系列中，你将学习到： 认识和了解 ASP.NET MVC 框架； 创建一个 ASP.NET MVC 应用程序； 在创建 ASP.NET MVC 应用程序的过程中执行测试。 &#160; 系统需求 为了完成此实验，你必须具备以下的系统配置环境： Microsoft Visual Studio 2008 SP1 Microsoft ASP.NET MVC 1.0 Microsoft SQL 2005 or Microsoft SQL 2008 (体验版或更高版本) [...]]]></description>
			<content:encoded><![CDATA[<p>MVC(Model View Controller) 架构模式通常分为三个主要部分：</p>
<ul>
<li>模型（Models）：模型对象一般是在应用中实现逻辑域的部分。通常情况下，模型对象用于在数据库中取得和存储模型状态。</li>
<li>视图（Views）：视图是应用中显示用户界面（UI）的组件。典型状况下，用户界面是根据模型数据创建。比如一个产品表的编辑视图中可能包括基于当前产品对象状态的文本框、下拉列表以及单选、复选框等。</li>
<li>控制器（Controllers）：控制器是处理用户交互，操作对应模型、最后选择相应视图来渲染用户界面的组件。在一个MVC架构的应用中，视图只用于显示信息；控制器对用户的输入和交互行为进行处理和响应。</li>
</ul>
<p> <span id="more-442"></span>
<p>MVC模式可以帮助你将应用拆分的不同方面拆分以形成多层结构（输入逻辑、商业逻辑和用户界面逻辑等），并为这些不同的层提供宽松的耦合关系。这样你就能在开发过程中一次只将精力集中于实现其中的一个方面。除了在处理复杂事务的优势外，调试基于MVC模式的应用也比调试传统ASP.NET WEB应用程序更容易， 因此MVC模式鼓励使用测试驱动开发（TDD: Test-driven development）来创建应用程序。</p>
<p><strong>ASP.NET MVC</strong> 框架为ASP.NET Web Forms开发人员提供了创建基于MVC的WEB应用的选择。<strong>ASP.NET MVC</strong> 框架是一个轻量级的、高可测试性的框架，它与基于Web Forms的应用程序一样，结合了现有的ASP.NET特性，例如母版页和基于用户（Membership-based）的认证等。</p>
<p>除此之外，MVC应用程序三个主要组件之间的宽耦合更方便进行多人并行开发。例如，一个开发人员开发试图，另一个开发人员开发逻辑控制器，与此同时还有一个开发人员在模型层进行商业逻辑开发。</p>
<h3>目标</h3>
<p>在这个动手实验室系列中，你将学习到：</p>
<ul>
<li>认识和了解 ASP.NET MVC 框架；</li>
<li>创建一个 ASP.NET MVC 应用程序；</li>
<li>在创建 ASP.NET MVC 应用程序的过程中执行测试。</li>
</ul>
<p>&#160;</p>
<p> <a href="#" name="_Toc168302999"></a><a href="#" name="_Toc157870738"></a><br />
<h3>系统需求</h3>
<p>为了完成此实验，你必须具备以下的系统配置环境：</p>
<ul>
<li>Microsoft Visual Studio 2008 SP1</li>
<li>Microsoft ASP.NET MVC 1.0 </li>
<li>Microsoft SQL 2005 or Microsoft SQL 2008 (体验版或更高版本) </li>
<li>Adventure Works 示例数据库
<ul>
<li>Microsoft SQL 2005 下使用: <a href="http://www.codeplex.com/MSFTDBProdSamples/Release/ProjectReleases.aspx?ReleaseId=4004" target="_blank">AdventureWorksLT.msi</a>
<p><b>备注：</b> 该 msi 安装程序只是将示例数据库文件拷贝到你的文件系统中；你还需要手动在SQL SERVER服务器中附加该数据库。更多信息，请参考 <a href="http://technet.microsoft.com/zh-cn/library/ms190209.aspx" target="_blank">如何：在SQL Server Management Studio 中附加数据库</a>.            <br /><i>Vista 用户请注意：</i> 确认将数据库文件安装到 “C:Program Files”以外的目录， 因为该文件夹具有额外的权限设置，可能会由于文件的只读属性造成你无法在工程文件中进行保存。</p>
</li>
<li>Microsoft SQL 2008 下使用: <a href="http://www.codeplex.com/MSFTDBProdSamples/Release/ProjectReleases.aspx?ReleaseId=18407">AdventureWorks 2008 sample databases</a>
<p><b>备注：</b> 该 msi 安装程序只是将示例数据库拷贝到你的文件系统中；不过，你只需要用到 <strong>AdventureWorksLT</strong> 数据库。</p>
<p>&#160;</p>
</li>
</ul>
</li>
</ul>
<h3>安装</h3>
<p>本实验所需的所有必备组件可以用依赖性检测工具来检验。要确定所有项目都已正确配置，请执行以下步骤：</p>
<p>备注：要执行以下安装步骤，你需要在以管理员身份运行的命令提示窗口（cmd.exe）中运行所有脚本。</p>
<ol>
<li>如果以前从没有进行过依赖性检测，请运行依赖性检测工具。要进行检测，运行 CheckDepenencies.cmd 脚本，该脚本位于 <strong>%TrainingKitInstallation%LabsaspNetMvcSetup</strong> 目录。根据向导提示扫描并安装任何缺少的组件（安装后，如果需要可以重新扫描）。
<p>提示：为了方便起见，在这个实验中你将用到的绝大部分代码会安装在Visual Studio 的 代码片段（code snippets）中。CheckDependencies.cmd 结束时会自动加载 Visual Studio 安装管理器来安装代码片段。</p>
</li>
</ol>
<h3>练习</h3>
<p>这个动手实验中包含以下练习：</p>
<ol>
<li>创建 ASP.NET MVC 应用程序 </li>
<li>开发和完善 ASP.NET MVC 应用程序 </li>
<li>测试 ASP.NET MVC 应用程序</li>
</ol>
<p>完成整个实验预计需要时间: <b>90分钟。</b></p>
<p>补充说明:</p>
<p><a href="#" name="_Toc166647553"></a><a href="#" name="_Toc172462715"></a><a href="#" name="_Toc182141329"></a>每个练习中都包含一个起始解决方案，起始解决方案中缺少的代码将在练习工程中完成。因此如果你直接运行起始解决方案，将不能正常执行。    <br />在每个练习中你还可以找到一个 End 目录，其中包括了在整个练习结束时你应该得到的解决方案。在练习过程中如果你需要额外的帮助，可以参考该解决方案。</p>
<p>（文本翻译自 ASP.NET MVC Training Kit，下载地址：<a title="http://www.microsoft.com/downloads/details.aspx?FamilyID=1E0BE0B2-910A-4676-9F3A-41E4D9C0FC08&amp;displaylang=en" href="http://www.microsoft.com/downloads/details.aspx?FamilyID=1E0BE0B2-910A-4676-9F3A-41E4D9C0FC08&amp;displaylang=en">http://www.microsoft.com/downloads/details.aspx?FamilyID=1E0BE0B2-910A-4676-9F3A-41E4D9C0FC08&amp;displaylang=en</a>）</p>
<h3  class="related_post_title">相关日志</h3><ul class="related_post"><li>2009-04-13 -- <a href="http://ofcss.com/2009/04/13/aspnetmvc-hands-on-labs-develop-application.html" title="[翻译]ASP.NET MVC动手实验1-3：开发ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-3：开发ASP.NET MVC应用</a></li><li>2009-04-09 -- <a href="http://ofcss.com/2009/04/09/aspnetmvc-hands-on-labs-create-application.html" title="[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用">[翻译]ASP.NET MVC动手实验1-2：创建ASP.NET MVC应用</a></li><li>2009-07-08 -- <a href="http://ofcss.com/2009/07/08/asp-net-mvc-best-practices-part-4.html" title="ASP.NET MVC 最佳实践（四）">ASP.NET MVC 最佳实践（四）</a></li><li>2009-07-07 -- <a href="http://ofcss.com/2009/07/07/asp-net-mvc-best-practices-part-3.html" title="ASP.NET MVC 最佳实践（三）">ASP.NET MVC 最佳实践（三）</a></li><li>2009-07-01 -- <a href="http://ofcss.com/2009/07/01/asp-net-mvc-best-practices-part-2.html" title="ASP.NET MVC 最佳实践（二）">ASP.NET MVC 最佳实践（二）</a></li><li>2009-06-28 -- <a href="http://ofcss.com/2009/06/28/asp-net-mvc-best-practices-part-1.html" title="ASP.NET MVC 最佳实践（一）">ASP.NET MVC 最佳实践（一）</a></li><li>2009-04-30 -- <a href="http://ofcss.com/2009/04/30/solution-for-js-intellisense-error.html" title="VS2008 中 JS IntelliSense出错的解决">VS2008 中 JS IntelliSense出错的解决</a></li><li>2011-03-14 -- <a href="http://ofcss.com/2011/03/14/browser-rendering-optimizer-translation-extra.html" title="对《优化浏览器渲染》的补充【译】">对《优化浏览器渲染》的补充【译】</a></li><li>2011-03-10 -- <a href="http://ofcss.com/2011/03/10/css-border-tricks-with-collapsed-boxes-translation.html" title="CSS边框实现&ldquo;无图化&rdquo;设计【译】">CSS边框实现&ldquo;无图化&rdquo;设计【译】</a></li><li>2010-10-31 -- <a href="http://ofcss.com/2010/10/31/prevent-a-float-drop-in-ie6-translation.html" title="CSS技巧:如何避免IE6中的&quot;浮动下坠&quot;【译】">CSS技巧:如何避免IE6中的&quot;浮动下坠&quot;【译】</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ofcss.com/2009/04/09/aspnetmvc-hands-on-labs-introduction.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

