<?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; 开发</title>
	<atom:link href="http://ofcss.com/tags/dev/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>PHP 5.3.0 发布</title>
		<link>http://ofcss.com/2009/07/05/php-5-3-0-release-new-feature.html</link>
		<comments>http://ofcss.com/2009/07/05/php-5-3-0-release-new-feature.html#comments</comments>
		<pubDate>Sat, 04 Jul 2009 19:33:30 +0000</pubDate>
		<dc:creator>小李刀刀</dc:creator>
				<category><![CDATA[所谓技术]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[开发]]></category>
		<category><![CDATA[编程]]></category>

		<guid isPermaLink="false">http://wukangrui.net/2009/07/05/php-5-3-0-release-new-feature.html</guid>
		<description><![CDATA[如今PHP 5.3.0也像ASP.NET一样，引入了命名空间、延迟绑定、匿名函数、Lambda表达式等先进特性，可见编程语言与平台无关性在未来将更加凸显，而混合编程的正确性和先进性也将不断得到体现。封闭自己，拒绝变化的产品和思想，在开发领域只有死路一条。]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.php.net/" rel="external" target="_blank">PHP 官方网站</a> 6月30日放出了<a href="http://www.php.net/archive/2009.php#id2009-06-30-1" rel="external" target="_blank">PHP 5.3.0 正式发布的消息</a>，该版本是PHP 5.x系列的一个重要里程碑。根据 PHP 官方网站7月3日更新的 <a href="http://cn2.php.net/manual/en/migration53.new-features.php" rel="external" target="_blank">PHP 5.3.0 新特性</a> 介绍，PHP 5.3.0 主要包括以下新增特性或功能：</p>
<p> <span id="more-845"></span>
</p>
<ul>
<li>支持<a href="http://php.net/namespaces" rel="external" target="_blank">命名空间</a> </li>
<li>支持<a href="http://cn2.php.net/manual/en/language.oop5.late-static-bindings.php" rel="external" target="_blank">延迟静态绑定</a>技术 </li>
<li>支持<a href="http://cn2.php.net/manual/en/control-structures.goto.php" rel="external" target="_blank">跳转标签</a>（受限制的goto） </li>
<li>支持<a href="http://cn2.php.net/manual/en/functions.anonymous.php" rel="external" target="_blank">闭包</a>（Lambda表达式和匿名函数） </li>
<li>新增两个魔法函数，<a href="http://cn2.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.methods" rel="external" target="_blank">__callStatic</a> 和 <a href="http://cn2.php.net/manual/en/language.oop5.magic.php#language.oop5.magic.invoke" rel="external" target="_blank">__invoke</a> </li>
<li>新增 <a href="http://cn2.php.net/manual/en/language.types.string.php#language.types.string.syntax.nowdoc" rel="external" target="_blank">Nowdoc</a> 语法支持，与 <a href="http://cn2.php.net/manual/en/language.types.string.php#language.types.string.syntax.heredoc" rel="external" target="_blank">Heredoc</a> 语法相同但是带有单引号 </li>
<li>可以在静态变量和类成员、类构造函数中使用 Heredoc 语法 </li>
<li>Heredoc 可以用双引号定义，以便与 Nowdoc 的单引号区别 </li>
<li><a href="http://cn2.php.net/manual/en/language.constants.syntax.php" rel="external" target="_blank">构造函数</a>可以在类之外用 <em>const</em> 关键词进行定义 </li>
<li>增加了<a href="http://cn2.php.net/manual/en/language.operators.comparison.php#language.operators.comparison.ternary" rel="external" target="_blank">条件操作符</a>的简短形式 ?: (例如 a = condition ? true : false） </li>
<li>200 到 399 的状态码在HTTP数据流容器被认为是成功 </li>
<li>允许动态访问静态成员 </li>
<li>允许对<a href="http://cn2.php.net/manual/en/language.operators.comparison.php#language.operators.comparison.ternary" rel="external" target="_blank">异常</a>进行嵌套 </li>
<li>增加并且默认启用垃圾回收机制 </li>
</ul>
<p>此外，针对Windows版本的改变有：</p>
<ul>
<li>不再支持Windows98,ME和NT4，最低支持Windows 2000 </li>
<li>Windows 二进制版本针对 i586 或更高版本编译，不再支持 i386和i486 </li>
<li>对 Windows 系统上的 64位 PHP 提供支持（实验性的） </li>
<li>支持Visual C++ 9（VC9）编译，可以使用 Visual Studio 2008。 </li>
<li><a href="http://cn2.php.net/manual/en/ref.pdo-oci.php" rel="external" target="_blank">PDO_OCI</a> 的 php_pdo_oci8.dll 库（用于Oracle 8的客户端类库）不再构建，替代它的是 php_pdo_oci.dll（去掉了“8”），用于 Oracle 10 或者 11。与其他版本的数据库连接继续支持。 </li>
<li>针对 <a href="http://cn2.php.net/manual/en/book.oci8.php" rel="external" target="_blank">OCI8</a> 的扩展，除了php_oci8.dll之外增加了一个php_oci8_11g.dll，但是不能同时启用。php_oci8.dll与Oracle 10.2客户端类库结合使用，而php_oci8_11g.dll 和 Oracle 11客户端类库结合使用。与其他版本数据库的连接继续支持。 </li>
</ul>
<p>Windows版本新增加了对下列函数的支持：</p>
<ul>
<li><a href="http://cn2.php.net/function.checkdnsrr.php">checkdnsrr()</a> </li>
<li>d<a href="http://cn2.php.net/function.dns-get-record.php">ns_get_record()</a> </li>
<li><a href="http://cn2.php.net/function.fnmatch.php">fnmatch()</a> </li>
<li><a href="http://cn2.php.net/function.getmxrr.php">getmxrr()</a> </li>
<li><a href="http://cn2.php.net/function.getopt.php">getopt()</a> </li>
<li><a href="http://cn2.php.net/function.imagecolorclosesthwb.php">imagecolorclosesthwb()</a> </li>
<li><a href="http://cn2.php.net/function.inet-ntop.php">inet_ntop()</a> </li>
<li><a href="http://cn2.php.net/function.inet-pton.php">inet_pton()</a> </li>
<li><a href="http://cn2.php.net/function.link.php">link()</a> </li>
<li><a href="http://cn2.php.net/function.linkinfo.php">linkinfo()</a> </li>
<li><a href="http://cn2.php.net/function.mcrypt-create-iv.php">mcrypt_create_iv()</a> </li>
<li><a href="http://cn2.php.net/function.readlink.php">readlink()</a> </li>
<li><a href="http://cn2.php.net/function.socket-create-pair.php">socket_create_pair()</a> &#8211; 这个函数以前就在Windows中支持，但是由于在PHP 4.3.0中的一个bug而被禁用 </li>
<li><a href="http://cn2.php.net/function.stream-socket-pair.php">stream_socket_pair()</a> </li>
<li><a href="http://cn2.php.net/function.symlink.php">symlink()</a> </li>
<li><a href="http://cn2.php.net/function.time-nanosleep.php">time_nanosleep()</a> </li>
<li><a href="http://cn2.php.net/function.time-sleep-until.php">time_sleep_until()</a> </li>
</ul>
<p>除了上述改变外，Windows版本还有一些其它提升性能或者增加兼容性的改进，而最为重要的则是一条针对Windows的说明：</p>
<p>在windows下采用ISAPI方式运行PHP已经被遗弃，采用改进的FastCGI SAPI模块来代替。我在<a href="http://wukangrui.net/2008/06/23/fastcgi-for-php-in-iis.html" rel="external" target="_blank">2008年6月23日的日志</a>中曾经笑称“PHP成为IIS‘一等公民’”，那是只是从微软IIS团队官方发布PHP的FastCGI模块，以及微软和Zend的合作而对PHP在Windows平台上的使用做了最乐观的展望，而后来微软在IIS7以后的版本内置FastCGI模块，甚至在云服务中也内置FastCGI支持，则更说明了PHP与Windows的联姻将继续增强。可惜的是直到Windows7发布之后，网上的绝大部分教程依然在教新手采用ISAPI方式运行PHP，甚至是采用PHP4的安装方式。甚至还有人专门跑到我的空间里叫嚣在Windows下运行PHP是如何如何。开源社区对Windows平台的妖魔化，至今影响深远。正是由于拒绝导致了他们对Windows、ASP.NET、C#的不了解，甚至直至今日还死抱着Windows比Linux慢、不如Linux安全之类的陈旧观念。</p>
<p>如今PHP 5.3.0也像ASP.NET一样，引入了命名空间、延迟绑定、匿名函数、Lambda表达式等先进特性，可见编程语言与平台无关性在未来将更加凸显，而混合编程的正确性和先进性也将不断得到体现。封闭自己，拒绝变化的产品和思想，在开发领域只有死路一条。</p>
<h3  class="related_post_title">相关日志</h3><ul class="related_post"><li>2008-06-04 -- <a href="http://ofcss.com/2008/06/04/unix-timestamp-in-asp.html" title="在ASP中实现UNIX时间戳">在ASP中实现UNIX时间戳</a></li><li>2008-05-23 -- <a href="http://ofcss.com/2008/05/23/disadvantages-of-discuz-ucenter.html" title="给UCenter的拥蹩们泼点冷水">给UCenter的拥蹩们泼点冷水</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-06-08 -- <a href="http://ofcss.com/2009/06/08/using-fastcgi-to-host-php-applications-on-iis-7x.html" title="在 IIS 7.x 中用 FastCGI 运行 PHP">在 IIS 7.x 中用 FastCGI 运行 PHP</a></li><li>2008-06-23 -- <a href="http://ofcss.com/2008/06/23/fastcgi-for-php-in-iis.html" title="微软官方FastCGI，PHP成为IIS“一等公民”">微软官方FastCGI，PHP成为IIS“一等公民”</a></li><li>2008-06-22 -- <a href="http://ofcss.com/2008/06/22/api-bug-in-powereasy-siteweaver-part2.html" title="动易SW中的一个严重但不影响使用的bug（二）">动易SW中的一个严重但不影响使用的bug（二）</a></li><li>2008-06-22 -- <a href="http://ofcss.com/2008/06/22/thinking-about-html-page-creating.html" title="静态页面生成的思考">静态页面生成的思考</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ofcss.com/2009/07/05/php-5-3-0-release-new-feature.html/feed</wfw:commentRss>
		<slash:comments>0</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>动易SW中的一个严重但不影响使用的bug（二）</title>
		<link>http://ofcss.com/2008/06/22/api-bug-in-powereasy-siteweaver-part2.html</link>
		<comments>http://ofcss.com/2008/06/22/api-bug-in-powereasy-siteweaver-part2.html#comments</comments>
		<pubDate>Sun, 22 Jun 2008 18:24:00 +0000</pubDate>
		<dc:creator>小李刀刀</dc:creator>
				<category><![CDATA[所谓技术]]></category>
		<category><![CDATA[ASP]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[动易]]></category>
		<category><![CDATA[开发]]></category>

		<guid isPermaLink="false">http://wukangrui.net/?p=282</guid>
		<description><![CDATA[　　上次分析出来了Bug的问题所在，是因为selectSingleNode(strNodeName)不能取到要取的元素，但是为什么这么大的Bug没有出现500错误呢？否则的话，这么大的一个bug不要说是来到用户手上，在开发人员手里就已经被发现了。 　　这次继续分析这个Bug。在新版本的API_Function.asp这个文件中，selectSingleNode这个函数一共用到了5次，有两次是在SendPost函数里，在很早的版本里那两个地方就用的是selectSingleNode，因为那里传递的参数用的是“//status”和“//message”，是正确的XPath，因此不用考虑那里了。此外的三处，代码如下： '************************************************** '函数名：getNodeText '作 用：获取XML文件中指定节点的文本 '参 数：strNodeName ----节点名称 '返回值：解析出来的文本值， '************************************************** Function getNodeText(strNodeName) If IsNull(strNodeName) Or IsEmpty(strNodeName) Or strNodeName = "" Then Exit Function If IsNode(strNodeName) Then getNodeText = sMyXmlDoc.documentElement.selectSingleNode(strNodeName).Text Else getNodeText = "" End If End Function '************************************************** '函数名：setNodeText '作 用：设置XML文件中指定节点的文本 '参 数：strNodeName ----节点名称 '　　　　strNodeText ----要设置的文本 '返回值：0 = 设置成功; 否则返回Err.Description '************************************************** Function setNodeText(strNodeName, strNodeText) [...]]]></description>
			<content:encoded><![CDATA[<p>　　<a href="http://blog.oophome.net/?id=279" target="_blank">上次</a>分析出来了Bug的问题所在，是因为selectSingleNode(strNodeName)不能取到要取的元素，但是为什么这么大的Bug没有出现500错误呢？否则的话，这么大的一个bug不要说是来到用户手上，在开发人员手里就已经被发现了。</p>
<p>　　这次继续分析这个Bug。在新版本的API_Function.asp这个文件中，selectSingleNode这个函数一共用到了5次，有两次是在SendPost函数里，在很早的版本里那两个地方就用的是selectSingleNode，因为那里传递的参数用的是“//status”和“//message”，是正确的XPath，因此不用考虑那里了。此外的三处，代码如下：<span id="more-282"></span></p>
<pre lang="ASP">'**************************************************
'函数名：getNodeText
'作  用：获取XML文件中指定节点的文本
'参  数：strNodeName   ----节点名称
'返回值：解析出来的文本值，
'**************************************************
Function getNodeText(strNodeName)
    If IsNull(strNodeName) Or IsEmpty(strNodeName) Or strNodeName = "" Then Exit Function
    If IsNode(strNodeName) Then
        getNodeText = sMyXmlDoc.documentElement.selectSingleNode(strNodeName).Text
    Else
        getNodeText = ""
    End If
End Function  

'**************************************************
'函数名：setNodeText
'作  用：设置XML文件中指定节点的文本
'参  数：strNodeName   ----节点名称
'　　　　strNodeText   ----要设置的文本
'返回值：0 = 设置成功; 否则返回Err.Description
'**************************************************
Function setNodeText(strNodeName, strNodeText)
    If IsNull(strNodeText) Or IsEmpty(strNodeText) Or strNodeText = "" Then Exit Function
    If IsNull(strNodeName) Or IsEmpty(strNodeName) Or strNodeName = "" Then Exit Function
    If IsNode(strNodeName) Then sMyXmlDoc.documentElement.selectSingleNode(strNodeName).Text = strNodeText
End Function  

'**************************************************
'函数名：IsNode
'作  用：检查一个Node是否存在且文本不为空
'参  数：strNodeName   ----节点名称
'返回值：True or False
'**************************************************
Function IsNode(strNodeName)
    IsNode = False
    If strNodeName = "" Then Exit Function
    If sMyXmlDoc.documentElement.selectSingleNode(strNodeName) Is Nothing Then
        IsNode = False
    Else
        IsNode = True
    End If
End Function</pre>
<p>　　我们来看，为什么设置message的值不会成功并且不报错呢？原因就在于setNodeText这个函数的最后一句：</p>
<div class="codeText">
<div class="codeHead">ASP/Visual Basic代码</div>
<ol class="dp-vb">
<li class="alt"><span><span class="keyword">If</span><span> IsNode(strNodeName) </span><span class="keyword">Then</span><span> sMyXmlDoc.documentElement.selectSingleNode(strNodeName).Text = strNodeText  </span></span></li>
</ol>
</div>
<p>　　IsNode这个函数，从函数的注释（还好这个没改）可以看出，作用是“检测一个元素是否存在<span style="color: #ff0000;">且文本不为空</span>”，这个函数本来的作用是用于检查传递的数据包中的“自定义元素”和“扩展元素”的，因为各个接口对标准的支持程度不同，因此在获取数据的时候，有的元素可能只是穿了空值过来，那我们就没有必要对该元素进行处理了，所以要用IsNode来检查一下。但是在setNodeText这个函数里没有调用过IsNode检查。就算调用了，按照以前的方式，一定会取到“message”元素的默认值，从而返回True。</p>
<p>　　在新版本中，由于采用了selectSingleNode来取“message”已经取不到了，自然，IsNode这个函数在检查到message的时候，必然返回空值，因为 sMyXmlDoc.documentElement.selectSingleNode Is Nothing这个判断为真了，所以会返回False。于是，sMyXmlDoc.documentElement.selectSingleNode(“message”).Text 这个语句就不会执行，也就不会引发500错误了。</p>
<p>　　做个假设，如果在修改了取元素的方式之后，没有给setNodeText和getNodeText加上IsNode判断，则必然引发500错误。或者，没有修改过IsNode这个函数，则仍然会返回True，然后引发500错误。正好是加上了判断，于是所有对message元素的值的读写都被忽略了，默认值“操作已成功”就这样被原封不动地回发给所有请求，而响应包中的用户数据元素也一样。</p>
<p>　　下面是纠正bug的代码：</p>
<div class="codeText">
<div class="codeHead">ASP/Visual Basic代码</div>
<ol class="dp-vb">
<li class="alt"><span><span class="comment">&#8216;************************************************** </span><span>  </span></span></li>
<li><span class="comment">&#8216;函数名：getNodeText </span><span>  </span></li>
<li class="alt"><span class="comment">&#8216;作  用：获取XML文件中指定节点的文本 </span><span>  </span></li>
<li><span class="comment">&#8216;参  数：strNodeName   &#8212;-节点名称 </span><span>  </span></li>
<li class="alt"><span class="comment">&#8216;返回值：解析出来的文本值， </span><span>  </span></li>
<li><span class="comment">&#8216;************************************************** </span><span>  </span></li>
<li class="alt"><span class="keyword">Function</span><span> getNodeText(strNodeName)   </span></li>
<li><span>    </span><span class="keyword">If</span><span> IsNull(strNodeName) </span><span class="keyword">Or</span><span> IsEmpty(strNodeName) </span><span class="keyword">Or</span><span> strNodeName = </span><span class="string">“”</span><span> </span><span class="keyword">Then</span><span> </span><span class="keyword">Exit</span><span> </span><span class="keyword">Function</span><span>  </span></li>
<li class="alt"><span>    </span><span class="keyword">If</span><span> IsNode(strNodeName) </span><span class="keyword">Then</span><span>  </span></li>
<li><span>        getNodeText = sMyXmlDoc.documentElement.<span style="background-color: #ffff00">getElementsByTagName(strNodeName).Item(0)</span>.Text   </span></li>
<li class="alt"><span>    </span><span class="keyword">Else</span><span>  </span></li>
<li><span>        getNodeText = </span><span class="string">“”</span><span>  </span></li>
<li class="alt"><span>    </span><span class="keyword">End</span><span> </span><span class="keyword">If</span><span>  </span></li>
<li><span class="keyword">End</span><span> </span><span class="keyword">Function</span><span>  </span></li>
<li class="alt"><span>  </span></li>
<li><span class="comment">&#8216;************************************************** </span><span>  </span></li>
<li class="alt"><span class="comment">&#8216;函数名：setNodeText </span><span>  </span></li>
<li><span class="comment">&#8216;作  用：设置XML文件中指定节点的文本 </span><span>  </span></li>
<li class="alt"><span class="comment">&#8216;参  数：strNodeName   &#8212;-节点名称 </span><span>  </span></li>
<li><span class="comment">&#8216;　　　　strNodeText   &#8212;-要设置的文本 </span><span>  </span></li>
<li class="alt"><span class="comment">&#8216;返回值：0 = 设置成功; 否则返回Err.Description </span><span>  </span></li>
<li><span class="comment">&#8216;************************************************** </span><span>  </span></li>
<li class="alt"><span class="keyword">Function</span><span> setNodeText(strNodeName, strNodeText)   </span></li>
<li><span>    </span><span class="keyword">If</span><span> IsNull(strNodeText) </span><span class="keyword">Or</span><span> IsEmpty(strNodeText) </span><span class="keyword">Or</span><span> strNodeText = </span><span class="string">“”</span><span> </span><span class="keyword">Then</span><span> </span><span class="keyword">Exit</span><span> </span><span class="keyword">Function</span><span>  </span></li>
<li class="alt"><span>    </span><span class="keyword">If</span><span> IsNull(strNodeName) </span><span class="keyword">Or</span><span> IsEmpty(strNodeName) </span><span class="keyword">Or</span><span> strNodeName = </span><span class="string">“”</span><span> </span><span class="keyword">Then</span><span> </span><span class="keyword">Exit</span><span> </span><span class="keyword">Function</span><span>  </span></li>
<li><span>    </span><span class="keyword">If</span><span> IsNode(strNodeName) </span><span class="keyword">Then</span><span> sMyXmlDoc.documentElement.<span style="background-color: #ffff00">getElementsByTagName(strNodeName).Item(0)</span>.Text = strNodeText   </span></li>
<li><span class="keyword">End</span><span> </span><span class="keyword">Function</span><span>  </span></li>
<li class="alt"><span>  </span></li>
<li><span class="comment">&#8216;************************************************** </span><span>  </span></li>
<li class="alt"><span class="comment">&#8216;函数名：IsNode </span><span>  </span></li>
<li><span class="comment">&#8216;作  用：检查一个Node是否存在且文本不为空 </span><span>  </span></li>
<li class="alt"><span class="comment">&#8216;参  数：strNodeName   &#8212;-节点名称 </span><span>  </span></li>
<li><span class="comment">&#8216;返回值：True or False </span><span>  </span></li>
<li class="alt"><span class="comment">&#8216;************************************************** </span><span>  </span></li>
<li><span class="keyword">Function</span><span> IsNode(strNodeName)   </span></li>
<li class="alt"><span>    IsNode = </span><span class="keyword">False</span><span>  </span></li>
<li><span>    </span><span class="keyword">If</span><span> strNodeName = </span><span class="string">“”</span><span> </span><span class="keyword">Then</span><span> </span><span class="keyword">Exit</span><span> </span><span class="keyword">Function</span><span>  </span></li>
<li class="alt"><span>    </span><span class="keyword">If</span><span> sMyXmlDoc.documentElement.<span style="background-color: #ffff00">getElementsByTagName(strNodeName).Item(0)</span> </span><span class="keyword">Is</span><span> </span><span class="keyword">Nothing</span><span style="background-color: #ffff00"> Or IsEmpty(sMyXmlDoc.documentElement.getElementByTagName(strNodeName).Item(0).Text) </span><span class="keyword">Then</span><span>  </span></li>
<li><span>        IsNode = </span><span class="keyword">False</span><span>  </span></li>
<li class="alt"><span>    </span><span class="keyword">Else</span><span>  </span></li>
<li><span>        IsNode = </span><span class="keyword">True</span><span>  </span></li>
<li class="alt"><span>    </span><span class="keyword">End</span><span> </span><span class="keyword">If</span><span>  </span></li>
<li><span class="keyword">End</span><span> </span><span class="keyword">Function</span><span>  </span></li>
</ol>
</div>
<p>第二种改法：用selectSingleNode的方法，代码如下</p>
<div class="codeText">
<div class="codeHead">ASP/Visual Basic代码</div>
<ol class="dp-vb">
<li class="alt"><span><span class="comment">&#8216;************************************************** </span><span>  </span></span></li>
<li><span class="comment">&#8216;函数名：getNodeText </span><span>  </span></li>
<li class="alt"><span class="comment">&#8216;作  用：获取XML文件中指定节点的文本 </span><span>  </span></li>
<li><span class="comment">&#8216;参  数：strNodeName   &#8212;-节点名称 </span><span>  </span></li>
<li class="alt"><span class="comment">&#8216;返回值：解析出来的文本值， </span><span>  </span></li>
<li><span class="comment">&#8216;************************************************** </span><span>  </span></li>
<li class="alt"><span class="keyword">Function</span><span> getNodeText(strNodeName)   </span></li>
<li><span>    </span><span class="keyword">If</span><span> IsNull(strNodeName) </span><span class="keyword">Or</span><span> IsEmpty(strNodeName) </span><span class="keyword">Or</span><span> strNodeName = </span><span class="string">“”</span><span> </span><span class="keyword">Then</span><span> </span><span class="keyword">Exit</span><span> </span><span class="keyword">Function</span><span>  </span></li>
<li class="alt"><span>    </span><span class="keyword">If</span><span> IsNode(strNodeName) </span><span class="keyword">Then</span><span>  </span></li>
<li><span>        getNodeText = sMyXmlDoc.documentElement.selectSingleNode(</span><span class="string">“//”</span><span>&amp;strNodeName).Text   </span></li>
<li class="alt"><span>    </span><span class="keyword">Else</span><span>  </span></li>
<li><span>        getNodeText = </span><span class="string">“”</span><span>  </span></li>
<li class="alt"><span>    </span><span class="keyword">End</span><span> </span><span class="keyword">If</span><span>  </span></li>
<li><span class="keyword">End</span><span> </span><span class="keyword">Function</span><span>  </span></li>
<li class="alt"><span>  </span></li>
<li><span class="comment">&#8216;************************************************** </span><span>  </span></li>
<li class="alt"><span class="comment">&#8216;函数名：setNodeText </span><span>  </span></li>
<li><span class="comment">&#8216;作  用：设置XML文件中指定节点的文本 </span><span>  </span></li>
<li class="alt"><span class="comment">&#8216;参  数：strNodeName   &#8212;-节点名称 </span><span>  </span></li>
<li><span class="comment">&#8216;　　　　strNodeText   &#8212;-要设置的文本 </span><span>  </span></li>
<li class="alt"><span class="comment">&#8216;返回值：0 = 设置成功; 否则返回Err.Description </span><span>  </span></li>
<li><span class="comment">&#8216;************************************************** </span><span>  </span></li>
<li class="alt"><span class="keyword">Function</span><span> setNodeText(strNodeName, strNodeText)   </span></li>
<li><span>    </span><span class="keyword">If</span><span> IsNull(strNodeText) </span><span class="keyword">Or</span><span> IsEmpty(strNodeText) </span><span class="keyword">Or</span><span> strNodeText = </span><span class="string">“”</span><span> </span><span class="keyword">Then</span><span> </span><span class="keyword">Exit</span><span> </span><span class="keyword">Function</span><span>  </span></li>
<li class="alt"><span>    </span><span class="keyword">If</span><span> IsNull(strNodeName) </span><span class="keyword">Or</span><span> IsEmpty(strNodeName) </span><span class="keyword">Or</span><span> strNodeName = </span><span class="string">“”</span><span> </span><span class="keyword">Then</span><span> </span><span class="keyword">Exit</span><span> </span><span class="keyword">Function</span><span>  </span></li>
<li><span>    </span><span class="keyword">If</span><span> IsNode(strNodeName) </span><span class="keyword">Then</span><span> sMyXmlDoc.documentElement.selectSingleNode(</span><span class="string">“//”</span><span>&amp;strNodeName).Text = strNodeText   </span></li>
<li class="alt"><span class="keyword">End</span><span> </span><span class="keyword">Function</span><span>  </span></li>
<li><span>  </span></li>
<li class="alt"><span class="comment">&#8216;************************************************** </span><span>  </span></li>
<li><span class="comment">&#8216;函数名：IsNode </span><span>  </span></li>
<li class="alt"><span class="comment">&#8216;作  用：检查一个Node是否存在且文本不为空 </span><span>  </span></li>
<li><span class="comment">&#8216;参  数：strNodeName   &#8212;-节点名称 </span><span>  </span></li>
<li class="alt"><span class="comment">&#8216;返回值：True or False </span><span>  </span></li>
<li><span class="comment">&#8216;************************************************** </span><span>  </span></li>
<li class="alt"><span class="keyword">Function</span><span> IsNode(strNodeName)   </span></li>
<li><span>    IsNode = </span><span class="keyword">False</span><span>  </span></li>
<li class="alt"><span>    </span><span class="keyword">If</span><span> strNodeName = </span><span class="string">“”</span><span> </span><span class="keyword">Then</span><span> </span><span class="keyword">Exit</span><span> </span><span class="keyword">Function</span><span>  </span></li>
<li><span>    </span><span class="keyword">If</span><span> sMyXmlDoc.documentElement.selectSingleNode(</span><span class="string">“//”</span><span>&amp;strNodeName) </span><span class="keyword">Is</span><span> </span><span class="keyword">Nothing</span><span> </span><span class="keyword">Or</span><span> IsEmpty(sMyXmlDoc.documentElement.selectSingleNode(</span><span class="string">“//”</span><span>&amp;strNodeName).Text) </span><span class="keyword">Then</span><span>  </span></li>
<li class="alt"><span>        IsNode = </span><span class="keyword">False</span><span>  </span></li>
<li><span>    </span><span class="keyword">Else</span><span>  </span></li>
<li class="alt"><span>        IsNode = </span><span class="keyword">True</span><span>  </span></li>
<li><span>    </span><span class="keyword">End</span><span> </span><span class="keyword">If</span><span>  </span></li>
<li class="alt"><span class="keyword">End</span><span> </span><span class="keyword">Function</span><span>  </span></li>
</ol>
</div>
<p>　　这样就能充分利用selectSingleNode的简洁了，但是还要注意哦，由于新版本的createXmlDom不再是自动生成支持的最高版本的xmldom对象，而是生成默认版本（系统默认版本一般都是3.0以下），而低于4.0的版本中，selectSingleNode对XPath的支持是有问题的，不支持带函数的XPath，所以还要小心！</p>
<h3  class="related_post_title">相关日志</h3><ul class="related_post"><li>2008-06-18 -- <a href="http://ofcss.com/2008/06/18/api-bug-in-powereasy-siteweaver-part1.html" title="动易SW中的一个严重但不影响使用的bug(一)">动易SW中的一个严重但不影响使用的bug(一)</a></li><li>2008-05-23 -- <a href="http://ofcss.com/2008/05/23/disadvantages-of-discuz-ucenter.html" title="给UCenter的拥蹩们泼点冷水">给UCenter的拥蹩们泼点冷水</a></li><li>2008-06-22 -- <a href="http://ofcss.com/2008/06/22/thinking-about-html-page-creating.html" title="静态页面生成的思考">静态页面生成的思考</a></li><li>2008-06-04 -- <a href="http://ofcss.com/2008/06/04/unix-timestamp-in-asp.html" title="在ASP中实现UNIX时间戳">在ASP中实现UNIX时间戳</a></li><li>2007-01-30 -- <a href="http://ofcss.com/2007/01/30/new-thinking-about-application-intergration.html" title="整合开发的新思路">整合开发的新思路</a></li><li>2006-04-12 -- <a href="http://ofcss.com/2006/04/12/innerhtml-can-not-be-excuted.html" title="用JavaScript动态输出的JS脚本不能执行">用JavaScript动态输出的JS脚本不能执行</a></li><li>2010-10-30 -- <a href="http://ofcss.com/2010/10/30/bfc-element-margin-bug-in-webkit.html" title="webkit中BFC元素临近浮动元素时的边距bug">webkit中BFC元素临近浮动元素时的边距bug</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-05 -- <a href="http://ofcss.com/2009/07/05/php-5-3-0-release-new-feature.html" title="PHP 5.3.0 发布">PHP 5.3.0 发布</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ofcss.com/2008/06/22/api-bug-in-powereasy-siteweaver-part2.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>静态页面生成的思考</title>
		<link>http://ofcss.com/2008/06/22/thinking-about-html-page-creating.html</link>
		<comments>http://ofcss.com/2008/06/22/thinking-about-html-page-creating.html#comments</comments>
		<pubDate>Sun, 22 Jun 2008 10:24:00 +0000</pubDate>
		<dc:creator>小李刀刀</dc:creator>
				<category><![CDATA[所谓技术]]></category>
		<category><![CDATA[动易]]></category>
		<category><![CDATA[开发]]></category>

		<guid isPermaLink="false">http://wukangrui.net/?p=280</guid>
		<description><![CDATA[　　现在的网站管理系统都喜欢采用生成静态网页的方式，以减轻服务器端处理过多动态解析的负担；实际上在asp.net、JSP这类编译执行的系统中，这个负担已经被大大减轻，生成静态文件同样是一大负担。当然，生成文件的慢是管理员体验，而首次访问慢是用户体验，从这个角度来说，服务器端生成静态文件还是有必要的。 　　但是我们不得不考虑到目前流行的html静态页生成的后遗症——后期维护，实际上这也正式目前我们团队在工作中已经遇到的大问题。 　　我们的网站每天更新量大约在2000条信息左右，目前仅新闻频道就已经有几十万条信息，我们每天同时有十多名甚至二十多名编辑同时在线更新。目前我们的网站目录已经有近10G大小，每次把网站文件打包需要三个多小时（不包括数据库，数据库是SQL Server）。因此编辑工作繁忙的时段，上传、生成等工作集中在一起，后台速度严重降低。 　　除此之外，每当我们需要对网站的栏目、页眉、页脚等方面进行一次改动，就不得不重新生成静态文件（现在我们采用生成shtml文件，服务器端包含页眉页脚的方式，已经基本解决这个问题），或者我们的网页模板进行了改动，必须重新生成静态文件。 　　这一切造成网站的规模越大，后期维护难度越大，成本越高。 　　针对这一切，我想到静态生成的另一种方式，当然，会增加模板制作的难度，但是同时却有更多的好处，那就是进一步分离网站的内容和结构。 　　我们知道生成静态文件最大的目的是减少数据库查询。生成静态页只需要一次请求就得到页面内容。那如果我们生成静态xml内容呢？这样一次生成之后，内容页以后基本不用再次生成（这相当于以前用文本数据存储的形式，但是文本数据存储是服务器端脚本通过I/O方式读取文档，而xml静态内容是客户端直接请求xml，完全无需服务器端做任何解析或者运算）。 　　有人说，生成xml了那怎么实现多姿多彩的网页效果啊？我们知道xslt可以把xml格式化成html，而且这种格式化可以在服务器端完成也可以在客户端完成。因此我们完全可以输出的就是指定了xslt的xml文件。内容很少，不需改动，就算改动了，也只需要重新生成当前的xml文件，磁盘读写内容大大减小。 　　基本的实现思路和带来的好处如下： 服务器端生成静态的xml，xslt相当于页面模板，是固定的，css文档是外部的。xml负责内容，xslt负责结构，css负责表现。 如果一个网站需要改变风格，比如颜色、背景和简单的布局变化，只需要写css就可以实现；如果更进一步，需要改变页面结构，只需要修改xslt（千万文章也只是一个或几个xslt）。立即更改立即生效。 不用在每次改版的时候重新生成任何的静态文件；并且，我们可以把公共信息单独输出xml，不和内容页混合在一起，要知道，一个xslt并不是只能单独处理一个xml.如此以来，当我们改变了导航结构等公共信息，依然只需要重新生成一个文件，就像更新了一下缓存。 用户访问的时候，每次只下载内容部分，不需要重新下载xslt和css，等于不用ajax却实现了局部更新。 　　这个思路并不是首创，我上网查找相关资料的时候发现有不少同类思路。动易系统在ASP版本中也实现过栏目导航的xml输出，不过只是为了让flash等非asp的应用便于读取栏目结构罢了。另外还有人成功实现了生成静态xml，采用Ajax方式在客户端实现页面内容的变换。 　　可见这并不是一个不可行的思路，当然具体实现起来需要解决很多问题，而且它也有它的缺点： 　　网页制作从静态html模板+标签变成了css文件和静态html（页面设计师实现）+xslt模板（UI工程师或者程序员实现）+xml标签数据和内容数据（应用开发商实现）； 　　但是这个困难只针对一个环节，就是建站环节，而事实上如果官方提供的xslt能够输出结构优秀的html结构，那么设计师其实不需要修改xslt对最终html文档结构做大的变动就可以对网站样式进行彻底地改变。 　　而且这样以来，程序员的web标准知识欠缺或者不了解xhtml，不能输出优秀的符合大家需要的html也不会影响到高水平站长对web标准的追求。 　　我坚信如果这个方案能够得到完善并实施，对于网站管理者来说，绝对是利大于弊。 相关日志2008-06-22 -- 动易SW中的一个严重但不影响使用的bug（二）2008-06-18 -- 动易SW中的一个严重但不影响使用的bug(一)2008-05-23 -- 给UCenter的拥蹩们泼点冷水2007-01-30 -- 整合开发的新思路2006-04-12 -- 用JavaScript动态输出的JS脚本不能执行2009-07-08 -- ASP.NET MVC 最佳实践（四）2009-07-07 -- ASP.NET MVC 最佳实践（三）2009-07-05 -- PHP 5.3.0 发布2009-07-01 -- ASP.NET MVC 最佳实践（二）2009-06-28 -- ASP.NET MVC 最佳实践（一）]]></description>
			<content:encoded><![CDATA[<p>　　现在的网站管理系统都喜欢采用生成静态网页的方式，以减轻服务器端处理过多动态解析的负担；实际上在asp.net、JSP这类编译执行的系统中，这个负担已经被大大减轻，生成静态文件同样是一大负担。当然，生成文件的慢是管理员体验，而首次访问慢是用户体验，从这个角度来说，服务器端生成静态文件还是有必要的。</p>
<p>　　但是我们不得不考虑到目前流行的html静态页生成的后遗症——后期维护，实际上这也正式目前我们团队在工作中已经遇到的大问题。<span id="more-280"></span></p>
<p><span style="color: #ff9900;">　　我们的网站每天更新量大约在2000条信息左右，目前仅新闻频道就已经有几十万条信息，我们每天同时有十多名甚至二十多名编辑同时在线更新。<span style="color: #ff0000;">目前我们的网站目录已经有近10G大小，每次把网站文件打包需要三个多小时（不包括数据库，数据库是SQL Server）。</span>因此编辑工作繁忙的时段，上传、生成等工作集中在一起，后台速度严重降低。</span></p>
<p><span style="color: #ff9900;">　　除此之外，每当我们需要对网站的栏目、页眉、页脚等方面进行一次改动，就不得不重新生成静态文件（现在我们采用生成shtml文件，服务器端包含页眉页脚的方式，已经基本解决这个问题），或者我们的网页模板进行了改动，必须重新生成静态文件。</span></p>
<p>　　这一切造成网站的规模越大，后期维护难度越大，成本越高。</p>
<p>　　针对这一切，我想到静态生成的另一种方式，当然，会增加模板制作的难度，但是同时却有更多的好处，那就是进一步分离网站的内容和结构。</p>
<p>　　我们知道生成静态文件最大的目的是减少数据库查询。生成静态页只需要一次请求就得到页面内容。那如果我们生成静态xml内容呢？这样一次生成之后，内容页以后基本不用再次生成（这相当于以前用文本数据存储的形式，但是文本数据存储是服务器端脚本通过I/O方式读取文档，而xml静态内容是客户端直接请求xml，完全无需服务器端做任何解析或者运算）。</p>
<p>　　有人说，生成xml了那怎么实现多姿多彩的网页效果啊？我们知道xslt可以把xml格式化成html，而且这种格式化可以在服务器端完成也可以在客户端完成。因此我们完全可以输出的就是指定了xslt的xml文件。内容很少，不需改动，就算改动了，也只需要重新生成当前的xml文件，磁盘读写内容大大减小。</p>
<p>　　基本的实现思路和带来的好处如下：</p>
<ol>
<li>服务器端生成静态的xml，xslt相当于页面模板，是固定的，css文档是外部的。xml负责内容，xslt负责结构，css负责表现。</li>
<li>如果一个网站需要改变风格，比如颜色、背景和简单的布局变化，只需要写css就可以实现；如果更进一步，需要改变页面结构，只需要修改xslt（千万文章也只是一个或几个xslt）。立即更改立即生效。</li>
<li>不用在每次改版的时候重新生成任何的静态文件；并且，我们可以把公共信息单独输出xml，不和内容页混合在一起，要知道，一个xslt并不是只能单独处理一个xml.如此以来，当我们改变了导航结构等公共信息，依然只需要重新生成一个文件，就像更新了一下缓存。</li>
<li>用户访问的时候，每次只下载内容部分，不需要重新下载xslt和css，等于不用ajax却实现了局部更新。</li>
</ol>
<p>　　这个思路并不是首创，我上网查找相关资料的时候发现有不少同类思路。动易系统在ASP版本中也实现过栏目导航的xml输出，不过只是为了让flash等非asp的应用便于读取栏目结构罢了。另外还有人成功实现了生成静态xml，采用Ajax方式在客户端实现页面内容的变换。</p>
<p>　　可见这并不是一个不可行的思路，当然具体实现起来需要解决很多问题，而且它也有它的缺点：</p>
<p>　　网页制作从静态html模板+标签变成了css文件和静态html（页面设计师实现）+xslt模板（UI工程师或者程序员实现）+xml标签数据和内容数据（应用开发商实现）；</p>
<p>　　但是这个困难只针对一个环节，就是建站环节，而事实上如果官方提供的xslt能够输出结构优秀的html结构，那么设计师其实不需要修改xslt对最终html文档结构做大的变动就可以对网站样式进行彻底地改变。</p>
<p>　　而且这样以来，程序员的web标准知识欠缺或者不了解xhtml，不能输出优秀的符合大家需要的html也不会影响到高水平站长对web标准的追求。</p>
<p>　　我坚信如果这个方案能够得到完善并实施，对于网站管理者来说，绝对是利大于弊。</p>
<h3  class="related_post_title">相关日志</h3><ul class="related_post"><li>2008-06-22 -- <a href="http://ofcss.com/2008/06/22/api-bug-in-powereasy-siteweaver-part2.html" title="动易SW中的一个严重但不影响使用的bug（二）">动易SW中的一个严重但不影响使用的bug（二）</a></li><li>2008-06-18 -- <a href="http://ofcss.com/2008/06/18/api-bug-in-powereasy-siteweaver-part1.html" title="动易SW中的一个严重但不影响使用的bug(一)">动易SW中的一个严重但不影响使用的bug(一)</a></li><li>2008-05-23 -- <a href="http://ofcss.com/2008/05/23/disadvantages-of-discuz-ucenter.html" title="给UCenter的拥蹩们泼点冷水">给UCenter的拥蹩们泼点冷水</a></li><li>2007-01-30 -- <a href="http://ofcss.com/2007/01/30/new-thinking-about-application-intergration.html" title="整合开发的新思路">整合开发的新思路</a></li><li>2006-04-12 -- <a href="http://ofcss.com/2006/04/12/innerhtml-can-not-be-excuted.html" title="用JavaScript动态输出的JS脚本不能执行">用JavaScript动态输出的JS脚本不能执行</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-05 -- <a href="http://ofcss.com/2009/07/05/php-5-3-0-release-new-feature.html" title="PHP 5.3.0 发布">PHP 5.3.0 发布</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></ul>]]></content:encoded>
			<wfw:commentRss>http://ofcss.com/2008/06/22/thinking-about-html-page-creating.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>动易SW中的一个严重但不影响使用的bug(一)</title>
		<link>http://ofcss.com/2008/06/18/api-bug-in-powereasy-siteweaver-part1.html</link>
		<comments>http://ofcss.com/2008/06/18/api-bug-in-powereasy-siteweaver-part1.html#comments</comments>
		<pubDate>Wed, 18 Jun 2008 12:20:00 +0000</pubDate>
		<dc:creator>小李刀刀</dc:creator>
				<category><![CDATA[所谓技术]]></category>
		<category><![CDATA[ASP]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[动易]]></category>
		<category><![CDATA[开发]]></category>

		<guid isPermaLink="false">http://wukangrui.net/?p=279</guid>
		<description><![CDATA[BUG描述：整个动易API接口的响应功能，除了操作状态码正常，其它部分完全失效，不会返回错误提示，也不会返回用户信息。 BUG重现：在启用了整合的站点，直接访问/API/API_Response.asp，将会看到&#60;status&#62;1&#60;/status&#62;（表示请求不正确或者操作失败），以及&#60;message&#62;操作已成功完成&#60;/message&#62;（操作成功返回的默认值）。就表示该BUG存在。 BUG影响：大部分情况下，各个应用程序并不会向动易请求用户信息，因此除了在登陆失败、注册失败等失败操作会提示用户“操作已成功”的假象以外，暂时不会造成其它影响。 　　动易SW里有这样一个问题，只有启用了整合接口并且曾经在整合的其它系统中遇到过错误提示的朋友才会发现： 　　每当整合出现问题或者是登陆、注册等一系列操作出错的时候，我们知道以前是返回错误的具体提示，包括服务器缺乏相关组件，或者接口配置错误，或者用户信息错误等，都会有不同的提示。到了SW里，这些操作同样也会返回错误，不会让你操作成功。但是错误的提示是什么呢？全部都是“操作已成功完成”，这个搞笑的问题出在哪里呢？ 　　以前设计API的时候，考虑到最常见的情况是用户注册、登陆、注销这些日常操作，而这些操作里又是成功的居多，所以我在用于返回信息的Response.xml模板里，设置了默认返回状态为0（表示成功），默认返回信息为“操作已成功完成”。这就是这个bug的缘起了。 　　那么，以前老的版本反而没有这个问题，为什么新版本里出现这个问题呢？第一反应：当出现错误的时候，没有修改message，也就是错误提示信息。好，我们打开API_Response.asp检查一下，发现当操作错误的时候，代码是这样的： If FoundErr Then sPE_Items(conStatus, 1) = "1" sPE_Items(conMessage, 1) = ErrMsg prepareXML (False) WriteXml Else sPE_Items(conStatus, 1) = "0" prepareXML (False) WriteXml End If 　　我用黄色背景标记的这行，翻译过来就是“设置提示信息的内容为ErrMsg（具体的错误信息）”，说明不是没有修改，于是我们继续往下查，sPE_Items这是一个API使用的全局数组，二维的，sPE_Items(a, b)，a代表xml里的不同元素，b为0标识我们要访问的是元素名称，1标识我们要访问的是元素里的内容；而conMessage是一个常数，实际上它等于4。在全局数组里sPE_Items(4, 1)代表的就是xml中message这个元素的内容。 　　接下来是prepareXML(False)这个函数。这个函数的作用是加载xml模板，然后用数组里的内容去替换默认值。经检查，在prepareXML这个函数里，当返回出错信息的时候的代码如下： ASP/Visual Basic代码 If intIndex &#60;&#62; conAction And intIndex &#60;&#62; conSyskey And intIndex &#60;&#62; conUsername Then setNodeText sPE_Items(intIndex,0),sPE_Items(intIndex,1) End If 　　这里不会有什么问题，看来问题就出在setNodeText这个函数上了。新版本中的这个函数是： [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>BUG描述：整个动易API接口的响应功能，除了操作状态码正常，其它部分完全失效，不会返回错误提示，也不会返回用户信息。</p>
<p>BUG重现：在启用了整合的站点，直接访问/API/API_Response.asp，将会看到<span style="color: #339966;">&lt;status&gt;<span style="color: #ff0000;">1</span>&lt;/status&gt;</span>（表示请求不正确或者操作失败），以及<span style="color: #339966;">&lt;message&gt;<span style="color: #ff0000;">操作已成功完成</span>&lt;/message&gt;</span>（操作成功返回的默认值）。就表示该BUG存在。</p>
<p>BUG影响：大部分情况下，各个应用程序并不会向动易请求用户信息，因此除了在登陆失败、注册失败等失败操作会提示用户“操作已成功”的假象以外，暂时不会造成其它影响。</p></blockquote>
<p><span id="more-279"></span><br />
　　动易SW里有这样一个问题，只有启用了整合接口并且曾经在整合的其它系统中遇到过错误提示的朋友才会发现：</p>
<p>　　每当整合出现问题或者是登陆、注册等一系列操作出错的时候，我们知道以前是返回错误的具体提示，包括服务器缺乏相关组件，或者接口配置错误，或者用户信息错误等，都会有不同的提示。到了SW里，这些操作同样也会返回错误，不会让你操作成功。但是错误的提示是什么呢？全部都是“操作已成功完成”，这个搞笑的问题出在哪里呢？</p>
<p>　　以前设计API的时候，考虑到最常见的情况是用户注册、登陆、注销这些日常操作，而这些操作里又是成功的居多，所以我在用于返回信息的Response.xml模板里，设置了默认返回状态为0（表示成功），默认返回信息为“操作已成功完成”。这就是这个bug的缘起了。</p>
<p>　　那么，以前老的版本反而没有这个问题，为什么新版本里出现这个问题呢？第一反应：当出现错误的时候，没有修改message，也就是错误提示信息。好，我们打开API_Response.asp检查一下，发现当操作错误的时候，代码是这样的：</p>
<pre lang="ASP">If FoundErr Then
    sPE_Items(conStatus, 1) = "1"
    sPE_Items(conMessage, 1) = ErrMsg
    prepareXML (False)
    WriteXml
Else
    sPE_Items(conStatus, 1) = "0"
    prepareXML (False)
    WriteXml
End If</pre>
<p>　　我用黄色背景标记的这行，翻译过来就是“设置提示信息的内容为ErrMsg（具体的错误信息）”，说明不是没有修改，于是我们继续往下查，sPE_Items这是一个API使用的全局数组，二维的，sPE_Items(a, b)，a代表xml里的不同元素，b为0标识我们要访问的是元素名称，1标识我们要访问的是元素里的内容；而conMessage是一个常数，实际上它等于4。在全局数组里sPE_Items(4, 1)代表的就是xml中message这个元素的内容。</p>
<p>　　接下来是prepareXML(False)这个函数。这个函数的作用是加载xml模板，然后用数组里的内容去替换默认值。经检查，在prepareXML这个函数里，当返回出错信息的时候的代码如下：</p>
<div class="codeText">
<div class="codeHead">ASP/Visual Basic代码</div>
<ol class="dp-vb">
<li class="alt"><span><span class="keyword">If</span><span> intIndex &lt;&gt; conAction </span><span class="keyword">And</span><span> intIndex &lt;&gt; conSyskey </span><span class="keyword">And</span><span> intIndex &lt;&gt; conUsername </span><span class="keyword">Then</span><span>  </span></span></li>
<li><span>    setNodeText sPE_Items(intIndex,0),sPE_Items(intIndex,1)  </span></li>
<li class="alt"><span><span class="keyword">End</span><span> </span><span class="keyword">If</span><span>  </span></span></li>
</ol>
</div>
<p>　　这里不会有什么问题，看来问题就出在setNodeText这个函数上了。新版本中的这个函数是：</p>
<div class="codeText">
<div class="codeHead">ASP/Visual Basic代码</div>
<ol class="dp-vb">
<li class="alt"><span><span class="comment">&#8216;**************************************************</span><span>  </span></span></li>
<li><span><span class="comment">&#8216;函数名：setNodeText</span><span>  </span></span></li>
<li class="alt"><span><span class="comment">&#8216;作  用：设置XML文件中指定节点的文本</span><span>  </span></span></li>
<li><span><span class="comment">&#8216;参  数：strNodeName   &#8212;-节点名称</span><span>  </span></span></li>
<li class="alt"><span><span class="comment">&#8216;　　　　strNodeText   &#8212;-要设置的文本</span><span>  </span></span></li>
<li><span><span class="comment">&#8216;返回值：0 = 设置成功; 否则返回Err.Description</span><span>  </span></span></li>
<li class="alt"><span><span class="comment">&#8216;**************************************************</span><span>  </span></span></li>
<li><span><span class="keyword">Function</span><span> setNodeText(strNodeName, strNodeText)  </span></span></li>
<li class="alt"><span>    <span class="keyword">If</span><span> IsNull(strNodeText) </span><span class="keyword">Or</span><span> IsEmpty(strNodeText) or strNodeText = </span><span class="string">“”</span><span> </span><span class="keyword">Then</span><span> </span><span class="keyword">Exit</span><span> </span><span class="keyword">Function</span><span>  </span></span></li>
<li><span>    <span class="keyword">If</span><span> IsNull(strNodeName) </span><span class="keyword">Or</span><span> IsEmpty(strNodeName) or strNodeName = </span><span class="string">“”</span><span> </span><span class="keyword">Then</span><span> </span><span class="keyword">Exit</span><span> </span><span class="keyword">Function</span><span>  </span></span></li>
<li class="alt"><span>    <span class="keyword">If</span><span> IsNode(strNodeName) </span><span class="keyword">Then</span><span> sMyXmlDoc.<span style="background-color: #ffff00">selectSingleNode(strNodeName).text</span> = strNodeText  </span></span></li>
<li><span><span class="keyword">End</span><span> </span><span class="keyword">Function</span><span>  </span></span></li>
</ol>
</div>
<p>　　以前的版本中代码是：</p>
<div class="codeText">
<div class="codeHead">ASP/Visual Basic代码</div>
<ol class="dp-vb">
<li class="alt"><span><span class="comment">&#8216;**************************************************</span><span>  </span></span></li>
<li><span><span class="comment">&#8216;函数名：setNodeText</span><span>  </span></span></li>
<li class="alt"><span><span class="comment">&#8216;作  用：设置XML文件中指定节点的文本</span><span>  </span></span></li>
<li><span><span class="comment">&#8216;参  数：strNodeName   &#8212;-节点名称</span><span>  </span></span></li>
<li class="alt"><span><span class="comment">&#8216;　　　　strNodeText   &#8212;-要设置的文本</span><span>  </span></span></li>
<li><span><span class="comment">&#8216;返回值：0 = 设置成功; 否则返回Err.Description</span><span>  </span></span></li>
<li class="alt"><span><span class="comment">&#8216;**************************************************</span><span>  </span></span></li>
<li><span><span class="keyword">Function</span><span> setNodeText(strNodeName, strNodeText)  </span></span></li>
<li class="alt"><span>    <span class="keyword">If</span><span> IsNull(strNodeText) </span><span class="keyword">Or</span><span> IsEmpty(strNodeText) or strNodeText = </span><span class="string">“”</span><span> </span><span class="keyword">Then</span><span> </span><span class="keyword">Exit</span><span> </span><span class="keyword">Function</span><span>  </span></span></li>
<li><span>    <span class="keyword">If</span><span> IsNull(strNodeName) </span><span class="keyword">Or</span><span> IsEmpty(strNodeName) or strNodeName = </span><span class="string">“”</span><span> </span><span class="keyword">Then</span><span> </span><span class="keyword">Exit</span><span> </span><span class="keyword">Function</span><span>   </span></span></li>
<li class="alt"><span>    <span class="keyword">If</span><span> IsNode(strNodeName) </span><span class="keyword">Then</span><span> sMyXmlDoc.<span style="background-color: #ffff00">getElementsByTagName(strNodeName).Item(0).text</span> = strNodeText  </span></span></li>
<li><span><span class="keyword">End</span><span> </span><span class="keyword">Function</span><span>  </span></span></li>
</ol>
</div>
<p>　　区别就在于，新版本用selectSingleNode这个方法获取节点，以前版本中我用getElementsByTagName().Item(0)这个方法来获取节点。两个方法都是返回xml文档树中的一个元素对象。新版本的代码简洁，直接从树中读取一个元素，而我的方法是读取文档树中所有标签为strNodeName（本例中指的是message）的元素列表，然后取第一个。</p>
<p>　　我排错的时候看到这里就已经明白问题所在了。因为当初我第一次写到这里的时候就犯过新版中这个错误。selectSingleNode这个方法的参数类型是XPath，而getElementsByTagName这个方法的参数类型是string。我们这里给的“message”，不是一个XPath，如果在我们的文档中用XPath来标识这个元素，正确的应该是“/root/body/message”，但是由于sMyXmlDoc这个对象取得是xml文档树的根元素，也就是root，所以其实也可以用“/body/message”来访问到。文档中只有一个message元素，因此也可以用“//message”来访问。不管用哪一种都行，但是用“message”是不对的。</p>
<p>　　所以这里给xml中所有body的子元素赋值都会失败。这就是问题所在了。</p>
<p>　　同理可知，在新版本的接口中，如果是整合的程序向动易发送请求，那么不管什么请求，返回的xml包中，都只有两个有效数据，一个是告诉对方响应者是动易系统，另一个就是告诉对方操作状态是成功还是失败。至于错误的具体提示，只有默认值，而其它的数据，比如检索用户信息，返回的则全部是空值。还好目前的整合中基本上不会用到这些元素，所以也就成了一个“严重”但不影响使用的bug了。关于这个bug为什么没有引发500错误以及如何修正，<a href="http://blog.oophome.net/article.asp?id=282" target="_blank">下次</a>我再继续说。</p>
<p>　　除此之外，动易的新版本接口还增加了一个新元素（sex），可以理解为符合接口规范的自定义元素，但是这个元素表示的是用户性别。这是在标准中定义的必备扩展元素，元素名称是gendar（英文单词意思是性别）。等于放弃了对标准元素gendar的支持，增加了一个自定义元素sex。</p>
<p>　　不知道三方是否在这个新增元素上做过沟通取得了共识。如果没有的话，那么这里又是一个新bug，就是通用注册的时候，其它程序将不能通知动易记录用户的性别，动易也没法通知其它用户。</p>
<p>　　我第一次看到这个新增元素的时候百思不得其解。如果是gendar命名不恰当，要改的话，那应该会发公告通知PDO接口规范更新到1.1或者2.0，新增sex元素，gendar元素状态变为“不推荐”，这是w3c在xhtml规范里喜欢用的方式。先不推荐但是还兼容，让你有时间慢慢改，以后时机恰当再取消。</p>
<p>　　但是我奇怪的是gendar无论从语意上讲还是从哪方面讲，都不算是命名不规范的元素啊，甚至是比sex更规范的元素。sex只不过是在部分web应用里习惯的用法而已。其英文单词意思是“性”，而不是“性别”。</p>
<p>　　莫非做这个修改的技术员在修改接口的时候不看接口规范？不得而知了。但是对于selectSingleNode不能根据元素名称选择元素这个问题，的确是不应该犯的。</p>
<p>　　发现我写的代码被更改并不是因为我写错了，本来应该是高兴的吧，但是我却高兴不起来。我依然是动易的忠实FANS，我希望它更好。</p>
<h3  class="related_post_title">相关日志</h3><ul class="related_post"><li>2008-06-22 -- <a href="http://ofcss.com/2008/06/22/api-bug-in-powereasy-siteweaver-part2.html" title="动易SW中的一个严重但不影响使用的bug（二）">动易SW中的一个严重但不影响使用的bug（二）</a></li><li>2008-05-23 -- <a href="http://ofcss.com/2008/05/23/disadvantages-of-discuz-ucenter.html" title="给UCenter的拥蹩们泼点冷水">给UCenter的拥蹩们泼点冷水</a></li><li>2008-06-22 -- <a href="http://ofcss.com/2008/06/22/thinking-about-html-page-creating.html" title="静态页面生成的思考">静态页面生成的思考</a></li><li>2008-06-04 -- <a href="http://ofcss.com/2008/06/04/unix-timestamp-in-asp.html" title="在ASP中实现UNIX时间戳">在ASP中实现UNIX时间戳</a></li><li>2007-01-30 -- <a href="http://ofcss.com/2007/01/30/new-thinking-about-application-intergration.html" title="整合开发的新思路">整合开发的新思路</a></li><li>2006-04-12 -- <a href="http://ofcss.com/2006/04/12/innerhtml-can-not-be-excuted.html" title="用JavaScript动态输出的JS脚本不能执行">用JavaScript动态输出的JS脚本不能执行</a></li><li>2010-10-30 -- <a href="http://ofcss.com/2010/10/30/bfc-element-margin-bug-in-webkit.html" title="webkit中BFC元素临近浮动元素时的边距bug">webkit中BFC元素临近浮动元素时的边距bug</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-05 -- <a href="http://ofcss.com/2009/07/05/php-5-3-0-release-new-feature.html" title="PHP 5.3.0 发布">PHP 5.3.0 发布</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ofcss.com/2008/06/18/api-bug-in-powereasy-siteweaver-part1.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>在ASP中实现UNIX时间戳</title>
		<link>http://ofcss.com/2008/06/04/unix-timestamp-in-asp.html</link>
		<comments>http://ofcss.com/2008/06/04/unix-timestamp-in-asp.html#comments</comments>
		<pubDate>Wed, 04 Jun 2008 06:55:00 +0000</pubDate>
		<dc:creator>小李刀刀</dc:creator>
				<category><![CDATA[所谓技术]]></category>
		<category><![CDATA[ASP]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[开发]]></category>

		<guid isPermaLink="false">http://wukangrui.net/?p=272</guid>
		<description><![CDATA[　　在康盛创想发布UC以后，我曾经尝试为其编写ASP把版本的客户端类库，过程中发现了几个问题，首当其冲的当然是服务器端不支持非php平台的接口，这个问题直接导致了我选择另起炉灶开发自己的通用用户中心。 　　但是在研究UC的过程中却也有一些细小的收获。这篇文章说说PHP中的时间戳。在PHP中，时间函数time()获得的不是我们在ASP中的事件函数Now()所返回的“2008-06-04 21:19:41”这样的形式，而是“1123495443”这样的形式。这个记录的是所表示的时间与1970年1月1日午夜零点之间的事件差，单位为秒，不考虑闰年等因素。 　　如果要编写UC的ASP客户端，这个问题是必然要面对的，实际上即使不为UC编写客户端，这个特性引入ASP还是有不少好处的。下面是具体的实现办法： ASP/Visual Basic代码 &#8216;参数：strTime:要转换的时间；intTimeZone：该时间对应的时区 &#8216;返回值：strTime相对于1970年1月1日午夜0点经过的秒数 &#8216;示例：ToUnixTime(“2008-5-23 10:51:0&#8243;, +8)，返回值为1211511060 Function ToUnixTime(strTime, intTimeZone) If IsEmpty(strTime) or Not IsDate(strTime) Then strTime = Now If IsEmpty(intTimeZone) or Not isNumeric(intTimeZone) Then intTimeZone = 0 ToUnixTime = DateAdd(“h”,-intTimeZone,strTime) ToUnixTime = DateDiff(“s”,“1970-1-1 0:0:0&#8243;, ToUnixTime) End Function &#8216;把UNIX时间戳转换为标准时间 &#8216;参数：intTime:要转换的UNIX时间戳；intTimeZone：该时间戳对应的时区 &#8216;返回值：intTime所代表的标准时间 &#8216;示例：FromUnixTime(“1211511060&#8243;, +8)，返回值2008-5-23 10:51:0 Function FromUnixTime(intTime, intTimeZone) If IsEmpty(intTime) Or Not [...]]]></description>
			<content:encoded><![CDATA[<p>　　在康盛创想发布UC以后，我曾经尝试为其编写ASP把版本的客户端类库，过程中发现了几个问题，首当其冲的当然是服务器端不支持非php平台的接口，这个问题直接导致了我选择另起炉灶开发自己的通用用户中心。</p>
<p>　　但是在研究UC的过程中却也有一些细小的收获。这篇文章说说PHP中的时间戳。在PHP中，时间函数time()获得的不是我们在ASP中的事件函数Now()所返回的“2008-06-04 21:19:41”这样的形式，而是“1123495443”这样的形式。这个记录的是所表示的时间与1970年1月1日午夜零点之间的事件差，单位为秒，不考虑闰年等因素。<span id="more-272"></span></p>
<p>　　如果要编写UC的ASP客户端，这个问题是必然要面对的，实际上即使不为UC编写客户端，这个特性引入ASP还是有不少好处的。下面是具体的实现办法：</p>
<div class="codeText">
<div class="codeHead">ASP/Visual Basic代码</div>
<ol class="dp-vb">
<li class="alt"><span><span class="comment">&#8216;参数：strTime:要转换的时间；intTimeZone：该时间对应的时区     </span><span>  </span></span></li>
<li><span class="comment">&#8216;返回值：strTime相对于1970年1月1日午夜0点经过的秒数     </span><span>  </span></li>
<li class="alt"><span class="comment">&#8216;示例：ToUnixTime(“2008-5-23 10:51:0&#8243;, +8)，返回值为1211511060     </span><span>  </span></li>
<li><span class="keyword">Function</span><span> ToUnixTime(strTime, intTimeZone)       </span></li>
<li class="alt"><span>    </span><span class="keyword">If</span><span> IsEmpty(strTime) or </span><span class="keyword">Not</span><span> IsDate(strTime) </span><span class="keyword">Then</span><span> strTime = Now       </span></li>
<li><span>    </span><span class="keyword">If</span><span> IsEmpty(intTimeZone) or </span><span class="keyword">Not</span><span> isNumeric(intTimeZone) </span><span class="keyword">Then</span><span> intTimeZone = 0       </span></li>
<li class="alt"><span>    ToUnixTime = DateAdd(</span><span class="string">“h”</span><span>,-intTimeZone,strTime)       </span></li>
<li><span>    ToUnixTime = DateDiff(</span><span class="string">“s”</span><span>,</span><span class="string">“1970-1-1 0:0:0&#8243;</span><span>, ToUnixTime)       </span></li>
<li class="alt"><span class="keyword">End</span><span> </span><span class="keyword">Function</span><span>      </span></li>
<li><span>      </span></li>
<li class="alt"><span class="comment">&#8216;把UNIX时间戳转换为标准时间     </span><span>  </span></li>
<li><span class="comment">&#8216;参数：intTime:要转换的UNIX时间戳；intTimeZone：该时间戳对应的时区     </span><span>  </span></li>
<li class="alt"><span class="comment">&#8216;返回值：intTime所代表的标准时间     </span><span>  </span></li>
<li><span class="comment">&#8216;示例：FromUnixTime(“1211511060&#8243;, +8)，返回值2008-5-23 10:51:0     </span><span>  </span></li>
<li class="alt"><span class="keyword">Function</span><span> FromUnixTime(intTime, intTimeZone)       </span></li>
<li><span>    </span><span class="keyword">If</span><span> </span><span>IsEmpty(intTime) </span><span class="keyword">Or</span><span> </span><span class="keyword">Not</span><span> IsNumeric(intTime) </span><span class="keyword">Then</span><span>      </span></li>
<li class="alt"><span>        FromUnixTime = Now()       </span></li>
<li><span>        </span><span class="keyword">Exit</span><span> </span><span class="keyword">Function</span><span>      </span></li>
<li class="alt"><span>    </span><span class="keyword">End</span><span> </span><span class="keyword">If</span><span>      </span></li>
<li><span>    </span><span class="keyword">If</span><span> </span><span>IsEmpty(intTime) </span><span class="keyword">Or</span><span> </span><span class="keyword">Not</span><span> IsNumeric(intTimeZone) </span><span class="keyword">Then</span><span> intTimeZone = 0       </span></li>
<li class="alt"><span>    FromUnixTime = DateAdd(</span><span class="string">“s”</span><span>, intTime, </span><span class="string">“1970-1-1 0:0:0&#8243;</span><span>)       </span></li>
<li><span>    FromUnixTime = DateAdd(</span><span class="string">“h”</span><span>, intTimeZone, FromUnixTime)       </span></li>
<li class="alt"><span class="keyword">End</span><span> </span><span class="keyword">Function</span><span>  </span></li>
</ol>
</div>
<p> 　　这两个函数分别用于标准时间转Unix时间戳和Unix时间戳转标准时间。用法在函数前面的注释里写得很清楚了。</p>
<h3  class="related_post_title">相关日志</h3><ul class="related_post"><li>2008-05-23 -- <a href="http://ofcss.com/2008/05/23/disadvantages-of-discuz-ucenter.html" title="给UCenter的拥蹩们泼点冷水">给UCenter的拥蹩们泼点冷水</a></li><li>2009-07-05 -- <a href="http://ofcss.com/2009/07/05/php-5-3-0-release-new-feature.html" title="PHP 5.3.0 发布">PHP 5.3.0 发布</a></li><li>2008-06-22 -- <a href="http://ofcss.com/2008/06/22/api-bug-in-powereasy-siteweaver-part2.html" title="动易SW中的一个严重但不影响使用的bug（二）">动易SW中的一个严重但不影响使用的bug（二）</a></li><li>2008-06-18 -- <a href="http://ofcss.com/2008/06/18/api-bug-in-powereasy-siteweaver-part1.html" title="动易SW中的一个严重但不影响使用的bug(一)">动易SW中的一个严重但不影响使用的bug(一)</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-06-08 -- <a href="http://ofcss.com/2009/06/08/using-fastcgi-to-host-php-applications-on-iis-7x.html" title="在 IIS 7.x 中用 FastCGI 运行 PHP">在 IIS 7.x 中用 FastCGI 运行 PHP</a></li><li>2008-09-19 -- <a href="http://ofcss.com/2008/09/19/bug-about-search-engine-of-oblog.html" title="Oblog检测搜索引擎的一个问题">Oblog检测搜索引擎的一个问题</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ofcss.com/2008/06/04/unix-timestamp-in-asp.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>给UCenter的拥蹩们泼点冷水</title>
		<link>http://ofcss.com/2008/05/23/disadvantages-of-discuz-ucenter.html</link>
		<comments>http://ofcss.com/2008/05/23/disadvantages-of-discuz-ucenter.html#comments</comments>
		<pubDate>Fri, 23 May 2008 03:32:00 +0000</pubDate>
		<dc:creator>小李刀刀</dc:creator>
				<category><![CDATA[所谓技术]]></category>
		<category><![CDATA[指手划脚]]></category>
		<category><![CDATA[ASP]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[动易]]></category>
		<category><![CDATA[开发]]></category>

		<guid isPermaLink="false">http://wukangrui.net/?p=270</guid>
		<description><![CDATA[康盛创想“七剑合璧”围绕着UCenter同时发布，不仅为站长同时提供了建立各种类型网站的全套解决方案，而且还充分实现了多系统之间的用户数据完美整合，并且解决了跨域条件下单点登录等问题。让很多开发人员都眼前为之一亮。 在康盛创想的论坛上能看到有不少JSP程序、ASP.NET程序员都在咨询或者说抱怨官方的开发文档和示例太难看懂，完全是基于PHP的，如果不把PHP搞懂，很难实现在其它开发平台下的接口开发。而官方的回答只是“以后考虑”。 动易SF 1.1的发布公告中也指出基于UCenter的接口已经列入开发计划中。令广大动易站长欢欣鼓舞。 但是，我却不得不在这里给众多开发人员和站长们泼一盆冷水&#38;mdash;&#38;mdash;基于目前的UCenter，是没办法开发其它平台的接口的。原因很简单，UCenter服务器端默认了客户端的接口路径为“应用URL” + “api/uc.php”，而且这个是不能在配置文件或者后台修改的。 也就是说，不管你在什么平台下，是什么开发语言，你的接口必须为uc.php。那么，只有一个解决方法，就是在你的服务器上映射.php的后缀到你的程序语言的解析器，让.php也变成asp文件或者.net页面的后缀。那你的站点就不可能再同时支持php和asp，或者php和jsp，或者php和asp.net。而如果你是虚拟主机用户，你需要做的事情更多。 我们可以通过简单的方法修改UCenter，使之支持各平台语言的接口（要修改的文件只有4个左右），但是如此一来，等于是第三方开发人员或者说二次开发人员需要对服务器端进行修改，那已经不像是一个“通用平台”的问题了。 其次，在跨平台的信息传递中，UCenter大量使用的是Get/Post方式发送URLEncode编码的数据，而不是在所有平台所有编码语言下都有良好支持的xml格式。这样开发人员不得不继续花费大量时间来处理编码问题。 还有，UCenter由于采用PHP开发，大量使用了PHP的特性的东西，比如UNIX时间戳，比如键值对的数组，而在其它语言平台中，对这些东西的支持是各有不同的。虽然能够处理，但是却非常麻烦。 UCenter目前给我们带来一个最大的启发，就是一个中心，多套应用的模式，以及采用P3P来实现跨域Cookie处理的思路。 我相信，随着UCenter的出现解决了一系列跨站整合中的问题后，完善的跨站用户中心应该会很快出现。而UCenter如果不在下一版本中做大规模的改变，它是不太可能成为最终的通用整合中心的。至少这么久以来，我们可以看到康盛自己的.NET论坛都还没能支持这个UCenter，就能说明一些问题。 相关日志2008-06-22 -- 动易SW中的一个严重但不影响使用的bug（二）2008-06-18 -- 动易SW中的一个严重但不影响使用的bug(一)2008-06-04 -- 在ASP中实现UNIX时间戳2009-07-05 -- PHP 5.3.0 发布2008-06-22 -- 静态页面生成的思考2007-01-30 -- 整合开发的新思路2006-04-12 -- 用JavaScript动态输出的JS脚本不能执行2009-07-08 -- ASP.NET MVC 最佳实践（四）2009-07-07 -- ASP.NET MVC 最佳实践（三）2009-07-01 -- ASP.NET MVC 最佳实践（二）]]></description>
			<content:encoded><![CDATA[<p>康盛创想“七剑合璧”围绕着UCenter同时发布，不仅为站长同时提供了建立各种类型网站的全套解决方案，而且还充分实现了多系统之间的用户数据完美整合，并且解决了跨域条件下单点登录等问题。让很多开发人员都眼前为之一亮。</p>
<p>在康盛创想的论坛上能看到有不少JSP程序、ASP.NET程序员都在咨询或者说抱怨官方的开发文档和示例太难看懂，完全是基于PHP的，如果不把PHP搞懂，很难实现在其它开发平台下的接口开发。而官方的回答只是“以后考虑”。</p>
<p><span id="more-270"></span></p>
<p>动易SF 1.1的发布公告中也指出基于UCenter的接口已经列入开发计划中。令广大动易站长欢欣鼓舞。</p>
<p>但是，我却不得不在这里给众多开发人员和站长们泼一盆冷水&amp;mdash;&amp;mdash;基于目前的UCenter，是没办法开发其它平台的接口的。原因很简单，UCenter服务器端默认了客户端的接口路径为“应用URL” + “api/uc.php”，而且这个是不能在配置文件或者后台修改的。</p>
<p>也就是说，不管你在什么平台下，是什么开发语言，你的接口必须为uc.php。那么，只有一个解决方法，就是在你的服务器上映射.php的后缀到你的程序语言的解析器，让.php也变成asp文件或者.net页面的后缀。那你的站点就不可能再同时支持php和asp，或者php和jsp，或者php和asp.net。而如果你是虚拟主机用户，你需要做的事情更多。</p>
<p>我们可以通过简单的方法修改UCenter，使之支持各平台语言的接口（要修改的文件只有4个左右），但是如此一来，等于是第三方开发人员或者说二次开发人员需要对服务器端进行修改，那已经不像是一个“通用平台”的问题了。</p>
<p>其次，在跨平台的信息传递中，UCenter大量使用的是Get/Post方式发送URLEncode编码的数据，而不是在所有平台所有编码语言下都有良好支持的xml格式。这样开发人员不得不继续花费大量时间来处理编码问题。</p>
<p>还有，UCenter由于采用PHP开发，大量使用了PHP的特性的东西，比如UNIX时间戳，比如键值对的数组，而在其它语言平台中，对这些东西的支持是各有不同的。虽然能够处理，但是却非常麻烦。</p>
<p>UCenter目前给我们带来一个最大的启发，就是一个中心，多套应用的模式，以及采用P3P来实现跨域Cookie处理的思路。</p>
<p>我相信，随着UCenter的出现解决了一系列跨站整合中的问题后，完善的跨站用户中心应该会很快出现。而UCenter如果不在下一版本中做大规模的改变，它是不太可能成为最终的通用整合中心的。至少这么久以来，我们可以看到康盛自己的.NET论坛都还没能支持这个UCenter，就能说明一些问题。</p>
<h3  class="related_post_title">相关日志</h3><ul class="related_post"><li>2008-06-22 -- <a href="http://ofcss.com/2008/06/22/api-bug-in-powereasy-siteweaver-part2.html" title="动易SW中的一个严重但不影响使用的bug（二）">动易SW中的一个严重但不影响使用的bug（二）</a></li><li>2008-06-18 -- <a href="http://ofcss.com/2008/06/18/api-bug-in-powereasy-siteweaver-part1.html" title="动易SW中的一个严重但不影响使用的bug(一)">动易SW中的一个严重但不影响使用的bug(一)</a></li><li>2008-06-04 -- <a href="http://ofcss.com/2008/06/04/unix-timestamp-in-asp.html" title="在ASP中实现UNIX时间戳">在ASP中实现UNIX时间戳</a></li><li>2009-07-05 -- <a href="http://ofcss.com/2009/07/05/php-5-3-0-release-new-feature.html" title="PHP 5.3.0 发布">PHP 5.3.0 发布</a></li><li>2008-06-22 -- <a href="http://ofcss.com/2008/06/22/thinking-about-html-page-creating.html" title="静态页面生成的思考">静态页面生成的思考</a></li><li>2007-01-30 -- <a href="http://ofcss.com/2007/01/30/new-thinking-about-application-intergration.html" title="整合开发的新思路">整合开发的新思路</a></li><li>2006-04-12 -- <a href="http://ofcss.com/2006/04/12/innerhtml-can-not-be-excuted.html" title="用JavaScript动态输出的JS脚本不能执行">用JavaScript动态输出的JS脚本不能执行</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></ul>]]></content:encoded>
			<wfw:commentRss>http://ofcss.com/2008/05/23/disadvantages-of-discuz-ucenter.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

