Jaa


每周源代码21- ASP.NET MVC Preview 2源代码

[原文发表地址] The Weekly Source Code 21 - ASP.NET MVC Preview 2 Source Code

[原文发表时间] 2008-03-21 12:26 PM

所以,亲爱的读者,我现在向你们展示"每周源代码"一系列帖子中的第21个。我这周身兼两职,但是ASP.NET MVC Source今天发布了,我想分享更多的想法。我鼓励大家到ASP.NET MVC 代码社区上查阅每周源代码的第17章。

阅读注释

当你在读代码时,找出像"TODO," "HACK," "REVIEW,"等词语,找出备受编写者关注的部分代码。

在SelectBuilder.cs中,有条注释这样写道:

// TODO: Should these be HTML encoded or HTML attribute encoded? Need to review all helper methods that call this.
string thisText = HttpUtility.HtmlEncode(listData[key].ToString());
string thisValue = HttpUtility.HtmlEncode(key.ToString());

这是个有趣的问题。他在询问他们该使用System.Web.HttpUtility.HtmlAttributeEncode还是HtmlEncode. HTML 编码规则 对 <, " and & 进行编码.

在ViewUserControl.cs中,我们可以看到以下代码:

public virtual void RenderView(ViewContext viewContext) {
// TODO: Remove this hack. Without it, the browser appears to always load cached output
viewContext.HttpContext.Response.Cache.SetExpires(DateTime.Now);
ViewUserControlContainerPage containerPage = new ViewUserControlContainerPage(this);
containerPage.RenderView(viewContext);
}
这个代码也非常难。当我在编写银行软件的过程中,跟踪缓存是个大麻烦,至少要消耗我10%的时间。直至现在,IE浏览器和火狐浏览器之间总有一些微妙(也不是太微妙)的区别。看起来火狐浏览器的缓存非常积极。

有几个注释标识着"REVIEW"如:

 // REVIEW: Should we make this public?
internal interface IBuildManager {
object CreateInstanceFromVirtualPath(string virtualPath, Type requiredBaseType);
ICollection GetReferencedAssemblies();
}

而这个还挺有趣的。HttpHandler中的一个IsReusable属性表明这个实例是否有状态,如果有的话,就不能重用于ASP.NET属性。如果你编写了一个没有状态的HttpHandler,只有一个ProcessRequest, 你可以“重用”它,并得到一点小小的收获.

protected virtual bool IsReusable {
get {
// REVIEW: What's this?
return false;
}
}

下面是重载中的一个:

//REVIEW: Should we have an overload that takes Uri?
[SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings",
Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
[SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings",
Justification = "Needs to take same parameters as HttpUtility.UrlEncode()")]
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic",
Justification = "For consistency, all helpers are instance methods.")]
public string Encode(string url) {
return HttpUtility.UrlEncode(url);
}

我们都写过这样的注释。关键是要确保在Visual Studio中包含所有的关键词,使您的注释在任务列表中呈现,然后可以在发布之前处理它们。

查看SuppressMessage

微软大量地使用了代码分析,你也应该这么做。然而,有时候代码分析提供的建议是错误的或者是不适用的,你必须禁止显示这些信息。

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate",
Justification = "There is already a ViewData property and it has a slightly different meaning.")]
protected internal virtual void SetViewData(object viewData) {
_viewData = viewData;
}

这是一个很好的方法通过找出对SuppressMessage的所有引用来找出哪些地方的代码分析出错了。换句话说,它不会损失偶尔对其进行重新评估作为重构的机会。

最有趣的是Justification特性,它是由开发人员编写的。例如,下面是GlobalSuppressions.cs:的内容:

[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Scope = "member", Target = "System.Web.Mvc.TempDataDictionary.#System.Collections.Generic.ICollection`1<system.collections.generic.keyvaluepair `2>)",
Justification = "There are no defined scenarios for wanting to derive from this class, but we don't want to prevent it either.")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Scope = "member", Target = "System.Web.Mvc.TempDataDictionary.#System.Collections.Generic.ICollection`1<system.collections.generic.keyvaluepair `2>[],System.Int32)",
Justification = "There are no defined scenarios for wanting to derive from this class, but we don't want to prevent it either.")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Scope = "member", Target = "System.Web.Mvc.TempDataDictionary.#System.Collections.Generic.ICollection`1<system.collections.generic.keyvaluepair `2>>.IsReadOnly",
Justification = "There are no defined scenarios for wanting to derive from this class, but we

这儿有个关于justification特性的好例子:

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "2#", Justification = "The return value is not a regular URL since it may contain ~/ ASP.NET-specific characters")]
public static string SubmitImage(this HtmlHelper helper, string htmlName, string imageRelativeUrl) {
return SubmitImage(helper, htmlName, imageRelativeUrl, null);
}

代码分析警示,有一个名为"Url"的字符串参数,但justification是有效的:“该值并非正规URL,因为它可能包含了 ~/ ASP.NET- 特定字符。

注意UTILS

正如我前面说提到的,每当我开始阅读代码时,我会寻找带有"Util."标识的代码。这些代码会告诉我们一些东西。Util会显示代码的“软肋”,并且可以让我们对代码有更好的考虑,或者是更好的阅读这些代码,或者是关于这些代码存在的框架

在ASP.NET MVC的项目中,有一个Util文件夹和一个Pair.cs文件,让我们查看一下。

//------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------

namespace System.Web.Util {
using System;

// Generic Pair class. Overrides Equals() and GetHashCode(), so it can be used as a dictionary key.
internal sealed class Pair {
private readonly TFirst _first;
private readonly TSecond _second;

public Pair(TFirst first, TSecond second) {
_first = first;
_second = second;
}

public TFirst First {
get {
return _first;
}
}

public TSecond Second {
get {
return _second;
}
}

public override bool Equals(object obj) {
if (obj == this) {
return true;
}

Pair other = obj as Pair;
return (other != null) &&
(((other._first == null) && (_first == null)) ||
((other._first != null) && other._first.Equals(_first))) &&
(((other._second == null) && (_second == null)) ||
((other._second != null) && other._second.Equals(_second)));
}

public override int GetHashCode() {
int a = (_first == null) ? 0 : _first.GetHashCode();
int b = (_second == null) ? 0 : _second.GetHashCode();
return CombineHashCodes(a, b);
}

// Copied from ndp\fx\src\xsp\System\Web\Util\HashCodeCombiner.cs
private static int CombineHashCodes(int h1, int h2) {
return ((h1 << 5) + h1) ^ h2;
}
}
}

这是一个简单但很巧妙的类,用泛型给人以任意两种类型进行配对。最有趣的部分是CombineHashCodes方法,从每个对象中取出一些哈西代码,将它们集合起来,使得每对哈西代码在下面的哈希表的使用中独一无二。

Pair类是用来在TempDataDictionary类内部创建的组合对象,如下所示:

private Pair<Dictionary<string , object>, HashSet<string>> _sessionData;

密钥是实际的临时数据存储库,该值是在请求的过程中被修改以便能在下一个请求中存活的一个密钥列表。

在阅读此代码的过程中,还有更多的东西值得去发掘,看到它发展,改变和提高将是件多么高兴的事啊!