<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_Fish Li</title><subtitle type="text">吾生也有涯，而知也无涯。以有涯随无涯，殆已。</subtitle><id>http://feed.cnblogs.com/blog/u/85203/rss</id><updated>2012-05-15T05:43:44Z</updated><author><name>Fish Li</name><uri>http://www.cnblogs.com/fish-li/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/fish-li/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/85203/rss"/><entry><id>http://www.cnblogs.com/fish-li/archive/2012/05/07/2486840.html</id><title type="text">细说ASP.NET Windows身份认证</title><summary type="text">上篇博客我谈到了一些关于ASP.NET Forms身份认证方面的话题，这次的博客将主要介绍ASP.NET Windows身份认证。Forms身份认证虽然使用广泛，不过，如果是在 Windows Active Directory 的环境中使用ASP.NET，那么使用Windows身份认证也会比较方便。方便性表现为：我们不用再设计登录页面，不用编写登录验证逻辑。而且使用Windows身份认证会有更好的安全保障。认识ASP.NET Windows身份认证要使用Windows身份认证模式，需要在web.config设置：&lt;authentication mode="Windows&amp;quo</summary><published>2012-05-07T00:27:00Z</published><updated>2012-05-07T00:27:00Z</updated><author><name>Fish Li</name><uri>http://www.cnblogs.com/fish-li/</uri></author><link rel="alternate" href="http://www.cnblogs.com/fish-li/archive/2012/05/07/2486840.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/fish-li/archive/2012/05/07/2486840.html"/><content type="html">&lt;p&gt;&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/04/15/2450571.html" target="_blank"&gt;上篇博客&lt;/a&gt;我谈到了一些关于ASP.NET Forms身份认证方面的话题，这次的博客将主要介绍ASP.NET Windows身份认证。&lt;/p&gt;&lt;p&gt;Forms身份认证虽然使用广泛，不过，如果是在 Windows Active Directory 的环境中使用ASP.NET，那么使用Windows身份认证也会比较方便。方便性表现为：我们不用再设计登录页面，不用编写登录验证逻辑。而且使用Windows身份认证会有更好的安全保障。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;认识ASP.NET Windows身份认证&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;要使用Windows身份认证模式，需要在web.config设置：&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;authentication &lt;/span&gt;&lt;span style="color:red"&gt;mode&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;Windows&lt;/span&gt;" &lt;span style="color:blue"&gt;/&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;Windows身份认证做为ASP.NET的默认认证方式，与Forms身份认证在许多基础方面是一样的。&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/04/15/2450571.html" target="_blank"&gt;上篇博客&lt;/a&gt;我说过：&lt;b&gt;我认为ASP.NET的身份认证的最核心部分其实就是HttpContext.User这个属性所指向的对象。&lt;/b&gt;在接下来的部分，我将着重分析这个对象在二种身份认证中有什么差别。&lt;/p&gt;&lt;p&gt;在ASP.NET身份认证过程中，IPrincipal和IIdentity这二个接口有着非常重要的作用。前者定义用户对象的基本功能，后者定义标识对象的基本功能，不同的身份认证方式得到的这二个接口的实例也是不同的。&lt;/p&gt;&lt;p&gt;ASP.NET Windows身份认证是由WindowsAuthenticationModule实现的。WindowsAuthenticationModule在ASP.NET管线的AuthenticateRequest事件中，使用从IIS传递到ASP.NET的Windows访问令牌(Token)创建一个WindowsIdentity对象，Token通过调用context.WorkerRequest.GetUserToken()获得，然后再根据WindowsIdentity 对象创建WindowsPrincipal对象，然后把它赋值给HttpContext.User。&lt;/p&gt;&lt;p&gt;在Forms身份认证中，我们需要创建登录页面，让用户提交用户名和密码，然后检查用户名和密码的正确性，接下来创建一个包含FormsAuthenticationTicket对象的登录Cookie供后续请求使用。FormsAuthenticationModule在ASP.NET管线的AuthenticateRequest事件中，解析登录Cookie并创建一个包含FormsIdentity的GenericPrincipal对象，然后把它赋值给HttpContext.User。&lt;/p&gt;&lt;p&gt;上面二段话简单了概括了二种身份认证方式的工作方式。&lt;br /&gt;我们可以发现它们存在以下差别：&lt;br /&gt;1. Forms身份认证需要Cookie表示登录状态，Windows身份认证则依赖于IIS&lt;br /&gt;2. Windows身份认证不需要我们设计登录页面，不用编写登录验证逻辑，因此更容易使用。&lt;/p&gt;&lt;p&gt;在授权阶段，UrlAuthorizationModule仍然会根据当前用户检查将要访问的资源是否得到许可。接下来，FileAuthorizationModule检查 HttpContext.User.Identity 属性中的 IIdentity 对象是否是 WindowsIdentity 类的一个实例。如果 IIdentity 对象不是 WindowsIdentity 类的一个实例，则 FileAuthorizationModule 类停止处理。如果存在 WindowsIdentity 类的一个实例，则 FileAuthorizationModule 类调用 AccessCheck Win32 函数（通过 P/Invoke）来确定是否授权经过身份验证的客户端访问请求的文件。如果该文件的安全描述符的随机访问控制列表 (DACL) 中至少包含一个 Read 访问控制项 (ACE)，则允许该请求继续。否则，FileAuthorizationModule 类调用 HttpApplication.CompleteRequest 方法并将状态码 401 返回到客户端。 &lt;/p&gt;&lt;p&gt;在Windows身份认证中，验证工作主要是由IIS实现的，WindowsAuthenticationModule其实只是负责创建WindowsPrincipal和WindowsIdentity而已。顺便介绍一下：Windows 身份验证又分为“NTLM 身份验证”和“Kerberos v5 身份验证”二种，关于这二种Windows身份认证的更多说明可查看MSDN技术文章：&lt;a href="http://msdn.microsoft.com/zh-cn/library/ff647076.aspx" target="_blank"&gt;解释：ASP.NET 2.0 中的 Windows 身份验证&lt;/a&gt;。在我看来，IIS最终使用哪种Windows身份认证方式并不影响我们的开发过程，因此本文不会讨论这个话题。&lt;/p&gt;&lt;p&gt;根据我的实际经验来看，使用Windows身份认证时，主要的开发工作将是根据登录名从Active Directory获取用户信息。因为，此时不需要我们再设计登录过程，IIS与ASP.NET已经为我们准备好了WindowsPrincipal和WindowsIdentity这二个与用户身份相关的对象。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;访问 Active Directory&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;我们通常使用LDAP协议来访问Active Directory，在.net framework中提供了DirectoryEntry和DirectorySearcher这二个类型让我们可以方便地从托管代码中访问 Active Directory 域服务。&lt;/p&gt;&lt;p&gt;如果我们要在"test.corp”这个域中搜索某个用户信息，我们可以使用下面的语句构造一个DirectoryEntry对象：&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:#2b91af"&gt;DirectoryEntry &lt;/span&gt;entry &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DirectoryEntry&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"LDAP://test.corp"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;&lt;p&gt;在这段代码中，我采用硬编码的方式把域名写进了代码。&lt;br /&gt;我们如何知道当前电脑所使用的是哪个域名呢？&lt;br /&gt;答案是：查看“我的电脑”的属性对话框：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012050111043131.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;注意：这个域名不一定与System.Environment.UserDomainName相同。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;除了可以查看“我的电脑”的属性对话框外，我们还可以使用代码的方式获取当前电脑所使用的域名：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;private static string &lt;/span&gt;GetDomainName()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;// 注意：这段代码需要在Windows XP及较新版本的操作系统中才能正常运行。&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#2b91af"&gt;SelectQuery &lt;/span&gt;query &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;SelectQuery&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"Win32_ComputerSystem"&lt;/span&gt;);&lt;br/&gt;    &lt;span style="color:blue"&gt;using&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;ManagementObjectSearcher &lt;/span&gt;searcher &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ManagementObjectSearcher&lt;/span&gt;(query) ) {&lt;br/&gt;        &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;ManagementObject &lt;/span&gt;mo &lt;span style="color:blue"&gt;in &lt;/span&gt;searcher&lt;span style="color:red"&gt;.&lt;/span&gt;Get() ) {&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( (&lt;span style="color:blue"&gt;bool&lt;/span&gt;)mo[&lt;span style="color:#a31515"&gt;"partofdomain"&lt;/span&gt;] )&lt;br/&gt;                &lt;span style="color:blue"&gt;return &lt;/span&gt;mo[&lt;span style="color:#a31515"&gt;"domain"&lt;/span&gt;]&lt;span style="color:red"&gt;.&lt;/span&gt;ToString();&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;当构造了DirectorySearcher对象后，我们便可以使用DirectorySearcher来执行对Active Directory的搜索。&lt;br /&gt;我们可以使用下面的步骤来执行搜索：&lt;br /&gt;1. 设置 DirectorySearcher.Filter 指示LDAP格式筛选器，这是一个字符串。&lt;br /&gt;2. 多次调用PropertiesToLoad.Add() 设置搜索过程中要检索的属性列表。&lt;br /&gt;3. 调用FindOne() 方法获取搜索结果。&lt;/p&gt;&lt;p&gt;下面的代码演示了如何从Active Directory中搜索登录名为“fl45”的用户信息：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;static void &lt;/span&gt;Main(&lt;span style="color:blue"&gt;string&lt;/span&gt;[] args)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;Console&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="color:#2b91af"&gt;Environment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;UserDomainName);&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;Console&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="color:#2b91af"&gt;Environment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;UserName);&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;Console&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="color:#a31515"&gt;"------------------------------------------------"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;    ShowUserInfo(&lt;span style="color:#a31515"&gt;"fl45"&lt;/span&gt;, GetDomainName());&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;private static string &lt;/span&gt;AllProperties &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"name,givenName,samaccountname,mail"&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public static void &lt;/span&gt;ShowUserInfo(&lt;span style="color:blue"&gt;string &lt;/span&gt;loginName, &lt;span style="color:blue"&gt;string &lt;/span&gt;domainName)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(loginName) &lt;span style="color:red"&gt;|| &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(domainName) )&lt;br/&gt;        &lt;span style="color:blue"&gt;return&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;string&lt;/span&gt;[] properties &lt;span style="color:red"&gt;= &lt;/span&gt;AllProperties&lt;span style="color:red"&gt;.&lt;/span&gt;Split(&lt;span style="color:blue"&gt;new char&lt;/span&gt;[] { &lt;span style="color:#a31515"&gt;'\r'&lt;/span&gt;, &lt;span style="color:#a31515"&gt;'\n'&lt;/span&gt;, &lt;span style="color:#a31515"&gt;',' &lt;/span&gt;}, &lt;br/&gt;                        &lt;span style="color:#2b91af"&gt;StringSplitOptions&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;RemoveEmptyEntries);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;try &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;DirectoryEntry &lt;/span&gt;entry &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DirectoryEntry&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"LDAP://" &lt;/span&gt;&lt;span style="color:red"&gt;+ &lt;/span&gt;domainName);&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;DirectorySearcher &lt;/span&gt;search &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DirectorySearcher&lt;/span&gt;(entry);&lt;br/&gt;        search&lt;span style="color:red"&gt;.&lt;/span&gt;Filter &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"(samaccountname=" &lt;/span&gt;&lt;span style="color:red"&gt;+ &lt;/span&gt;loginName &lt;span style="color:red"&gt;+ &lt;/span&gt;&lt;span style="color:#a31515"&gt;")"&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:blue"&gt;string &lt;/span&gt;p &lt;span style="color:blue"&gt;in &lt;/span&gt;properties )&lt;br/&gt;            search&lt;span style="color:red"&gt;.&lt;/span&gt;PropertiesToLoad&lt;span style="color:red"&gt;.&lt;/span&gt;Add(p);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;SearchResult &lt;/span&gt;result &lt;span style="color:red"&gt;= &lt;/span&gt;search&lt;span style="color:red"&gt;.&lt;/span&gt;FindOne();&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( result &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) {&lt;br/&gt;            &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:blue"&gt;string &lt;/span&gt;p &lt;span style="color:blue"&gt;in &lt;/span&gt;properties ) {&lt;br/&gt;                &lt;span style="color:#2b91af"&gt;ResultPropertyValueCollection &lt;/span&gt;collection &lt;span style="color:red"&gt;= &lt;/span&gt;result&lt;span style="color:red"&gt;.&lt;/span&gt;Properties[p];&lt;br/&gt;                &lt;span style="color:blue"&gt;for&lt;/span&gt;( &lt;span style="color:blue"&gt;int &lt;/span&gt;i &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;; i &lt;span style="color:red"&gt;&amp;lt; &lt;/span&gt;collection&lt;span style="color:red"&gt;.&lt;/span&gt;Count; i&lt;span style="color:red"&gt;++ &lt;/span&gt;)&lt;br/&gt;                    &lt;span style="color:#2b91af"&gt;Console&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;WriteLine(p &lt;span style="color:red"&gt;+ &lt;/span&gt;&lt;span style="color:#a31515"&gt;": " &lt;/span&gt;&lt;span style="color:red"&gt;+ &lt;/span&gt;collection[i]);&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;catch&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;Exception &lt;/span&gt;ex ) {&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;Console&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;WriteLine(ex&lt;span style="color:red"&gt;.&lt;/span&gt;ToString());&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;结果如下：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012050111045790.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;在前面的代码，我在搜索Active Directory时，只搜索了"name,givenName,samaccountname,mail"这4个属性。然而，LDAP还支持更多的属性，我们可以使用下面的代码查看更多的用户信息：&lt;a href="javascript:void(0);" codeId="pre-AllProperties"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;private static string &lt;/span&gt;AllProperties &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;@"&lt;br/&gt;homemdb&lt;br/&gt;distinguishedname&lt;br/&gt;countrycode&lt;br/&gt;cn&lt;br/&gt;lastlogoff&lt;br/&gt;mailnickname&lt;br/&gt;dscorepropagationdata&lt;br/&gt;msexchhomeservername&lt;br/&gt;msexchmailboxsecuritydescriptor&lt;br/&gt;msexchalobjectversion&lt;br/&gt;usncreated&lt;br/&gt;objectguid&lt;br/&gt;whenchanged&lt;br/&gt;memberof&lt;br/&gt;msexchuseraccountcontrol&lt;br/&gt;accountexpires&lt;br/&gt;displayname&lt;br/&gt;primarygroupid&lt;br/&gt;badpwdcount&lt;br/&gt;objectclass&lt;br/&gt;instancetype&lt;br/&gt;objectcategory&lt;br/&gt;samaccounttype&lt;br/&gt;whencreated&lt;br/&gt;lastlogon&lt;br/&gt;useraccountcontrol&lt;br/&gt;physicaldeliveryofficename&lt;br/&gt;samaccountname&lt;br/&gt;usercertificate&lt;br/&gt;givenname&lt;br/&gt;mail&lt;br/&gt;userparameters&lt;br/&gt;adspath&lt;br/&gt;homemta&lt;br/&gt;msexchmailboxguid&lt;br/&gt;pwdlastset&lt;br/&gt;logoncount&lt;br/&gt;codepage&lt;br/&gt;name&lt;br/&gt;usnchanged&lt;br/&gt;legacyexchangedn&lt;br/&gt;proxyaddresses&lt;br/&gt;department&lt;br/&gt;userprincipalname&lt;br/&gt;badpasswordtime&lt;br/&gt;objectsid&lt;br/&gt;sn&lt;br/&gt;mdbusedefaults&lt;br/&gt;telephonenumber&lt;br/&gt;showinaddressbook&lt;br/&gt;msexchpoliciesincluded&lt;br/&gt;textencodedoraddress&lt;br/&gt;lastlogontimestamp&lt;br/&gt;company&lt;br/&gt;"&lt;/span&gt;;&lt;br/&gt;&lt;p&gt;&lt;strong&gt;在ASP.NET中访问Active Directory&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;前面我在一个控制台程序中演示了访问Active Directory的方法，通过示例我们可以看到：在代码中，我用Environment.UserName就可以得到当前用户的登录名。然而，如果是在ASP.NET程序中，访问Environment.UserName就&lt;b class="redText"&gt;很有可能&lt;/b&gt;得不到真正用户登录名。因为：Environment.UserName是使用WIN32API中的GetUserName获取线程相关的用户名，但ASP.NET运行在IIS中，线程相关的用户名就不一定是客户端的用户名了。不过，ASP.NET可以模拟用户方式运行，通过这种方式才可以得到正确的结果。关于“模拟”的话题在本文的后面部分有说明。&lt;/p&gt;&lt;p&gt;在ASP.NET中，为了能可靠的获取登录用户的登录名，我们可以使用下面的代码：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;根据指定的HttpContext对象，获取登录名。&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;/// &amp;lt;param name="context"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public static string &lt;/span&gt;GetUserLoginName(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( context &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;        &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( context&lt;span style="color:red"&gt;.&lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;IsAuthenticated &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;)&lt;br/&gt;        &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;string &lt;/span&gt;userName &lt;span style="color:red"&gt;= &lt;/span&gt;context&lt;span style="color:red"&gt;.&lt;/span&gt;User&lt;span style="color:red"&gt;.&lt;/span&gt;Identity&lt;span style="color:red"&gt;.&lt;/span&gt;Name;&lt;br/&gt;    &lt;span style="color:green"&gt;// 此时userName的格式为：UserDomainName\LoginName&lt;br/&gt;    // 我们只需要后面的LoginName就可以了。&lt;br/&gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;[] array &lt;span style="color:red"&gt;= &lt;/span&gt;userName&lt;span style="color:red"&gt;.&lt;/span&gt;Split(&lt;span style="color:blue"&gt;new char&lt;/span&gt;[] { &lt;span style="color:#a31515"&gt;'\\' &lt;/span&gt;}, &lt;span style="color:#2b91af"&gt;StringSplitOptions&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;RemoveEmptyEntries);&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( array&lt;span style="color:red"&gt;.&lt;/span&gt;Length &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:purple"&gt;2 &lt;/span&gt;)&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;array[&lt;span style="color:purple"&gt;1&lt;/span&gt;];&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;在ASP.NET中使用Windows身份认证时，IIS和WindowsAuthenticationModule已经做了许多验证用户的相关工作，虽然我们可以使用前面的代码获取到用户的登录名，但用户的其它信息即需要我们自己来获取。在实际使用Windows身份认证时，我们要做的事：基本上就是从Active Directory中根据用户的登录名获取所需的各种信息。&lt;/p&gt;&lt;P&gt;比如：我的程序在运行时，还需要使用以下与用户相关的信息：&lt;/P&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public sealed class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;UserInfo&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;GivenName;&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;FullName;&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;Email;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;p&gt;那么，我们可以使用这样的代码来获取所需的用户信息：&lt;a href="javascript:void(0);" codeId="pre-UserHelper"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public static class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;UserHelper&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;活动目录中的搜索路径，也可根据实际情况来修改这个值。&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;public static string &lt;/span&gt;DirectoryPath &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"LDAP://" &lt;/span&gt;&lt;span style="color:red"&gt;+ &lt;/span&gt;GetDomainName();&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;获取与指定HttpContext相关的用户信息&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    /// &amp;lt;param name="context"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;public static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;UserInfo &lt;/span&gt;GetCurrentUserInfo(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;string &lt;/span&gt;loginName &lt;span style="color:red"&gt;= &lt;/span&gt;GetUserLoginName(context);&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(loginName) )&lt;br/&gt;            &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;GetUserInfoByLoginName(loginName);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;根据指定的HttpContext对象，获取登录名。&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    /// &amp;lt;param name="context"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;public static string &lt;/span&gt;GetUserLoginName(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( context &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( context&lt;span style="color:red"&gt;.&lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;IsAuthenticated &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;string &lt;/span&gt;userName &lt;span style="color:red"&gt;= &lt;/span&gt;context&lt;span style="color:red"&gt;.&lt;/span&gt;User&lt;span style="color:red"&gt;.&lt;/span&gt;Identity&lt;span style="color:red"&gt;.&lt;/span&gt;Name;&lt;br/&gt;        &lt;span style="color:green"&gt;// 此时userName的格式为：UserDomainName\LoginName&lt;br/&gt;        // 我们只需要后面的LoginName就可以了。&lt;br/&gt;&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;[] array &lt;span style="color:red"&gt;= &lt;/span&gt;userName&lt;span style="color:red"&gt;.&lt;/span&gt;Split(&lt;span style="color:blue"&gt;new char&lt;/span&gt;[] { &lt;span style="color:#a31515"&gt;'\\' &lt;/span&gt;}, &lt;span style="color:#2b91af"&gt;StringSplitOptions&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;RemoveEmptyEntries);&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( array&lt;span style="color:red"&gt;.&lt;/span&gt;Length &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:purple"&gt;2 &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;array[&lt;span style="color:purple"&gt;1&lt;/span&gt;];&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;    &lt;br/&gt;&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;根据登录名查询活动目录，获取用户信息。&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    /// &amp;lt;param name="loginName"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;public static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;UserInfo &lt;/span&gt;GetUserInfoByLoginName(&lt;span style="color:blue"&gt;string &lt;/span&gt;loginName)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(loginName) )&lt;br/&gt;            &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 下面的代码将根据登录名查询用户在AD中的信息。&lt;br/&gt;        // 为了提高性能，可以在此处增加一个缓存容器(Dictionary or Hashtable)。&lt;br/&gt;&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:blue"&gt;try &lt;/span&gt;{&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;DirectoryEntry &lt;/span&gt;entry &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DirectoryEntry&lt;/span&gt;(DirectoryPath);&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;DirectorySearcher &lt;/span&gt;search &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DirectorySearcher&lt;/span&gt;(entry);&lt;br/&gt;            search&lt;span style="color:red"&gt;.&lt;/span&gt;Filter &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"(SAMAccountName=" &lt;/span&gt;&lt;span style="color:red"&gt;+ &lt;/span&gt;loginName &lt;span style="color:red"&gt;+ &lt;/span&gt;&lt;span style="color:#a31515"&gt;")"&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;            search&lt;span style="color:red"&gt;.&lt;/span&gt;PropertiesToLoad&lt;span style="color:red"&gt;.&lt;/span&gt;Add(&lt;span style="color:#a31515"&gt;"givenName"&lt;/span&gt;);&lt;br/&gt;            search&lt;span style="color:red"&gt;.&lt;/span&gt;PropertiesToLoad&lt;span style="color:red"&gt;.&lt;/span&gt;Add(&lt;span style="color:#a31515"&gt;"cn"&lt;/span&gt;);&lt;br/&gt;            search&lt;span style="color:red"&gt;.&lt;/span&gt;PropertiesToLoad&lt;span style="color:red"&gt;.&lt;/span&gt;Add(&lt;span style="color:#a31515"&gt;"mail"&lt;/span&gt;);&lt;br/&gt;            &lt;span style="color:green"&gt;// 如果还需要从AD中获取其它的用户信息，请参考ActiveDirectoryDEMO&lt;br/&gt;&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:#2b91af"&gt;SearchResult &lt;/span&gt;result &lt;span style="color:red"&gt;= &lt;/span&gt;search&lt;span style="color:red"&gt;.&lt;/span&gt;FindOne();&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( result &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) {&lt;br/&gt;                &lt;span style="color:#2b91af"&gt;UserInfo &lt;/span&gt;info &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;UserInfo&lt;/span&gt;();&lt;br/&gt;                info&lt;span style="color:red"&gt;.&lt;/span&gt;GivenName &lt;span style="color:red"&gt;= &lt;/span&gt;result&lt;span style="color:red"&gt;.&lt;/span&gt;Properties[&lt;span style="color:#a31515"&gt;"givenName"&lt;/span&gt;][&lt;span style="color:purple"&gt;0&lt;/span&gt;]&lt;span style="color:red"&gt;.&lt;/span&gt;ToString();&lt;br/&gt;                info&lt;span style="color:red"&gt;.&lt;/span&gt;FullName &lt;span style="color:red"&gt;= &lt;/span&gt;result&lt;span style="color:red"&gt;.&lt;/span&gt;Properties[&lt;span style="color:#a31515"&gt;"cn"&lt;/span&gt;][&lt;span style="color:purple"&gt;0&lt;/span&gt;]&lt;span style="color:red"&gt;.&lt;/span&gt;ToString();&lt;br/&gt;                info&lt;span style="color:red"&gt;.&lt;/span&gt;Email &lt;span style="color:red"&gt;= &lt;/span&gt;result&lt;span style="color:red"&gt;.&lt;/span&gt;Properties[&lt;span style="color:#a31515"&gt;"mail"&lt;/span&gt;][&lt;span style="color:purple"&gt;0&lt;/span&gt;]&lt;span style="color:red"&gt;.&lt;/span&gt;ToString();&lt;br/&gt;                &lt;span style="color:blue"&gt;return &lt;/span&gt;info;&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color:blue"&gt;catch &lt;/span&gt;{&lt;br/&gt;            &lt;span style="color:green"&gt;// 如果需要记录异常，请在此处添加代码。&lt;br/&gt;        &lt;/span&gt;}&lt;br/&gt;        &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;private static string &lt;/span&gt;GetDomainName()&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:green"&gt;// 注意：这段代码需要在Windows XP及较新版本的操作系统中才能正常运行。&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:#2b91af"&gt;SelectQuery &lt;/span&gt;query &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;SelectQuery&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"Win32_ComputerSystem"&lt;/span&gt;);&lt;br/&gt;        &lt;span style="color:blue"&gt;using&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;ManagementObjectSearcher &lt;/span&gt;searcher &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ManagementObjectSearcher&lt;/span&gt;(query) ) {&lt;br/&gt;            &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;ManagementObject &lt;/span&gt;mo &lt;span style="color:blue"&gt;in &lt;/span&gt;searcher&lt;span style="color:red"&gt;.&lt;/span&gt;Get() ) {&lt;br/&gt;                &lt;span style="color:blue"&gt;if&lt;/span&gt;( (&lt;span style="color:blue"&gt;bool&lt;/span&gt;)mo[&lt;span style="color:#a31515"&gt;"partofdomain"&lt;/span&gt;] )&lt;br/&gt;                    &lt;span style="color:blue"&gt;return &lt;/span&gt;mo[&lt;span style="color:#a31515"&gt;"domain"&lt;/span&gt;]&lt;span style="color:red"&gt;.&lt;/span&gt;ToString();&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;使用UserHelper的页面代码：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;html &lt;/span&gt;&lt;span style="color:red"&gt;xmlns&lt;/span&gt;&lt;span style="color:blue"&gt;="http://www.w3.org/1999/xhtml"&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;head&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;title&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;WindowsAuthentication DEMO  - http://www.cnblogs.com/fish-li/&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;title&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;head&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;body&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color:blue"&gt;if&lt;/span&gt;( Request&lt;span style="color:red"&gt;.&lt;/span&gt;IsAuthenticated ) { &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;    当前登录全名：&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;Context&lt;span style="color:red"&gt;.&lt;/span&gt;User&lt;span style="color:red"&gt;.&lt;/span&gt;Identity&lt;span style="color:red"&gt;.&lt;/span&gt;Name&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode()&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt; &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;br &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;    &lt;br/&gt;    &lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color:blue"&gt;var &lt;/span&gt;user &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;UserHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetCurrentUserInfo(Context); &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;    &lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color:blue"&gt;if&lt;/span&gt;( user &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) { &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;        用户短名：&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;user&lt;span style="color:red"&gt;.&lt;/span&gt;GivenName&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode()&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt; &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;br &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;        &lt;/span&gt;用户全名：&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;user&lt;span style="color:red"&gt;.&lt;/span&gt;FullName&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt; &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;br &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;        &lt;/span&gt;邮箱地址：&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;user&lt;span style="color:red"&gt;.&lt;/span&gt;Email&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;    &lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;    &lt;br/&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="color:blue"&gt;else &lt;/span&gt;{ &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;    当前用户还未登录。&lt;br/&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;body&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;html&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;程序运行的效果如下：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012050111052224.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;另外，还可以从Active Directory查询一个叫做memberof的属性&lt;i&gt;（它与Windows用户组无关）&lt;/i&gt;，有时候可以用它区分用户，设计与权限相关的操作。&lt;/p&gt;&lt;p&gt;在设计数据持久化的表结构时，由于此时没有“用户表”，那么我们可以直接保存用户的登录名。剩下的开发工作就与Forms身份认证没有太多的差别了。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;使用Active Directory验证用户身份&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;前面介绍了ASP.NET Windows身份认证，在这种方式下，IIS和WindowsAuthenticationModule为我们实现了用户身份认证的过程。然而，有时可能由于各种原因，需要我们以编程的方式使用Active Directory验证用户身份，比如：在WinForm程序，或者其它的验证逻辑。&lt;/p&gt;&lt;p&gt;我们不仅可以从Active Directory中查询用户信息，也可以用它来实现验证用户身份，这样便可以实现自己的登录验证逻辑。&lt;/p&gt;&lt;p&gt;不管是如何使用Active Directory，我们都需要使用DirectoryEntry和DirectorySearcher这二个对象。DirectoryEntry还提供一个构造函数可让我们输入用户名和密码：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:green"&gt;// 摘要:&lt;br/&gt;//     初始化 System.DirectoryServices.DirectoryEntry 类的新实例。&lt;br/&gt;//&lt;br/&gt;// 参数:&lt;br/&gt;//   Password:&lt;br/&gt;//     在对客户端进行身份验证时使用的密码。DirectoryEntry.Password 属性初始化为该值。&lt;br/&gt;//&lt;br/&gt;//   username:&lt;br/&gt;//     在对客户端进行身份验证时使用的用户名。DirectoryEntry.Username 属性初始化为该值。&lt;br/&gt;//&lt;br/&gt;//   Path:&lt;br/&gt;//     此 DirectoryEntry 的路径。DirectoryEntry.Path 属性初始化为该值。&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public &lt;/span&gt;DirectoryEntry(&lt;span style="color:blue"&gt;string &lt;/span&gt;path, &lt;span style="color:blue"&gt;string &lt;/span&gt;username, &lt;span style="color:blue"&gt;string &lt;/span&gt;password);&lt;br/&gt;&lt;br/&gt;&lt;p&gt;要实现自己的登录检查，就需要使用这个构造函数。&lt;br /&gt;以下是我写用WinForm写的一个登录检查的示例：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;private void &lt;/span&gt;btnLogin_Click(&lt;span style="color:blue"&gt;object &lt;/span&gt;sender, &lt;span style="color:#2b91af"&gt;EventArgs &lt;/span&gt;e)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( txtUsername&lt;span style="color:red"&gt;.&lt;/span&gt;Text&lt;span style="color:red"&gt;.&lt;/span&gt;Length &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;&lt;span style="color:red"&gt;|| &lt;/span&gt;txtPassword&lt;span style="color:red"&gt;.&lt;/span&gt;Text&lt;span style="color:red"&gt;.&lt;/span&gt;Length &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;) {&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;MessageBox&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Show(&lt;span style="color:#a31515"&gt;"用户名或者密码不能为空。"&lt;/span&gt;, &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Text, &lt;span style="color:#2b91af"&gt;MessageBoxButtons&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;OK, &lt;span style="color:#2b91af"&gt;MessageBoxIcon&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Warning);&lt;br/&gt;        &lt;span style="color:blue"&gt;return&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;string &lt;/span&gt;ldapPath &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"LDAP://" &lt;/span&gt;&lt;span style="color:red"&gt;+ &lt;/span&gt;GetDomainName();&lt;br/&gt;    &lt;span style="color:blue"&gt;string &lt;/span&gt;domainAndUsername &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Environment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;UserDomainName &lt;span style="color:red"&gt;+ &lt;/span&gt;&lt;span style="color:#a31515"&gt;"\\" &lt;/span&gt;&lt;span style="color:red"&gt;+ &lt;/span&gt;txtUsername&lt;span style="color:red"&gt;.&lt;/span&gt;Text;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;DirectoryEntry &lt;/span&gt;entry &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DirectoryEntry&lt;/span&gt;(ldapPath, domainAndUsername, txtPassword&lt;span style="color:red"&gt;.&lt;/span&gt;Text);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;DirectorySearcher &lt;/span&gt;search &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DirectorySearcher&lt;/span&gt;(entry);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;try &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;SearchResult &lt;/span&gt;result &lt;span style="color:red"&gt;= &lt;/span&gt;search&lt;span style="color:red"&gt;.&lt;/span&gt;FindOne();&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;MessageBox&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Show(&lt;span style="color:#a31515"&gt;"登录成功。"&lt;/span&gt;, &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Text, &lt;span style="color:#2b91af"&gt;MessageBoxButtons&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;OK, &lt;span style="color:#2b91af"&gt;MessageBoxIcon&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Information);&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;catch&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;Exception &lt;/span&gt;ex ) {&lt;br/&gt;        &lt;span style="color:green"&gt;// 如果用户名或者密码不正确，也会抛出异常。&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MessageBox&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Show(ex&lt;span style="color:red"&gt;.&lt;/span&gt;Message, &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Text, &lt;span style="color:#2b91af"&gt;MessageBoxButtons&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;OK, &lt;span style="color:#2b91af"&gt;MessageBoxIcon&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Stop);&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;程序运行的效果如下：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012050111054152.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;安全上下文与用户模拟&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在ASP.NET Windows身份认证环境中，与用户相关的安全上下文对象保存在HttpContext.User属性中，是一个类型为WindowsPrincipal的对象，我们还可以访问HttpContext.User.Identity来获取经过身份认证的用户标识，它是一个WindowsIdentity类型的对象。&lt;/p&gt;&lt;p&gt;在.NET Framework中，我们可以通过WindowsIdentity.GetCurrent()获取与当前线程相关的WindowsIdentity对象，这种方法获取的是当前运行的Win32线程的安全上下文标识。由于ASP.NET运行在IIS进程中，因此ASP.NET线程的安全标识其实是从IIS的进程中继承的，所以此时用二种方法得到的WindowsIdentity对象其实是不同的。&lt;/p&gt;&lt;p&gt;在Windows操作系统中，许多权限检查都是基于Win32线程的安全上下文标识，于是前面所说的二种WindowsIdentity对象会造成编程模型的不一致问题，为了解决这个问题，ASP.NET提供了“模拟”功能，&lt;b&gt;允许线程以特定的Windows帐户的安全上下文来访问资源。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;为了能更好的理解模拟的功能，我准备了一个示例（ShowWindowsIdentity.ashx）：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ShowWindowsIdentity &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;{&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color:blue"&gt;public void &lt;/span&gt;ProcessRequest (&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context) {&lt;br/&gt;        &lt;span style="color:green"&gt;// 要观察【模拟】的影响，&lt;br/&gt;        // 可以启用，禁止web.config中的设置：&amp;lt;identity impersonate="true"/&amp;gt;&lt;br/&gt;        &lt;br/&gt;        &lt;/span&gt;context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;ContentType &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"text/plain"&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#2b91af"&gt;Environment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;UserDomainName &lt;span style="color:red"&gt;+ &lt;/span&gt;&lt;span style="color:#a31515"&gt;"\\" &lt;/span&gt;&lt;span style="color:red"&gt;+ &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Environment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;UserName &lt;span style="color:red"&gt;+ &lt;/span&gt;&lt;span style="color:#a31515"&gt;"\r\n"&lt;/span&gt;);&lt;br/&gt;        &lt;br/&gt;        &lt;span style="color:#2b91af"&gt;WindowsPrincipal &lt;/span&gt;winPrincipal &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;WindowsPrincipal&lt;/span&gt;)&lt;span style="color:#2b91af"&gt;HttpContext&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Current&lt;span style="color:red"&gt;.&lt;/span&gt;User;&lt;br/&gt;        context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Format(&lt;span style="color:#a31515"&gt;"HttpContext.Current.User.Identity: {0}, {1}\r\n"&lt;/span&gt;, &lt;br/&gt;                winPrincipal&lt;span style="color:red"&gt;.&lt;/span&gt;Identity&lt;span style="color:red"&gt;.&lt;/span&gt;AuthenticationType, winPrincipal&lt;span style="color:red"&gt;.&lt;/span&gt;Identity&lt;span style="color:red"&gt;.&lt;/span&gt;Name));&lt;br/&gt;        &lt;br/&gt;        &lt;span style="color:#2b91af"&gt;WindowsPrincipal &lt;/span&gt;winPrincipal2 &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;WindowsPrincipal&lt;/span&gt;)&lt;span style="color:#2b91af"&gt;Thread&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;CurrentPrincipal;&lt;br/&gt;        context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Format(&lt;span style="color:#a31515"&gt;"Thread.CurrentPrincipal.Identity: {0}, {1}\r\n"&lt;/span&gt;,&lt;br/&gt;                winPrincipal2&lt;span style="color:red"&gt;.&lt;/span&gt;Identity&lt;span style="color:red"&gt;.&lt;/span&gt;AuthenticationType, winPrincipal2&lt;span style="color:red"&gt;.&lt;/span&gt;Identity&lt;span style="color:red"&gt;.&lt;/span&gt;Name));&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;WindowsIdentity &lt;/span&gt;winId &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;WindowsIdentity&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetCurrent();&lt;br/&gt;        context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Format(&lt;span style="color:#a31515"&gt;"WindowsIdentity.GetCurrent(): {0}, {1}"&lt;/span&gt;,&lt;br/&gt;                winId&lt;span style="color:red"&gt;.&lt;/span&gt;AuthenticationType, winId&lt;span style="color:red"&gt;.&lt;/span&gt;Name));&lt;br/&gt;    }&lt;br/&gt;&lt;p&gt;首先，在web.config中设置:&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;authentication &lt;/span&gt;&lt;span style="color:red"&gt;mode&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;Windows&lt;/span&gt;" &lt;span style="color:blue"&gt;/&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;&lt;b&gt;注意：要把网站部署在IIS中，否则看不出效果。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;此时，访问ShowWindowsIdentity.ashx，将看到如下图所示的结果：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012050111060137.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;现在修改一下web.config中设置：（&lt;b class="redText"&gt;注意：后面加了一句配置&lt;/b&gt;）&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;authentication &lt;/span&gt;&lt;span style="color:red"&gt;mode&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;Windows&lt;/span&gt;" &lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;identity &lt;/span&gt;&lt;span style="color:red"&gt;impersonate&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;true&lt;/span&gt;"&lt;span style="color:blue"&gt;/&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;此时，访问ShowWindowsIdentity.ashx，将看到如下图所示的结果：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012050111062316.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;说明：&lt;br /&gt;1. FISH-SRV2003是我的计算机名。&lt;i&gt;它在一个没有域的环境中。&lt;/i&gt;&lt;br /&gt;2. fish-li是我的一个Windows帐号的登录名。&lt;br /&gt;3. 网站部署在IIS6中，进程以NETWORK SERVICE帐号运行。&lt;br /&gt;4. 打开网页时，我输入的用户名是fish-li&lt;/p&gt;&lt;p&gt;&lt;b&gt;前面二张图片的差异之处其实也就是ASP.NET的“模拟”所发挥的功能。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;关于模拟，我想说四点：&lt;br /&gt;1. 在ASP.NET中，我们应该访问HttpContext.User.Identity获取当前用户标识，那么就不存在问题（&lt;b&gt;此时可以不需要模拟&lt;/b&gt;），例如FileAuthorizationModule就是这样处理的。&lt;br /&gt;2. 模拟只是在ASP.NET应用程序访问Windows系统资源时需要应用Windows的安全检查功能才会有用。&lt;br /&gt;3. Forms身份认证也能配置模拟功能，但只能模拟一个Windows帐户。&lt;br /&gt;4. 绝大多数情况下是不需要模拟的。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;在IIS中配置Windows身份认证&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;与使用Forms身份认证的程序不同，使用Windows身份认证的程序需要额外的配置步骤。这个小节将主要介绍在IIS中配置Windows身份认证，我将常用的IIS6和IIS7.5为例分别介绍这些配置。&lt;/p&gt;&lt;p&gt;&lt;b&gt;IIS6的配置&lt;/b&gt; 请参考下图：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012050111064118.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;IIS7.5的配置&lt;/b&gt; 请参考下图：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012050111065895.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;注意：Windows身份认证是需要安装的，方法请参考下图：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012050111071851.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;关于浏览器的登录对话框问题&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;当我们用浏览器访问一个使用Windows身份认证的网站时，浏览器都会弹出一个对话框（左IE，右Safari）：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012050111073894.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;此时，要求我们输入Windows的登录帐号，然后交给IIS验证身份。&lt;/p&gt;&lt;p&gt;首次弹出这个对话框很正常：因为程序要验证用户的身份。&lt;br /&gt;然而，每次关闭浏览器下次重新打开页面时，又会出现此对话框，此时感觉就很不方便了。&lt;br /&gt;虽然有些浏览器能记住用户名和密码，但我发现FireFox，Opera，Chrome仍然会弹出这个对话框，等待我们点击确定，只有Safari才不会打扰用户直接打开网页。IE的那个“记住我的密码”复选框完全是个摆设，它根本不会记住密码！&lt;/p&gt;&lt;p&gt;因此，我所试过的所有浏览器中，只有Safari是最人性化的。&lt;br /&gt;虽然在默认情况下，虽然IE不会记住密码，每次都需要再次输入。&lt;br /&gt;不过，&lt;b&gt;IE却可以支持不提示用户输入登录帐号而直接打开网页，&lt;/b&gt;此时IE将使用用户的当前Windows登录帐号传递给IIS验证身份。&lt;/p&gt;&lt;p&gt;要让IE打开一个Windows身份认证的网站不提示登录对话框，必须满足以下条件：&lt;br /&gt;1. 必须在 IIS 的 Web 站点属性中启用 Windows 集成身份验证。&lt;br /&gt;2. 客户端和Web服务器都必须在基于Microsoft Windows的同一个域内。&lt;br /&gt;3. Internet Explorer 必须把所请求的 URL 视为 Intranet（本地）。&lt;br /&gt;4. Internet Explorer 的 Intranet 区域的安全性设置必须设为“只在 Intranet 区域自动登录”。&lt;br /&gt;5. 请求Web页的用户必须具有访问该Web页以及该Web页中引用的所有对象的适当的文件系统(NTFS)权限。&lt;br /&gt;6. 用户必须用域帐号登录到Windows 。&lt;/p&gt;&lt;p&gt;在这几个条件中，如果网站是在一个Windows域中运行，除了第3条可能不满足外，其它条件应该都容易满足（第4条是默认值）。因此，要让IE不提示输入登录帐号，只要确保第3条满足就可以了。下面的图片演示了如何完成这个配置：&lt;b&gt;（注意：配置方法也适合用域名访问的情况）&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012050111075620.png" alt="" /&gt;&lt;/p&gt;&lt;P&gt;&lt;/p&gt;&lt;p&gt;另外，除了在IE中设置Intranet外，还可以在访问网站时，&lt;b&gt;用计算机名代替IP地址或者域名&lt;/b&gt;，那么IE始终认为是在访问Intranet内的网站，此时也不会弹出登录对话框。&lt;/p&gt;&lt;p&gt;在此，我想再啰嗦三句：&lt;br /&gt;1. IE在集成Windows身份认证时，虽然不提示登录对话框，但是不表示不安全，它会自动传递登录凭据。&lt;br /&gt;2. 这种行为只有IE才能支持。&lt;i&gt;（其它的浏览器只是会记住密码，在实现上其实是不一样的。）&lt;/i&gt;&lt;br /&gt;3. 集成Windows身份认证，也只适合在Intranet的环境中使用。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;在客户端代码中访问Windows身份认证的页面&lt;/strong&gt;&lt;/p&gt;&lt;P&gt;在上篇博客中，我演示了如何用代码访问一个使用Forms身份认证的网站中的受限页面，方法是使用CookieContainer对象接收服务端生的登录Cookie。然而，在Windows身份认证的网站中，身份验证的过程发生在IIS中，而且根本不使用Cookie保存登录状态，而是需要在请求时发送必要的身份验证信息。&lt;/P&gt;&lt;p&gt;在使用代码做为客户端访问Web服务器时，我们仍然需要使用HttpWebRequest对象。为了能让HttpWebRequest在访问IIS时发送必要的身份验证信息，HttpWebRequest提供二个属性都可以完成这个功能：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:green"&gt;// 获取或设置请求的身份验证信息。&lt;br/&gt;//&lt;br/&gt;// 返回结果:&lt;br/&gt;//     包含与该请求关联的身份验证凭据的 System.Net.ICredentials。默认为 null。&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public override &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ICredentials &lt;/span&gt;Credentials { &lt;span style="color:blue"&gt;get&lt;/span&gt;; &lt;span style="color:blue"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:green"&gt;// 获取或设置一个 System.Boolean 值，该值控制默认凭据是否随请求一起发送。&lt;br/&gt;//&lt;br/&gt;// 返回结果:&lt;br/&gt;//     如果使用默认凭据，则为 true；否则为 false。默认值为 false。&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public override bool &lt;/span&gt;UseDefaultCredentials { &lt;span style="color:blue"&gt;get&lt;/span&gt;; &lt;span style="color:blue"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;p&gt;下面是我准备的完整的示例代码&lt;b class="redText"&gt;（注意代码中的注释）&lt;/b&gt;：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;static void &lt;/span&gt;Main(&lt;span style="color:blue"&gt;string&lt;/span&gt;[] args)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;try &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color:green"&gt;// 请把WindowsAuthWebSite1这个网站部署在IIS中，&lt;br/&gt;        // 开启Windows认证方式，并禁止匿名用户访问。&lt;br/&gt;        // 然后修改下面的访问地址。&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpWebRequest &lt;/span&gt;request &lt;span style="color:red"&gt;= &lt;br/&gt;            &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;HttpWebRequest&lt;/span&gt;)&lt;span style="color:#2b91af"&gt;WebRequest&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Create(&lt;span style="color:#a31515"&gt;"http://localhost:33445/Default.aspx"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 下面三行代码，启用任意一行都是可以的。&lt;br/&gt;        &lt;/span&gt;request&lt;span style="color:red"&gt;.&lt;/span&gt;UseDefaultCredentials &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;true&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color:green"&gt;//request.Credentials = CredentialCache.DefaultCredentials;&lt;br/&gt;        //request.Credentials = CredentialCache.DefaultNetworkCredentials;&lt;br/&gt;        // 如果上面的三行代码全被注释了，那么将会看到401的异常信息。&lt;br/&gt;&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:blue"&gt;using&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;HttpWebResponse &lt;/span&gt;response &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;HttpWebResponse&lt;/span&gt;)request&lt;span style="color:red"&gt;.&lt;/span&gt;GetResponse() ) {&lt;br/&gt;            &lt;span style="color:blue"&gt;using&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;StreamReader &lt;/span&gt;sr &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;StreamReader&lt;/span&gt;(response&lt;span style="color:red"&gt;.&lt;/span&gt;GetResponseStream()) ) {&lt;br/&gt;                &lt;span style="color:#2b91af"&gt;Console&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;WriteLine(sr&lt;span style="color:red"&gt;.&lt;/span&gt;ReadToEnd());&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;catch&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;WebException &lt;/span&gt;wex ) {&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;Console&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="color:#a31515"&gt;"====================================="&lt;/span&gt;);&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;Console&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="color:#a31515"&gt;"异常发生了。"&lt;/span&gt;);&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;Console&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="color:#a31515"&gt;"====================================="&lt;/span&gt;);&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;Console&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;WriteLine(wex&lt;span style="color:red"&gt;.&lt;/span&gt;Message);&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;其实关键部分还是设置UseDefaultCredentials或者Credentials，代码中的三种方法是有效的。&lt;br /&gt;这三种方法的差别：&lt;br /&gt;1. Credentials = CredentialCache.DefaultCredentials; 表示在发送请求会带上当前用户的身份验证凭据。&lt;br /&gt;2. UseDefaultCredentials = true; 此方法在内部会调用前面的方法，因此与前面的方法是一样的。&lt;br /&gt;3. Credentials = CredentialCache.DefaultNetworkCredentials; 是在.NET 2.0中引用的新方法。&lt;/p&gt;&lt;p&gt;关于DefaultCredentials和DefaultNetworkCredentials的更多差别，请看我整理的表格：&lt;/p&gt;&lt;table cellpadding="2" cellspacing="1" class="MyTable" &gt;&lt;thead&gt;&lt;tr&gt;&lt;td&gt;Credentials属性&lt;/td&gt;&lt;td&gt;申明类型&lt;/td&gt;&lt;td&gt;实例类型&lt;/td&gt;&lt;td&gt;.NET支持版本&lt;/td&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tr&gt;&lt;td&gt;DefaultCredentials&lt;/td&gt;&lt;td&gt;ICredentials&lt;/td&gt;&lt;td&gt;SystemNetworkCredential&lt;/td&gt;&lt;td&gt;从1.0开始&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;DefaultNetworkCredentials&lt;/td&gt;&lt;td&gt;NetworkCredential&lt;/td&gt;&lt;td&gt;SystemNetworkCredential&lt;/td&gt;&lt;td&gt;从2.0开始&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;p&gt;三个类型的继承关系：&lt;br /&gt;1. NetworkCredential实现了ICredentials接口，&lt;br /&gt;2. SystemNetworkCredential继承自NetworkCredential。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;在结束这篇博客之前，我想我应该感谢新蛋。&lt;br /&gt;在新蛋的网络环境中，让我学会了使用Windows身份认证。&lt;br /&gt;除了感谢之外，我现在还特别怀念 fl45 这个登录名......&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://files.cnblogs.com/fish-li/AspnetLogin.cab.7z"&gt;点击此处下载示例代码&lt;/a&gt;&lt;/p&gt;&lt;div class="articleFooter"&gt;&lt;p&gt;如果，您认为阅读这篇博客让您有些收获，不妨点击一下右下角的&lt;a id="btnRecommendMyBlog" href="javascript:void(0);"&gt;【&lt;b&gt;推荐&lt;/b&gt;】&lt;/a&gt;按钮。&lt;br /&gt;如果，您希望更容易地发现我的新博客，不妨点击一下右下角的&lt;a id="btnFollowFishLi" href="javascript:void(0);"&gt;【&lt;b&gt;关注 Fish Li&lt;/b&gt;】&lt;/a&gt;。&lt;br /&gt;因为，我的写作热情也离不开您的肯定支持。&lt;/p&gt;&lt;p&gt;感谢您的阅读，如果您对我的博客所讲述的内容有兴趣，请继续关注我的后续博客，我是Fish Li 。&lt;span class="icon_smile"&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/fish-li/aggbug/2486840.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/05/07/2486840.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/fish-li/archive/2012/04/15/2450571.html</id><title type="text">细说ASP.NET Forms身份认证</title><summary type="text">用户登录是个很常见的业务需求，在ASP.NET中，这个过程被称为身份认证。由于很常见，因此，我认为把这块内容整理出来，与大家分享应该是件有意义的事。在开发ASP.NET项目中，我们最常用的是Forms认证，也叫【表单认证】。这种认证方式既可以用于局域网环境，也可用于互联网环境，因此，它有着非常广泛的使用。这篇博客主要讨论的话题是：ASP.NET Forms 身份认证。有一点我要申明一下：在这篇博客中，不会涉及ASP.NET的登录系列控件以及membership的相关话题，我只想用比较原始的方式来说明在ASP.NET中是如何实现身份认证的过程。ASP.NET身份认证基础在开始今天的博客之前，我想</summary><published>2012-04-15T11:59:00Z</published><updated>2012-04-15T11:59:00Z</updated><author><name>Fish Li</name><uri>http://www.cnblogs.com/fish-li/</uri></author><link rel="alternate" href="http://www.cnblogs.com/fish-li/archive/2012/04/15/2450571.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/fish-li/archive/2012/04/15/2450571.html"/><content type="html">&lt;p&gt;用户登录是个很常见的业务需求，在ASP.NET中，这个过程被称为身份认证。由于很常见，因此，我认为把这块内容整理出来，与大家分享应该是件有意义的事。&lt;/p&gt;&lt;p&gt;在开发ASP.NET项目中，我们最常用的是Forms认证，也叫【表单认证】。这种认证方式既可以用于局域网环境，也可用于互联网环境，因此，它有着非常广泛的使用。这篇博客主要讨论的话题是：ASP.NET Forms 身份认证。&lt;/p&gt;&lt;p&gt;&lt;b&gt;有一点我要申明一下：&lt;/b&gt;在这篇博客中，不会涉及ASP.NET的登录系列控件以及membership的相关话题，我只想用比较原始的方式来说明在ASP.NET中是如何实现身份认证的过程。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;ASP.NET身份认证基础&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在开始今天的博客之前，我想有二个最基础的问题首先要明确：&lt;br /&gt;1. 如何判断当前请求是一个已登录用户发起的？&lt;br /&gt;2. 如何获取当前登录用户的登录名？&lt;/p&gt;&lt;p&gt;在标准的ASP.NET身份认证方式中，上面二个问题的答案是：&lt;br /&gt;1. 如果Request.IsAuthenticated为true，则表示是一个已登录用户。&lt;br /&gt;2. 如果是一个已登录用户，访问HttpContext.User.Identity.Name可获取登录名（都是实例属性）。&lt;/p&gt;&lt;p&gt;接下来，本文将会围绕上面二个问题展开，请继续阅读。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;ASP.NET身份认证过程&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在ASP.NET中，整个身份认证的过程其实可分为二个阶段：认证与授权。&lt;br /&gt;1. 认证阶段：识别当前请求的用户是不是一个可识别（的已登录）用户。&lt;br /&gt;2. 授权阶段：是否允许当前请求访问指定的资源。&lt;/p&gt;&lt;p&gt;这二个阶段在ASP.NET管线中用AuthenticateRequest和AuthorizeRequest事件来表示。&lt;br /&gt;在认证阶段，ASP.NET会检查当前请求，根据web.config设置的认证方式，尝试构造HttpContext.User对象供我们在后续的处理中使用。在授权阶段，会检查当前请求所访问的资源是否允许访问，因为有些受保护的页面资源可能要求特定的用户或者用户组才能访问。所以，即使是一个已登录用户，也有可能会不能访问某些页面。当发现用户不能访问某个页面资源时，ASP.NET会将请求重定向到登录页面。&lt;/p&gt;&lt;p&gt;受保护的页面与登录页面我们都可以在web.config中指定，具体方法可参考后文。&lt;/p&gt;&lt;p&gt;在ASP.NET中，Forms认证是由FormsAuthenticationModule实现的，URL的授权检查是由UrlAuthorizationModule实现的。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;如何实现登录与注销&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;前面我介绍了可以使用Request.IsAuthenticated来判断当前用户是不是一个已登录用户，那么这一过程又是如何实现的呢？&lt;/p&gt;&lt;p&gt;为了回答这个问题，我准备了一个简单的示例页面，代码如下：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;fieldset&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;legend&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;用户状态&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;legend&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;form &lt;/span&gt;&lt;span style="color:red"&gt;action&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;= Request.RawUrl &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;" &lt;/span&gt;&lt;span style="color:red"&gt;method&lt;/span&gt;&lt;span style="color:blue"&gt;="post"&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color:blue"&gt;if&lt;/span&gt;( Request&lt;span style="color:red"&gt;.&lt;/span&gt;IsAuthenticated ) { &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;        当前用户已登录，登录名：&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;Context&lt;span style="color:red"&gt;.&lt;/span&gt;User&lt;span style="color:red"&gt;.&lt;/span&gt;Identity&lt;span style="color:red"&gt;.&lt;/span&gt;Name&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt; &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;br &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;            &lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="submit" &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="Logon" &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="退出" /&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="color:blue"&gt;else &lt;/span&gt;{ &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;        &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;b&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;当前用户还未登录。&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;b&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;            &lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;form&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;fieldset&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;页面显示效果如下：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012041519495950.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;根据前面的代码，我想现在能看到这个页面显示也是正确的，是的，我目前还没有登录&lt;i&gt;（根本还没有实现这个功能）&lt;/i&gt;。&lt;/p&gt;&lt;p&gt;下面我再加点代码来实现用户登录。页面代码：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;fieldset&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;legend&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;普通登录&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;legend&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;form &lt;/span&gt;&lt;span style="color:red"&gt;action&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;= Request.RawUrl &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;" &lt;/span&gt;&lt;span style="color:red"&gt;method&lt;/span&gt;&lt;span style="color:blue"&gt;="post"&amp;gt;&lt;br/&gt;    &lt;/span&gt;登录名：&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text" &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="loginName" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;: &lt;span style="color:blue"&gt;200px" &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="Fish" /&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="submit" &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="NormalLogin" &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="登录" /&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;form&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;fieldset&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;现在页面的显示效果：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012041519504267.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;登录与退出登录的实现代码：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public void &lt;/span&gt;Logon()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;FormsAuthentication&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;SignOut();&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public void &lt;/span&gt;NormalLogin()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;// -----------------------------------------------------------------&lt;br/&gt;    // 注意：演示代码为了简单，这里不检查用户名与密码是否正确。&lt;br/&gt;    // -----------------------------------------------------------------&lt;br/&gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;string &lt;/span&gt;loginName &lt;span style="color:red"&gt;= &lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;Form[&lt;span style="color:#a31515"&gt;"loginName"&lt;/span&gt;];&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(loginName) )&lt;br/&gt;        &lt;span style="color:blue"&gt;return&lt;/span&gt;;&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color:#2b91af"&gt;FormsAuthentication&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;SetAuthCookie(loginName, &lt;span style="color:blue"&gt;true&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;    TryRedirect();&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;现在，我可试一下登录功能。点击登录按钮后，页面的显示效果如下：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012041519510967.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;从图片的显示可以看出，我前面写的NormalLogin()方法确实可以实现用户登录。&lt;br /&gt;当然了，我也可以在此时点击退出按钮，那么就回到了图片２的显示。&lt;/p&gt;&lt;p&gt;写到这里，我想有必要再来总结一下在ASP.NET中实现登录与注销的方法：&lt;br /&gt;1. 登录：调用FormsAuthentication.SetAuthCookie()方法，传递一个登录名即可。&lt;br /&gt;2. 注销：调用FormsAuthentication.SignOut()方法。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;保护受限制的页面&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在一个ASP.NET网站中，有些页面会允许所有用户访问，包括一些未登录用户，但有些页面则必须是已登录用户才能访问，还有一些页面可能会要求特定的用户或者用户组的成员才能访问。这类页面因此也可称为【受限页面】，它们一般代表着比较重要的页面，包含一些重要的操作或功能。&lt;/p&gt;&lt;p&gt;为了保护受限制的页面的访问，ASP.NET提供了一种简单的方式：可以在web.config中指定受限资源允许哪些用户或者用户组（角色）的访问，也可以设置为禁止访问。&lt;/p&gt;&lt;p&gt;比如，网站有一个页面：MyInfo.aspx，它要求访问这个页面的访问者必须是一个已登录用户，那么可以在web.config中这样配置：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;location &lt;/span&gt;&lt;span style="color:red"&gt;path&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;MyInfo.aspx&lt;/span&gt;"&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;system.web&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;authorization&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;            &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;deny &lt;/span&gt;&lt;span style="color:red"&gt;users&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;?&lt;/span&gt;"&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;        &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;authorization&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;system.web&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;location&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;为了方便，我可能会将一些管理相关的多个页面放在Admin目录中，显然这些页面只允许Admin用户组的成员才可以访问。对于这种情况，我们可以直接针对一个目录设置访问规则：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;location &lt;/span&gt;&lt;span style="color:red"&gt;path&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;Admin&lt;/span&gt;"&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;system.web&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;authorization&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;            &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;allow &lt;/span&gt;&lt;span style="color:red"&gt;roles&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;Admin&lt;/span&gt;"&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;            &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;deny &lt;/span&gt;&lt;span style="color:red"&gt;users&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*&lt;/span&gt;"&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;        &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;authorization&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;system.web&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;location&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;这样就不必一个一个页面单独设置了，还可以在目录中创建一个web.config来指定目录的访问规则，请参考后面的示例。&lt;/p&gt;&lt;p&gt;在前面的示例中，有一点要特别注意的是：&lt;br /&gt;1. allow和deny之间的顺序一定不能写错了，UrlAuthorizationModule将按这个顺序依次判断。&lt;br /&gt;2. 如果某个资源只允许某类用户访问，那么最后的一条规则一定是 &amp;lt;deny users="*" /&amp;gt; &lt;/p&gt;&lt;p&gt;在allow和deny的配置中，我们可以在一条规则中指定多个用户：&lt;br /&gt;1. 使用users属性，值为逗号分隔的用户名列表。&lt;br /&gt;2. 使用roles属性，值为逗号分隔的角色列表。&lt;br /&gt;3. 问号 (?) 表示匿名用户。&lt;br /&gt;4. 星号 (*) 表示所有用户。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;登录页不能正常显示的问题&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;有时候，我们可能要开发一个内部使用的网站程序，这类网站程序要求 &lt;b&gt;禁止匿名用户的访问&lt;/b&gt;，即：所有使用者必须先登录才能访问。因此，我们通常会在网站根目录下的web.config中这样设置：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;authorization&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;deny &lt;/span&gt;&lt;span style="color:red"&gt;users&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;?&lt;/span&gt;"&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;authorization&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;对于我们的示例，我们也可以这样设置。此时在浏览器打开页面时，呈现效果如下：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012041519520392.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;从图片中可以看出：页面的样式显示不正确，最下边还多出了一行文字。&lt;/p&gt;&lt;p&gt;这个页面的完整代码是这样的（它引用了一个CSS文件和一个JS文件）：&lt;a href="javascript:void(0);" codeId="pre-default-aspx"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;@ &lt;/span&gt;&lt;span style="color:#a31515"&gt;Page &lt;/span&gt;&lt;span style="color:red"&gt;Language&lt;/span&gt;&lt;span style="color:blue"&gt;="C#" &lt;/span&gt;&lt;span style="color:red"&gt;CodeFile&lt;/span&gt;&lt;span style="color:blue"&gt;="Default.aspx.cs" &lt;/span&gt;&lt;span style="color:red"&gt;Inherits&lt;/span&gt;&lt;span style="color:blue"&gt;="_Default" &lt;/span&gt;&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;html &lt;/span&gt;&lt;span style="color:red"&gt;xmlns&lt;/span&gt;&lt;span style="color:blue"&gt;="http://www.w3.org/1999/xhtml"&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;head&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;title&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;FormsAuthentication DEMO  - http://www.cnblogs.com/fish-li/&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;title&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;link &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text/css" &lt;/span&gt;&lt;span style="color:red"&gt;rel&lt;/span&gt;&lt;span style="color:blue"&gt;="Stylesheet" &lt;/span&gt;&lt;span style="color:red"&gt;href&lt;/span&gt;&lt;span style="color:blue"&gt;="css/StyleSheet.css" /&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;head&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;body&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;fieldset&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;legend&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;普通登录&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;legend&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;form &lt;/span&gt;&lt;span style="color:red"&gt;action&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;= Request.RawUrl &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;" &lt;/span&gt;&lt;span style="color:red"&gt;method&lt;/span&gt;&lt;span style="color:blue"&gt;="post"&amp;gt;&lt;br/&gt;        &lt;/span&gt;登录名：&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text" &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="loginName" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;: &lt;span style="color:blue"&gt;200px" &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="Fish" /&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="submit" &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="NormalLogin" &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="登录" /&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;form&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;fieldset&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;     &lt;br/&gt;    &lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;fieldset&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;legend&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;用户状态&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;legend&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;form &lt;/span&gt;&lt;span style="color:red"&gt;action&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;= Request.RawUrl &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;" &lt;/span&gt;&lt;span style="color:red"&gt;method&lt;/span&gt;&lt;span style="color:blue"&gt;="post"&amp;gt;&lt;br/&gt;        &lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color:blue"&gt;if&lt;/span&gt;( Request&lt;span style="color:red"&gt;.&lt;/span&gt;IsAuthenticated ) { &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;            当前用户已登录，登录名：&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;Context&lt;span style="color:red"&gt;.&lt;/span&gt;User&lt;span style="color:red"&gt;.&lt;/span&gt;Identity&lt;span style="color:red"&gt;.&lt;/span&gt;Name&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt; &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;br &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;            &lt;br/&gt;            &lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color:blue"&gt;var &lt;/span&gt;user &lt;span style="color:red"&gt;= &lt;/span&gt;Context&lt;span style="color:red"&gt;.&lt;/span&gt;User &lt;span style="color:blue"&gt;as &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyFormsPrincipal&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;UserInfo&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt;&lt;/span&gt;;  &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;            &lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color:blue"&gt;if&lt;/span&gt;( user &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) { &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;                &lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;user&lt;span style="color:red"&gt;.&lt;/span&gt;UserData&lt;span style="color:red"&gt;.&lt;/span&gt;ToString()&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;            &lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;            &lt;br/&gt;            &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="submit" &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="Logon" &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="退出" /&amp;gt;&lt;br/&gt;        &lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="color:blue"&gt;else &lt;/span&gt;{ &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;            &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;b&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;当前用户还未登录。&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;b&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;            &lt;br/&gt;    &lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;form&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;fieldset&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;    &lt;br/&gt;    &lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;p &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="hideText"&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;i&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;不应该显示的文字&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;i&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;script &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text/javascript" &lt;/span&gt;&lt;span style="color:red"&gt;src&lt;/span&gt;&lt;span style="color:blue"&gt;="js/JScript.js"&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;script&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;body&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;html&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;页面最后一行文字平时不显示是因为JScript.js中有以下代码：&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;document.getElementById(&lt;span style="color:#a31515"&gt;"hideText"&lt;/span&gt;).setAttribute(&lt;span style="color:#a31515"&gt;"style"&lt;/span&gt;&lt;span style="color:red"&gt;, &lt;/span&gt;&lt;span style="color:#a31515"&gt;"display: none"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;&lt;p&gt;这段JS代码能做什么，我想就不用再解释了。&lt;br /&gt;虽然这段JS代码没什么价值，但我主要是想演示在登录页面中引用JS的场景。&lt;/p&gt;&lt;p&gt;根据前面图片，我们可以猜测到：应该是CSS和JS文件没有正确加载造成的。&lt;br /&gt;为了确认就是这样原因，我们可以打开FireBug再来看一下页面加载情况：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012041519522597.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;根据FireBug提供的线索我们可以分析出，页面在访问CSS, JS文件时，其实是被重定向到登录页面了，因此获得的结果肯定也是无意义的，所以就造成了登录页的显示不正确。&lt;/p&gt;&lt;p&gt;还记得前所说的【授权】吗？&lt;br /&gt;是的，现在就是由于我们在web.config中设置了不允许匿名用户访问，因此，所有的资源也就不允许匿名用户访问了，包括登录页所引用的CSS, JS文件。当授权检查失败时，请求会被重定向到登录页面，所以，登录页本身所引用的CSS, JS文件最后得到的响应内容其实是登录页的HTML代码，最终导致它们不能发挥作用，表现为登录页的样式显示不正确，以及引用的JS文件也不起作用。&lt;/p&gt;&lt;p&gt;不过，有一点比较奇怪：为什么访问登录页面时，没有发生重定向呢？&lt;br /&gt;原因是这样的：在ASP.NET内部，当发现是在访问登录面时，会设置HttpContext.SkipAuthorization = true &lt;i&gt;（其实是一个内部调用）&lt;/i&gt;，这样的设置会告诉后面的授权检查模块：&lt;b&gt;跳过这次请求的授权检查。&lt;/b&gt;因此，登录页总是允许所有用户访问，但是CSS文件以及JS文件是在另外的请求中发生的，那些请求并不会要跳过授权模块的检查。&lt;/p&gt;&lt;p&gt;为了解决登录页不能正确显示的问题，我们可以这样处理：&lt;br /&gt;1. 在网站根目录中的web.config中设置登录页所引用的JS, CSS文件都允许匿名访问。&lt;br /&gt;2. 也可以直接针对JS, CSS目录设置为允许匿名用户访问。&lt;br /&gt;3. 还可以在CSS, JS目录中创建一个web.config文件来配置对应目录的授权规则。可参考以下web.config文件：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a31515"&gt;xml &lt;/span&gt;&lt;span style="color:red"&gt;version&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;1.0&lt;/span&gt;"&lt;span style="color:blue"&gt;?&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;configuration&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;system.web&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;authorization&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;            &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;allow &lt;/span&gt;&lt;span style="color:red"&gt;users&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*&lt;/span&gt;"&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;        &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;authorization&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;system.web&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;configuration&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;第三种做法可以不修改网站根目录下的web.config文件。&lt;/p&gt;&lt;p&gt;&lt;b&gt;注意：在IIS中看到的情况就和在Visual Studio中看到的结果就不一样了。&lt;/b&gt;因为，像js, css, image这类文件属于静态资源文件，IIS能直接处理，不需要交给ASP.NET来响应，因此就不会发生授权检查失败，所以，如果这类网站部署在IIS中，看到的结果又是正常的。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;认识Forms身份认证&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;前面我演示了如何用代码实现登录与注销的过程，下面再来看一下登录时，ASP.NET到底做了些什么事情，它是如何知道当前请求是一个已登录用户的？&lt;/p&gt;&lt;p&gt;在继续探索这个问题前，我想有必要来了解一下HTTP协议的一些特点。&lt;br /&gt;HTTP是一个无状态的协议，无状态的意思可以理解为：WEB服务器在处理所有传入请求时，根本就不知道某个请求是否是一个用户的第一次请求与后续请求，或者是另一个用户的请求。WEB服务器每次在处理请求时，都会按照用户所访问的资源所对应的处理代码，从头到尾执行一遍，然后输出响应内容，WEB服务器根本不会记住已处理了哪些用户的请求，因此，我们通常说HTTP协议是无状态的。&lt;/p&gt;&lt;p&gt;虽然HTTP协议与WEB服务器是无状态，但我们的业务需求却要求有状态，典型的就是用户登录，在这种业务需求中，要求WEB服务器端能区分某个请求是不是一个已登录用户发起的，或者当前请求是哪个用户发出的。在开发WEB应用程序时，我们通常会使用Cookie来保存一些简单的数据供服务端维持必要的状态。既然这是个通常的做法，那我们现在就来看一下现在页面的Cookie使用情况吧，以下是我用FireFox所看到的Cookie列表：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012041519524428.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;这个名字：LoginCookieName，是我在web.config中指定的：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;authentication &lt;/span&gt;&lt;span style="color:red"&gt;mode&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;Forms&lt;/span&gt;" &lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;forms &lt;/span&gt;&lt;span style="color:red"&gt;cookieless&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;UseCookies&lt;/span&gt;" &lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;LoginCookieName&lt;/span&gt;" &lt;span style="color:red"&gt;loginUrl&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;~/Default.aspx&lt;/span&gt;"&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;forms&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;authentication&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;在这段配置中，我不仅指定的登录状态的Cookie名，还指定了身份验证模式，以及Cookie的使用方式。&lt;/p&gt;&lt;p&gt;为了判断这个Cookie是否与登录状态有关，我们可以在浏览器提供的界面删除它，然后刷新页面，此时页面的显示效果如下：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012041519530142.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;此时，页面显示当前用户没有登录。&lt;/p&gt;&lt;p&gt;为了确认这个Cookie与登录状态有关，我们可以重新登录，然后再退出登录。&lt;br /&gt;发现只要是页面显示当前用户未登录时，这个Cookie就不会存在。&lt;/p&gt;&lt;p&gt;事实上，通过SetAuthCookie这个方法名，我们也可以猜得出这个操作会写一个Cookie。&lt;br /&gt;&lt;b&gt;注意：本文不讨论无Cookie模式的Forms登录。&lt;/b&gt; &lt;/p&gt;&lt;p&gt;从前面的截图我们可以看出：虽然当前用户名是 Fish ，但是，Cookie的值是一串乱码样的字符串。&lt;br /&gt;由于安全性的考虑，ASP.NET对Cookie做过加密处理了，这样可以防止恶意用户构造Cookie绕过登录机制来模拟登录用户。如果想知道这串加密字符串是如何得到的，那么请参考后文。&lt;/p&gt;&lt;p&gt;小结：&lt;br /&gt;1. Forms身份认证是在web.config中指定的，我们还可以设置Forms身份认证的其它配置参数。&lt;br /&gt;2. Forms身份认证的登录状态是通过Cookie来维持的。&lt;br /&gt;3. Forms身份认证的登录Cookie是加密的。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;理解Forms身份认证&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;经过前面的Cookie分析，我们可以发现Cookie的值是一串加密后的字符串，现在我们就来分析这个加密过程以及Cookie对于身份认证的作用。&lt;/p&gt;&lt;P&gt;登录的操作通常会检查用户提供的用户名和密码，因此登录状态也必须具有足够高的安全性。在Forms身份认证中，由于登录状态是保存在Cookie中，而Cookie又会保存到客户端，因此，为了保证登录状态不被恶意用户伪造，ASP.NET采用了加密的方式保存登录状态。为了实现安全性，ASP.NET采用【Forms身份验证凭据】（即FormsAuthenticationTicket对象）来表示一个Forms登录用户，加密与解密由FormsAuthentication的Encrypt与Decrypt的方法来实现。&lt;/P&gt;&lt;p&gt;用户登录的过程大致是这样的：&lt;br /&gt;1. 检查用户提交的登录名和密码是否正确。&lt;br /&gt;2. 根据登录名创建一个FormsAuthenticationTicket对象。&lt;br /&gt;3. 调用FormsAuthentication.Encrypt()加密。&lt;br /&gt;4. 根据加密结果创建登录Cookie，并写入Response。&lt;br /&gt;在登录验证结束后，一般会产生重定向操作，那么后面的每次请求将带上前面产生的加密Cookie，供服务器来验证每次请求的登录状态。&lt;/p&gt;&lt;p&gt;每次请求时的（认证）处理过程如下：&lt;br /&gt;1. FormsAuthenticationModule尝试读取登录Cookie。&lt;br /&gt;2. 从Cookie中解析出FormsAuthenticationTicket对象。过期的对象将被忽略。&lt;br /&gt;3. 根据FormsAuthenticationTicket对象构造FormsIdentity对象并设置HttpContext.User&lt;br /&gt;4. UrlAuthorizationModule执行授权检查。&lt;/p&gt;&lt;p&gt;在登录与认证的实现中，FormsAuthenticationTicket和FormsAuthentication是二个核心的类型，前者可以认为是一个数据结构，后者可认为是处理前者的工具类。&lt;/p&gt;&lt;p&gt;UrlAuthorizationModule是一个授权检查模块，其实它与登录认证的关系较为独立，因此，如果我们不使用这种基于用户名与用户组的授权检查，也可以禁用这个模块。&lt;/p&gt;&lt;p&gt;由于Cookie本身有过期的特点，然而为了安全，FormsAuthenticationTicket也支持过期策略，不过，ASP.NET的默认设置支持FormsAuthenticationTicket的可调过期行为，即：slidingExpiration=true 。这二者任何一个过期时，都将导致登录状态无效。&lt;/p&gt;&lt;p&gt;FormsAuthenticationTicket的可调过期的主要判断逻辑由FormsAuthentication.RenewTicketIfOld方法实现，代码如下：&lt;a href="javascript:void(0);" codeId="pre-RenewTicketIfOld"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;FormsAuthenticationTicket &lt;/span&gt;RenewTicketIfOld(&lt;span style="color:#2b91af"&gt;FormsAuthenticationTicket &lt;/span&gt;tOld)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;// 这段代码是意思是：当指定的超时时间逝去大半时将更新FormsAuthenticationTicket对象。&lt;br/&gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( tOld &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) &lt;br/&gt;        &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color:#2b91af"&gt;DateTime &lt;/span&gt;now &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DateTime&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Now;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;TimeSpan &lt;/span&gt;span &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;TimeSpan&lt;/span&gt;)(now &lt;span style="color:red"&gt;- &lt;/span&gt;tOld&lt;span style="color:red"&gt;.&lt;/span&gt;IssueDate);&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;TimeSpan &lt;/span&gt;span2 &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;TimeSpan&lt;/span&gt;)(tOld&lt;span style="color:red"&gt;.&lt;/span&gt;Expiration &lt;span style="color:red"&gt;- &lt;/span&gt;now);&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( span2 &lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;span ) &lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;tOld;&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;FormsAuthenticationTicket&lt;/span&gt;(tOld&lt;span style="color:red"&gt;.&lt;/span&gt;Version, tOld&lt;span style="color:red"&gt;.&lt;/span&gt;Name,&lt;br/&gt;        now, now &lt;span style="color:red"&gt;+ &lt;/span&gt;(tOld&lt;span style="color:red"&gt;.&lt;/span&gt;Expiration &lt;span style="color:red"&gt;- &lt;/span&gt;tOld&lt;span style="color:red"&gt;.&lt;/span&gt;IssueDate),&lt;br/&gt;        tOld&lt;span style="color:red"&gt;.&lt;/span&gt;IsPersistent, tOld&lt;span style="color:red"&gt;.&lt;/span&gt;UserData, tOld&lt;span style="color:red"&gt;.&lt;/span&gt;CookiePath);&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;Request.IsAuthenticated可以告诉我们当前请求是否&lt;b&gt;已经过身份验证&lt;/b&gt;，我们来看一下这个属性是如何实现的：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public bool &lt;/span&gt;IsAuthenticated&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;get&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;(((&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;_context&lt;span style="color:red"&gt;.&lt;/span&gt;User &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;) &lt;br/&gt;            &lt;span style="color:red"&gt;&amp;amp;&amp;amp; &lt;/span&gt;(&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;_context&lt;span style="color:red"&gt;.&lt;/span&gt;User&lt;span style="color:red"&gt;.&lt;/span&gt;Identity &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;)) &lt;br/&gt;            &lt;span style="color:red"&gt;&amp;amp;&amp;amp; &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;_context&lt;span style="color:red"&gt;.&lt;/span&gt;User&lt;span style="color:red"&gt;.&lt;/span&gt;Identity&lt;span style="color:red"&gt;.&lt;/span&gt;IsAuthenticated);&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;从代码可以看出，它的返回结果基本上来源于对Context.User的判断。&lt;br /&gt;另外，由于User和Identity都是二个接口类型的属性，因此，不同的实现方式对返回值也有影响。&lt;/p&gt;&lt;p&gt;由于可能会经常使用HttpContext.User这个实例属性，为了让它能正常使用，DefaultAuthenticationModule会在ASP.NET管线的PostAuthenticateRequest事件中检查此属性是否为null，如果它为null，DefaultAuthenticationModule会给它一个默认的GenericPrincipal对象，此对象指示一个未登录的用户。&lt;/p&gt;&lt;p&gt;&lt;b&gt;我认为ASP.NET的身份认证的最核心部分其实就是HttpContext.User这个属性所指向的对象。&lt;/b&gt;&lt;br /&gt;为了更好了理解Forms身份认证，我认为自己重新实现User这个对象的接口会有较好的帮助。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;实现自定义的身份认证标识&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;前面演示了最简单的ASP.NET Forms身份认证的实现方法，即：直接调用SetAuthCookie方法。不过调用这个方法，只能传递一个登录名。但是有时候为了方便后续的请求处理，还需要保存一些与登录名相关的额外信息。虽然知道ASP.NET使用Cookie来保存登录名状态信息，我们也可以直接将前面所说的额外信息直接保存在Cookie中，但是考虑安全性，我们还需要设计一些加密方法，而且还需要考虑这些额外信息保存在哪里才能方便使用，并还要考虑随登录与注销同步修改。因此，实现这些操作还是有点繁琐的。&lt;/p&gt;&lt;p&gt;为了保存与登录名相关的额外的用户信息，我认为实现自定义的身份认证标识（HttpContext.User实例）是个容易的解决方法。&lt;br /&gt;理解这个方法也会让我们对Forms身份认证有着更清楚地认识。&lt;/p&gt;&lt;p&gt;这个方法的核心是（分为二个子过程）：&lt;br /&gt;1. 在登录时，创建自定义的FormsAuthenticationTicket对象，它包含了用户信息。&lt;br /&gt;2. 加密FormsAuthenticationTicket对象。&lt;br /&gt;3. 创建登录Cookie，它将包含FormsAuthenticationTicket对象加密后的结果。&lt;br /&gt;4. 在管线的早期阶段，读取登录Cookie，如果有，则解密。&lt;br /&gt;5. 从解密后的FormsAuthenticationTicket对象中还原我们保存的用户信息。&lt;br /&gt;6. 设置HttpContext.User为我们自定义的对象。&lt;/p&gt;&lt;p&gt;现在，我们还是来看一下HttpContext.User这个属性的定义：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:green"&gt;//  为当前 HTTP 请求获取或设置安全信息。&lt;br/&gt;//&lt;br/&gt;// 返回结果:&lt;br/&gt;//     当前 HTTP 请求的安全信息。&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public &lt;/span&gt;IPrincipal User { &lt;span style="color:blue"&gt;get&lt;/span&gt;; &lt;span style="color:blue"&gt;set&lt;/span&gt;; }&lt;br/&gt;&lt;p&gt;由于这个属性只是个接口类型，因此，我们也可以自己实现这个接口。&lt;br /&gt;考虑到更好的通用性：不同的项目可能要求接受不同的用户信息类型。所以，我定义了一个泛型类。&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyFormsPrincipal&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;TUserData&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IPrincipal&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;where &lt;/span&gt;TUserData : &lt;span style="color:blue"&gt;class&lt;/span&gt;, &lt;span style="color:blue"&gt;new&lt;/span&gt;()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IIdentity &lt;/span&gt;_identity;&lt;br/&gt;    &lt;span style="color:blue"&gt;private &lt;/span&gt;TUserData _userData;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public &lt;/span&gt;MyFormsPrincipal(&lt;span style="color:#2b91af"&gt;FormsAuthenticationTicket &lt;/span&gt;ticket, TUserData userData)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( ticket &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"ticket"&lt;/span&gt;);&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( userData &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"userData"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;        _identity &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;FormsIdentity&lt;/span&gt;(ticket);&lt;br/&gt;        _userData &lt;span style="color:red"&gt;= &lt;/span&gt;userData;&lt;br/&gt;    }&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color:blue"&gt;public &lt;/span&gt;TUserData UserData&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;get &lt;/span&gt;{ &lt;span style="color:blue"&gt;return &lt;/span&gt;_userData; }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IIdentity &lt;/span&gt;Identity&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;get &lt;/span&gt;{ &lt;span style="color:blue"&gt;return &lt;/span&gt;_identity; }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public bool &lt;/span&gt;IsInRole(&lt;span style="color:blue"&gt;string &lt;/span&gt;role)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:green"&gt;// 把判断用户组的操作留给UserData去实现。&lt;br/&gt;&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IPrincipal &lt;/span&gt;principal &lt;span style="color:red"&gt;= &lt;/span&gt;_userData &lt;span style="color:blue"&gt;as &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IPrincipal&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( principal &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;NotImplementedException&lt;/span&gt;();&lt;br/&gt;        &lt;span style="color:blue"&gt;else&lt;br/&gt;            return &lt;/span&gt;principal&lt;span style="color:red"&gt;.&lt;/span&gt;IsInRole(role);&lt;br/&gt;    }&lt;br/&gt;&lt;p&gt;与之配套使用的用户信息的类型定义如下（可以根据实际情况来定义）：&lt;a href="javascript:void(0);" codeId="pre-UserInfo"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;UserInfo &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IPrincipal&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;public int &lt;/span&gt;UserId;&lt;br/&gt;    &lt;span style="color:blue"&gt;public int &lt;/span&gt;GroupId;&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;UserName;&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color:green"&gt;// 如果还有其它的用户信息，可以继续添加。&lt;br/&gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;public override string &lt;/span&gt;ToString()&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;return string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Format(&lt;span style="color:#a31515"&gt;"UserId: {0}, GroupId: {1}, UserName: {2}, IsAdmin: {3}"&lt;/span&gt;,&lt;br/&gt;            UserId, GroupId, UserName, IsInRole(&lt;span style="color:#a31515"&gt;"Admin"&lt;/span&gt;));&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;#region &lt;/span&gt;IPrincipal Members&lt;br/&gt;&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;ScriptIgnore&lt;/span&gt;]&lt;br/&gt;    &lt;span style="color:blue"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IIdentity &lt;/span&gt;Identity&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;get &lt;/span&gt;{ &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;NotImplementedException&lt;/span&gt;(); }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public bool &lt;/span&gt;IsInRole(&lt;span style="color:blue"&gt;string &lt;/span&gt;role)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Compare(role, &lt;span style="color:#a31515"&gt;"Admin"&lt;/span&gt;, &lt;span style="color:blue"&gt;true&lt;/span&gt;) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;GroupId &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:purple"&gt;1&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color:blue"&gt;else&lt;br/&gt;            return &lt;/span&gt;GroupId &lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;#endregion&lt;br/&gt;&lt;/span&gt;}&lt;br/&gt;&lt;p&gt;&lt;b&gt;注意：&lt;/b&gt;表示用户信息的类型并不要求一定要实现IPrincipal接口，如果不需要用户组的判断，可以不实现这个接口。&lt;/p&gt;&lt;p&gt;登录时需要调用的方法（定义在MyFormsPrincipal类型中）：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;执行用户登录操作&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;/// &amp;lt;param name="loginName"&amp;gt;&lt;/span&gt;&lt;span style="color:green"&gt;登录名&lt;/span&gt;&lt;span style="color:gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;/// &amp;lt;param name="userData"&amp;gt;&lt;/span&gt;&lt;span style="color:green"&gt;与登录名相关的用户信息&lt;/span&gt;&lt;span style="color:gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;/// &amp;lt;param name="expiration"&amp;gt;&lt;/span&gt;&lt;span style="color:green"&gt;登录Cookie的过期时间，单位：分钟。&lt;/span&gt;&lt;span style="color:gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public static void &lt;/span&gt;SignIn(&lt;span style="color:blue"&gt;string &lt;/span&gt;loginName, TUserData userData, &lt;span style="color:blue"&gt;int &lt;/span&gt;expiration)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(loginName) )&lt;br/&gt;        &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"loginName"&lt;/span&gt;);&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( userData &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;        &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"userData"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 1. 把需要保存的用户数据转成一个字符串。&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;string &lt;/span&gt;data &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( userData &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;        data &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;JavaScriptSerializer&lt;/span&gt;())&lt;span style="color:red"&gt;.&lt;/span&gt;Serialize(userData);&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 2. 创建一个FormsAuthenticationTicket，它包含登录名以及额外的用户数据。&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#2b91af"&gt;FormsAuthenticationTicket &lt;/span&gt;ticket &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;FormsAuthenticationTicket&lt;/span&gt;(&lt;br/&gt;        &lt;span style="color:purple"&gt;2&lt;/span&gt;, loginName, &lt;span style="color:#2b91af"&gt;DateTime&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Now, &lt;span style="color:#2b91af"&gt;DateTime&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Now&lt;span style="color:red"&gt;.&lt;/span&gt;AddDays(&lt;span style="color:purple"&gt;1&lt;/span&gt;), &lt;span style="color:blue"&gt;true&lt;/span&gt;, data);&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 3. 加密Ticket，变成一个加密的字符串。&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;string &lt;/span&gt;cookieValue &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;FormsAuthentication&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Encrypt(ticket);&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 4. 根据加密结果创建登录Cookie&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpCookie &lt;/span&gt;cookie &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpCookie&lt;/span&gt;(&lt;span style="color:#2b91af"&gt;FormsAuthentication&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;FormsCookieName, cookieValue);&lt;br/&gt;    cookie&lt;span style="color:red"&gt;.&lt;/span&gt;HttpOnly &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;true&lt;/span&gt;;&lt;br/&gt;    cookie&lt;span style="color:red"&gt;.&lt;/span&gt;Secure &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;FormsAuthentication&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;RequireSSL;&lt;br/&gt;    cookie&lt;span style="color:red"&gt;.&lt;/span&gt;Domain &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;FormsAuthentication&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;CookieDomain;&lt;br/&gt;    cookie&lt;span style="color:red"&gt;.&lt;/span&gt;Path &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;FormsAuthentication&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;FormsCookiePath;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( expiration &lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;)&lt;br/&gt;        cookie&lt;span style="color:red"&gt;.&lt;/span&gt;Expires &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DateTime&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Now&lt;span style="color:red"&gt;.&lt;/span&gt;AddMinutes(expiration);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpContext&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Current;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( context &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;        &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;InvalidOperationException&lt;/span&gt;();&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 5. 写登录Cookie&lt;br/&gt;    &lt;/span&gt;context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Cookies&lt;span style="color:red"&gt;.&lt;/span&gt;Remove(cookie&lt;span style="color:red"&gt;.&lt;/span&gt;Name);&lt;br/&gt;    context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Cookies&lt;span style="color:red"&gt;.&lt;/span&gt;Add(cookie);&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;这里有必要再补充一下：登录状态是有过期限制的。Cookie有 有效期，FormsAuthenticationTicket对象也有 有效期。这二者任何一个过期时，都将导致登录状态无效。按照默认设置，FormsAuthenticationModule将采用slidingExpiration=true的策略来处理FormsAuthenticationTicket过期问题。&lt;/p&gt;&lt;p&gt;登录页面代码：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;fieldset&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;legend&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;包含【用户信息】的自定义登录&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;legend&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;form &lt;/span&gt;&lt;span style="color:red"&gt;action&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;= Request.RawUrl &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;" &lt;/span&gt;&lt;span style="color:red"&gt;method&lt;/span&gt;&lt;span style="color:blue"&gt;="post"&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;table &lt;/span&gt;&lt;span style="color:red"&gt;border&lt;/span&gt;&lt;span style="color:blue"&gt;="0"&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;登录名：&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text" &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="loginName" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;: &lt;span style="color:blue"&gt;200px" &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="Fish" /&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;UserId：&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text" &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="UserId" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;: &lt;span style="color:blue"&gt;200px" &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="78" /&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;GroupId：&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text" &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="GroupId" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;: &lt;span style="color:blue"&gt;200px" /&amp;gt;&lt;br/&gt;        &lt;/span&gt;1表示管理员用户&lt;br/&gt;        &lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;用户全名：&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text" &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="UserName" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;: &lt;span style="color:blue"&gt;200px" &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="Fish Li" /&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;table&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;    &lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="submit" &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="CustomizeLogin" &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="登录" /&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;form&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;fieldset&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;登录处理代码：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public void &lt;/span&gt;CustomizeLogin()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;// -----------------------------------------------------------------&lt;br/&gt;    // 注意：演示代码为了简单，这里不检查用户名与密码是否正确。&lt;br/&gt;    // -----------------------------------------------------------------&lt;br/&gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;string &lt;/span&gt;loginName &lt;span style="color:red"&gt;= &lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;Form[&lt;span style="color:#a31515"&gt;"loginName"&lt;/span&gt;];&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(loginName) )&lt;br/&gt;        &lt;span style="color:blue"&gt;return&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;UserInfo &lt;/span&gt;userinfo &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;UserInfo&lt;/span&gt;();&lt;br/&gt;    &lt;span style="color:blue"&gt;int&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;TryParse(Request&lt;span style="color:red"&gt;.&lt;/span&gt;Form[&lt;span style="color:#a31515"&gt;"UserId"&lt;/span&gt;], &lt;span style="color:blue"&gt;out &lt;/span&gt;userinfo&lt;span style="color:red"&gt;.&lt;/span&gt;UserId);&lt;br/&gt;    &lt;span style="color:blue"&gt;int&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;TryParse(Request&lt;span style="color:red"&gt;.&lt;/span&gt;Form[&lt;span style="color:#a31515"&gt;"GroupId"&lt;/span&gt;], &lt;span style="color:blue"&gt;out &lt;/span&gt;userinfo&lt;span style="color:red"&gt;.&lt;/span&gt;GroupId);&lt;br/&gt;    userinfo&lt;span style="color:red"&gt;.&lt;/span&gt;UserName &lt;span style="color:red"&gt;= &lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;Form[&lt;span style="color:#a31515"&gt;"UserName"&lt;/span&gt;];&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 登录状态100分钟内有效&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyFormsPrincipal&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;UserInfo&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt;.&lt;/span&gt;SignIn(loginName, userinfo, &lt;span style="color:purple"&gt;100&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;    TryRedirect();&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;显示用户信息的页面代码：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;fieldset&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;legend&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;用户状态&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;legend&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;form &lt;/span&gt;&lt;span style="color:red"&gt;action&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;= Request.RawUrl &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;" &lt;/span&gt;&lt;span style="color:red"&gt;method&lt;/span&gt;&lt;span style="color:blue"&gt;="post"&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color:blue"&gt;if&lt;/span&gt;( Request&lt;span style="color:red"&gt;.&lt;/span&gt;IsAuthenticated ) { &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;        当前用户已登录，登录名：&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;Context&lt;span style="color:red"&gt;.&lt;/span&gt;User&lt;span style="color:red"&gt;.&lt;/span&gt;Identity&lt;span style="color:red"&gt;.&lt;/span&gt;Name&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt; &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;br &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;        &lt;br/&gt;        &lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color:blue"&gt;var &lt;/span&gt;user &lt;span style="color:red"&gt;= &lt;/span&gt;Context&lt;span style="color:red"&gt;.&lt;/span&gt;User &lt;span style="color:blue"&gt;as &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyFormsPrincipal&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;UserInfo&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt;&lt;/span&gt;;  &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;        &lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color:blue"&gt;if&lt;/span&gt;( user &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) { &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;            &lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;user&lt;span style="color:red"&gt;.&lt;/span&gt;UserData&lt;span style="color:red"&gt;.&lt;/span&gt;ToString()&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;        &lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;        &lt;br/&gt;        &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="submit" &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="Logon" &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="退出" /&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="color:blue"&gt;else &lt;/span&gt;{ &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;        &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;b&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;当前用户还未登录。&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;b&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;            &lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;form&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;fieldset&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;为了能让上面的页面代码发挥工作，必须在页面显示前重新设置HttpContext.User对象。&lt;br /&gt;为此，我在Global.asax中添加了一个事件处理器：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;protected void &lt;/span&gt;Application_AuthenticateRequest(&lt;span style="color:blue"&gt;object &lt;/span&gt;sender, &lt;span style="color:#2b91af"&gt;EventArgs &lt;/span&gt;e)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;HttpApplication &lt;/span&gt;app &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;HttpApplication&lt;/span&gt;)sender;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;MyFormsPrincipal&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;UserInfo&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt;.&lt;/span&gt;TrySetUserInfo(app&lt;span style="color:red"&gt;.&lt;/span&gt;Context);&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;TrySetUserInfo的实现代码：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;根据HttpContext对象设置用户标识对象&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;/// &amp;lt;param name="context"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public static void &lt;/span&gt;TrySetUserInfo(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( context &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;        &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"context"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 1. 读登录Cookie&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpCookie &lt;/span&gt;cookie &lt;span style="color:red"&gt;= &lt;/span&gt;context&lt;span style="color:red"&gt;.&lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;Cookies[&lt;span style="color:#2b91af"&gt;FormsAuthentication&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;FormsCookieName];&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( cookie &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;&lt;span style="color:red"&gt;|| &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(cookie&lt;span style="color:red"&gt;.&lt;/span&gt;Value) )&lt;br/&gt;        &lt;span style="color:blue"&gt;return&lt;/span&gt;;&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color:blue"&gt;try &lt;/span&gt;{&lt;br/&gt;        TUserData userData &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color:green"&gt;// 2. 解密Cookie值，获取FormsAuthenticationTicket对象&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:#2b91af"&gt;FormsAuthenticationTicket &lt;/span&gt;ticket &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;FormsAuthentication&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Decrypt(cookie&lt;span style="color:red"&gt;.&lt;/span&gt;Value);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( ticket &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;&lt;span style="color:red"&gt;&amp;amp;&amp;amp; &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(ticket&lt;span style="color:red"&gt;.&lt;/span&gt;UserData) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:green"&gt;// 3. 还原用户数据&lt;br/&gt;            &lt;/span&gt;userData &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;JavaScriptSerializer&lt;/span&gt;())&lt;span style="color:red"&gt;.&lt;/span&gt;Deserialize&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;TUserData&lt;span style="color:red"&gt;&amp;gt;&lt;/span&gt;(ticket&lt;span style="color:red"&gt;.&lt;/span&gt;UserData);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( ticket &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;&lt;span style="color:red"&gt;&amp;amp;&amp;amp; &lt;/span&gt;userData &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:green"&gt;// 4. 构造我们的MyFormsPrincipal实例，重新给context.User赋值。&lt;br/&gt;            &lt;/span&gt;context&lt;span style="color:red"&gt;.&lt;/span&gt;User &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyFormsPrincipal&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;TUserData&lt;span style="color:red"&gt;&amp;gt;&lt;/span&gt;(ticket, userData);&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;catch &lt;/span&gt;{ &lt;span style="color:green"&gt;/* 有异常也不要抛出，防止攻击者试探。 */ &lt;/span&gt;}&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&lt;strong&gt;在多台服务器之间使用Forms身份认证&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;默认情况下，ASP.NET 生成随机密钥并将其存储在本地安全机构 (LSA) 中，因此，当需要在多台机器之间使用Forms身份认证时，就不能再使用随机生成密钥的方式，&lt;b&gt;需要我们手工指定，保证每台机器的密钥是一致的。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;用于Forms身份认证的密钥可以在web.config的machineKey配置节中指定，我们还可以指定加密解密算法：&lt;/p&gt;&lt;br/&gt;&amp;lt;machineKey &lt;br/&gt;  decryption="Auto" [Auto | DES | 3DES | AES]&lt;br/&gt;  decryptionKey="AutoGenerate,IsolateApps" [String]&lt;br/&gt;/&amp;gt;&lt;br/&gt;&lt;p&gt;关于这二个属性，MSDN有如下解释：&lt;/p&gt;&lt;div style="line-height: 0px;"&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012041519531822.png" alt="" /&gt;&lt;br /&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012041519534487.png" alt="" /&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;在客户端程序中访问受限页面&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;i&gt;这一小节送给所有对自动化测试感兴趣的朋友。&lt;/i&gt;&lt;/p&gt;&lt;p&gt;有时我们需要用代码访问某些页面，比如：希望用代码测试服务端的响应。&lt;/p&gt;&lt;p&gt;如果是简单的页面，或者页面允许所有客户端访问，这样不会有问题，但是，如果此时我们要访问的页面是一个受限页面，那么就必须也要像人工操作那样：先访问登录页面，提交登录数据，获取服务端生成的登录Cookie，接下来才能去访问其它的受限页面（但要带上登录Cookie）。&lt;/p&gt;&lt;p&gt;&lt;b&gt;注意：&lt;/b&gt;由于登录Cookie通常是加密的，且会发生变化，因此直接在代码中硬编码指定登录Cookie会导致代码难以维护。&lt;/p&gt;&lt;p&gt;在前面的示例中，我已在web.config为MyInfo.aspx设置过禁止匿名访问，如果我用下面的代码去调用：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;private static readonly string &lt;/span&gt;MyInfoPageUrl &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"http://localhost:51855/MyInfo.aspx"&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;static void &lt;/span&gt;Main(&lt;span style="color:blue"&gt;string&lt;/span&gt;[] args)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;// 这个调用得到的结果其实是default.aspx页面的输出，并非MyInfo.aspx&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpWebRequest &lt;/span&gt;request &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyHttpClient&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;CreateHttpWebRequest(MyInfoPageUrl);&lt;br/&gt;    &lt;span style="color:blue"&gt;string &lt;/span&gt;html &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyHttpClient&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetResponseText(request);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( html&lt;span style="color:red"&gt;.&lt;/span&gt;IndexOf(&lt;span style="color:#a31515"&gt;"&amp;lt;span&amp;gt;Fish&amp;lt;/span&amp;gt;"&lt;/span&gt;) &lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;)&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;Console&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="color:#a31515"&gt;"调用成功。"&lt;/span&gt;);&lt;br/&gt;    &lt;span style="color:blue"&gt;else&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Console&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="color:#a31515"&gt;"页面结果不符合预期。"&lt;/span&gt;);&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;此时，输出的结果将会是：&lt;/p&gt;&lt;p class="console"&gt;页面结果不符合预期。&lt;/p&gt;&lt;p&gt;如果我用下面的代码：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;private static readonly string &lt;/span&gt;LoginUrl &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"http://localhost:51855/default.aspx"&lt;/span&gt;;&lt;br/&gt;&lt;span style="color:blue"&gt;private static readonly string &lt;/span&gt;MyInfoPageUrl &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"http://localhost:51855/MyInfo.aspx"&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;static void &lt;/span&gt;Main(&lt;span style="color:blue"&gt;string&lt;/span&gt;[] args)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;// 创建一个CookieContainer实例，供多次请求之间共享Cookie&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CookieContainer &lt;/span&gt;cookieContainer &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CookieContainer&lt;/span&gt;();&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 首先去登录页面登录&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyHttpClient&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;HttpPost(LoginUrl, &lt;span style="color:#a31515"&gt;"NormalLogin=aa&amp;amp;loginName=Fish"&lt;/span&gt;, cookieContainer);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 此时cookieContainer已经包含了服务端生成的登录Cookie&lt;br/&gt;&lt;br/&gt;    // 再去访问要请求的页面。&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;string &lt;/span&gt;html &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyHttpClient&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;HttpGet(MyInfoPageUrl, cookieContainer);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( html&lt;span style="color:red"&gt;.&lt;/span&gt;IndexOf(&lt;span style="color:#a31515"&gt;"&amp;lt;span&amp;gt;Fish&amp;lt;/span&amp;gt;"&lt;/span&gt;) &lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;)&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;Console&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="color:#a31515"&gt;"调用成功。"&lt;/span&gt;);&lt;br/&gt;    &lt;span style="color:blue"&gt;else&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Console&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="color:#a31515"&gt;"页面结果不符合预期。"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 如果还要访问其它的受限页面，可以继续调用。&lt;br/&gt;&lt;/span&gt;}&lt;br/&gt;&lt;p&gt;此时，输出的结果将会是：&lt;/p&gt;&lt;p class="console"&gt;调用成功。&lt;/p&gt;&lt;p&gt;说明：在改进的版本中，我首先创建一个CookieContainer实例，它可以在HTTP调用过程中接收服务器产生的Cookie，并能在发送HTTP请求时将已经保存的Cookie再发送给服务端。在创建好CookieContainer实例之后，每次使用HttpWebRequest对象时，只要将CookieContainer实例赋值给HttpWebRequest对象的CookieContainer属性，即可实现在多次的HTTP调用中Cookie的接收与发送，最终可以模拟浏览器的Cookie处理行为，服务端也能正确识别客户的身份。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;ASP.NET Forms身份认证就说到这里，如果您对ASP.NET Windows身份认证有兴趣，那么请关注我的后续博客。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://files.cnblogs.com/fish-li/AspnetLogin.cab.7z"&gt;点击此处下载示例代码&lt;/a&gt;&lt;/p&gt;&lt;div class="articleFooter"&gt;&lt;p&gt;如果，您认为阅读这篇博客让您有些收获，不妨点击一下右下角的&lt;a id="btnRecommendMyBlog" href="javascript:void(0);"&gt;【&lt;b&gt;推荐&lt;/b&gt;】&lt;/a&gt;按钮。&lt;br /&gt;如果，您希望更容易地发现我的新博客，不妨点击一下右下角的&lt;a id="btnFollowFishLi" href="javascript:void(0);"&gt;【&lt;b&gt;关注 Fish Li&lt;/b&gt;】&lt;/a&gt;。&lt;br /&gt;因为，我的写作热情也离不开您的肯定支持。&lt;/p&gt;&lt;p&gt;感谢您的阅读，如果您对我的博客所讲述的内容有兴趣，请继续关注我的后续博客，我是Fish Li 。&lt;span class="icon_smile"&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/fish-li/aggbug/2450571.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/04/15/2450571.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/fish-li/archive/2012/03/12/2392321.html</id><title type="text">Fish Li 的一年博客总结</title><summary type="text">2011-03-12开博，今天2012-03-12，整整写了一年的博客，今天决定写个总结。这篇总结为分四个部分：1. 博客索引：谈谈技术，给博客做个索引。2. 回顾经历：讲述我的写博历程。3. 博客定位：公开我的博客风格以及选题范围。4. 规划未来：介绍我未来的写作计划。博客索引我的博客在选题时，都选择的是一些基础内容。下面我从技术的角度，将博客做个分类索引。在ASP.NET程序中，能够在服务端读取的客户端数据通常只有三个：QueryString, Form, Cookie关于这三者，我写了三篇博客详细地介绍过它们：1. 细说Cookie2. 细说 Form (表单) 3. 细说 Reques</summary><published>2012-03-12T12:29:00Z</published><updated>2012-03-12T12:29:00Z</updated><author><name>Fish Li</name><uri>http://www.cnblogs.com/fish-li/</uri></author><link rel="alternate" href="http://www.cnblogs.com/fish-li/archive/2012/03/12/2392321.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/fish-li/archive/2012/03/12/2392321.html"/><content type="html">&lt;p&gt;2011-03-12开博，今天2012-03-12，整整写了一年的博客，今天决定写个总结。&lt;/p&gt;&lt;p&gt;这篇总结为分四个部分：&lt;br /&gt;1. 博客索引：谈谈技术，给博客做个索引。&lt;br /&gt;2. 回顾经历：讲述我的写博历程。&lt;br /&gt;3. 博客定位：公开我的博客风格以及选题范围。&lt;br /&gt;4. 规划未来：介绍我未来的写作计划。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;博客索引&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;我的博客在选题时，都选择的是一些基础内容。&lt;br /&gt;下面我从技术的角度，将博客做个分类索引。&lt;/p&gt;&lt;p&gt;在ASP.NET程序中，能够在服务端读取的客户端数据通常只有三个：QueryString, Form, Cookie&lt;br /&gt;关于这三者，我写了三篇博客详细地介绍过它们：&lt;br /&gt;1. &lt;a href="http://www.cnblogs.com/fish-li/archive/2011/07/03/2096903.html" target=""&gt;细说Cookie&lt;/a&gt;&lt;br /&gt;2. &lt;a href="http://www.cnblogs.com/fish-li/archive/2011/07/17/2108884.html" target=""&gt;细说 Form (表单) &lt;/a&gt;&lt;br /&gt;3. &lt;a href="http://www.cnblogs.com/fish-li/archive/2011/12/06/2278463.html" target=""&gt;细说 Request[]与Request.Params[]&lt;/a&gt;&lt;/p&gt;&lt;p&gt;要想把ASP.NET用得顺手，我认为掌握一些ASP.NET核心对象也是必须的，&lt;br /&gt;可以参考我的博客：&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/08/21/2148640.html" target="_blank"&gt;我心目中的Asp.net核心对象&lt;/a&gt;&lt;/p&gt;&lt;p&gt;ASP.NET的管线也是非常重要的，了解它就能更好地理解ASP.NET的处理机制。&lt;br /&gt;可以参考我的博客：&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/09/05/2168073.html" target="_blank"&gt;用Asp.net写自己的服务框架&lt;/a&gt;&lt;/p&gt;&lt;p&gt;除了以上这些核心之外，如果您打算基于ASP.NET开发一些工具类库，&lt;br /&gt;那么，了解下面博客中的内容也有很有帮助的：&lt;br /&gt;1. &lt;a href="http://www.cnblogs.com/fish-li/archive/2011/12/27/2304063.html" target="_blank"&gt;细说 ASP.NET Cache 及其高级用法&lt;/a&gt;&lt;br /&gt;2. &lt;a href="http://www.cnblogs.com/fish-li/archive/2012/01/29/2331477.html" target="_blank"&gt;细说 HttpHandler 的映射过程&lt;/a&gt;&lt;br /&gt;3. &lt;a href="http://www.cnblogs.com/fish-li/archive/2011/12/18/2292037.html" target="_blank"&gt;在.net中读写config文件的各种方法&lt;/a&gt;&lt;br /&gt;4. &lt;a href="http://www.cnblogs.com/fish-li/archive/2012/01/11/2320027.html" target="_blank"&gt;细说 ASP.NET控制HTTP缓存&lt;/a&gt;&lt;/p&gt;&lt;p&gt;如果您需要基于ASP.NET平台设计自己的框架，那么可以参考下面的博客：&lt;br /&gt;1. &lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/12/2348395.html" target="_blank"&gt;写自己的ASP.NET MVC框架（上）&lt;/a&gt;&lt;br /&gt;2. &lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/21/2361982.html" target="_blank"&gt;写自己的ASP.NET MVC框架（下）&lt;/a&gt;&lt;br /&gt;3. &lt;a href="http://www.cnblogs.com/fish-li/archive/2011/09/05/2168073.html" target="_blank"&gt;用Asp.net写自己的服务框架&lt;/a&gt;&lt;/p&gt;&lt;p&gt;异步也有个很有用的东西哦，如果想了解这方面的知识，可以阅读下面的博客：&lt;br /&gt;1. &lt;a href="http://www.cnblogs.com/fish-li/archive/2011/10/23/2222013.html" target="_blank"&gt;C#客户端的异步操作&lt;/a&gt;&lt;br /&gt;2. &lt;a href="http://www.cnblogs.com/fish-li/archive/2011/11/20/2256385.html" target="_blank"&gt;细说ASP.NET的各种异步操作&lt;/a&gt;&lt;/p&gt;&lt;p&gt;您对性能优化感兴趣吗？如果有兴趣，可以阅读下面的博客：&lt;br /&gt;1. &lt;a href="http://www.cnblogs.com/fish-li/archive/2011/06/06/2073626.html" target="_blank"&gt;看懂SqlServer查询计划&lt;/a&gt;&lt;br /&gt;2. &lt;a href="http://www.cnblogs.com/fish-li/archive/2012/03/11/2390569.html" target="_blank"&gt;ASP.NET页面优化，性能提升８倍的方法&lt;/a&gt;&lt;/p&gt;&lt;p&gt;您对 NoSQL 数据库有兴趣吗？我也写过这方面的博客：&lt;br /&gt;&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/06/26/2090800.html" target="_blank"&gt;MongoDB实战开发 【零基础学习，附完整Asp.net示例】&lt;/a&gt;&lt;/p&gt;&lt;p&gt;写完了ASP.NET项目，您知道如何部署它们吗？如果不清楚，可以参考下面的博客：&lt;br /&gt;&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/26/2368989.html" target="_blank"&gt;如何在IIS6,7中部署ASP.NET网站&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;回顾经历&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;2011-03-12，我在博客园注册了一个帐号，从此开始我的写博的经历。&lt;/p&gt;&lt;p&gt;刚开始，只是想晒晒自己的一点小作品（一直都是可下载的），于是发了一系列的灌水贴，最重要的有三篇：&lt;br /&gt;1. &lt;a href="http://www.cnblogs.com/fish-li/archive/2011/03/12/1982434.html" target="_blank"&gt;晒晒我的Ajax服务端框架&lt;/a&gt;&lt;br /&gt;2. &lt;a href="http://www.cnblogs.com/fish-li/archive/2011/03/28/1998104.html" target="_blank"&gt;晒晒我的通用数据访问层&lt;/a&gt;&lt;br /&gt;3. &lt;a href="http://www.cnblogs.com/fish-li/archive/2011/05/02/2034010.html" target="_blank"&gt;通用数据访问层及Ajax服务端框架的综合示例，展示与下载&lt;/a&gt;&lt;br /&gt;由于以前从未写过博客，风格也是模仿他人的风格：短篇+系列的形式。&lt;br /&gt;我数了一下，这类灌水贴有13篇。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;虽然这些博客也属于技术博客，而且我还写过博客说明它们的实现原理，但我把它们称为灌水贴是因为：&lt;br /&gt;&lt;b&gt;它们与我后期的博客相比，感觉实在是在灌水。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;我对灌水贴还有另一个衡量指标：访问量以及推荐数量较低。&lt;br /&gt;早期的这些博客在这二个指标上，实在是不及格。&lt;/p&gt;&lt;p&gt;2011-06-06，迎来了我的博客发展史的转折点，我发了一篇博客：&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/06/06/2073626.html" target="_blank"&gt;&lt;b&gt;看懂SqlServer查询计划&lt;/b&gt;&lt;/a&gt;，&lt;br /&gt;从此，我的博客被博客园称为：推荐博客。&lt;br /&gt;也从这时起，我的博客的访问量才有了一定的增长。&lt;/p&gt;&lt;p&gt;我的博客的另一个重要里程碑来自于我在2011-07-03发布的一篇博客：&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/07/03/2096903.html" target="_blank"&gt;&lt;b&gt;细说Cookie&lt;/b&gt;&lt;/a&gt;，&lt;br /&gt;在2011-07-17，我又发了另一篇博客：&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/07/17/2108884.html" target="_blank"&gt;&lt;b&gt;细说 Form (表单)&lt;/b&gt;&lt;/a&gt;&lt;br /&gt;从此，我的博客的访问量以及推荐数量均得到较大的提升。&lt;/p&gt;&lt;p&gt;在2011-08-21和2011-09-05，我又分别发了二篇博客：&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/08/21/2148640.html" target="_blank"&gt;&lt;b&gt;我心目中的Asp.net核心对象&lt;/b&gt;&lt;/a&gt; 和 &lt;a href="http://www.cnblogs.com/fish-li/archive/2011/09/05/2168073.html" target="_blank"&gt;&lt;b&gt;用Asp.net写自己的服务框架&lt;/b&gt;&lt;/a&gt;，&lt;br /&gt;这二篇博客的推出，将我的博客推向鼎盛时期。&lt;br /&gt;这二篇博客现在一直在我的博客的【阅读排行榜】和【推荐排行榜】占据着前二名的位置，而且它们的 &lt;b&gt;推荐次数已超过 300&lt;/b&gt; 。&lt;/p&gt;&lt;p&gt;其实这二篇博客并非孤立的，而是都属于我当时规划的一个系列。&lt;br /&gt;为了让后续的博客更精彩，我又花了二个月的时间写了二篇我认为很有价值的博客：&lt;br /&gt;&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/10/23/2222013.html" target="_blank"&gt;&lt;b&gt;C#客户端的异步操作&lt;/b&gt;&lt;/a&gt; 和  &lt;a href="http://www.cnblogs.com/fish-li/archive/2011/11/20/2256385.html" target="_blank"&gt;&lt;b&gt;细说ASP.NET的各种异步操作&lt;/b&gt;&lt;/a&gt;，&lt;br /&gt;我认为它们很有价值的原因是因为：我在二篇博客中对【异步】做了较为全面细致地总结，&lt;br /&gt;这些内容肯定是在许多的技术书上是找不到的，包含像【CLR via C#】这样的书。&lt;/p&gt;&lt;p&gt;不过，让我没想到的是：这二篇博客（起初）并不受欢迎。&lt;br /&gt;从博客的回复中我也发现：有些人问我为什么不说XXX这类多线程的东西。&lt;br /&gt;其实我也很郁闷啊：难道多线程就是异步吗？&lt;/p&gt;&lt;p&gt;随着时间的推移，我又发了几篇博客，让我意外的是：&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/12/18/2292037.html" target="_blank"&gt;&lt;b&gt;在.net中读写config文件的各种方法&lt;/b&gt;&lt;/a&gt; 和 &lt;a href="http://www.cnblogs.com/fish-li/archive/2011/12/27/2304063.html" target="_blank"&gt;&lt;b&gt;细说 ASP.NET Cache 及其高级用法&lt;/b&gt;&lt;/a&gt;，&lt;br /&gt;这二篇博客的访问量都已过万（3个月的时间），推荐次数已超200 ，看到这个成绩，真是我当时没想到的。&lt;/p&gt;&lt;p&gt;最近，我又写了一个大的系列博客：&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/21/2361982.html" target="_blank"&gt;&lt;b&gt;MyMVC框架&lt;/b&gt;&lt;/a&gt;，有兴趣的可以去阅读并下载所有源代码。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;博客定位&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;前面以流水帐的形式讲述了我的写博经历，这里再来谈谈我的博客定位。&lt;/p&gt;&lt;p&gt;在我写完 &lt;a href="http://www.cnblogs.com/fish-li/archive/2011/07/03/2096903.html" target="_blank"&gt;&lt;b&gt;细说Cookie&lt;/b&gt;&lt;/a&gt;，&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/07/17/2108884.html" target="_blank"&gt;&lt;b&gt;细说 Form (表单)&lt;/b&gt;&lt;/a&gt;之后，我总算知道为什么我早期的博客不受欢迎的原因：&lt;b&gt;定位不正确。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;所以，从那时起，我就对我的博客有了一个明确的定位：&lt;br /&gt;1. 只写一些基础话题，但要写出深度。&lt;br /&gt;2. 不写过于简单的话题。诸如一些server控件的使用。&lt;br /&gt;3. 别人写过的话题，除非我能写出更多的内涵，否则不写。&lt;br /&gt;4. 尽量选择一些经得起时间流逝的话题，我希望能留下一些经典。&lt;br /&gt;5. 不搞短篇连载，我认为博客应该更像有内涵的文章而不是向微博发展。&lt;/p&gt;&lt;p&gt;以上5点也可以用4个字来概括：基础，精品：&lt;br /&gt;&lt;b&gt;基础：&lt;/b&gt;博客话题以基础技术点为主，因为基础的内容不仅仅重要，而且不会过时。&lt;br /&gt;&lt;b&gt;精品：&lt;/b&gt;精品博客是我的追求目标，我更希望若干年后能留下几篇经典的博客。&lt;/p&gt;&lt;p&gt;在写博客的过程中，也有人建议我：为什么不把博客写成XXX系列的？&lt;br /&gt;其实我认为，我一直在写一个系列，一个大的系列：ASP.NET系列。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;规划未来&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;写作是一种总结，总结就会有收获。&lt;/p&gt;&lt;p&gt;分享是件有意义的事情，可以让自己留在别人心里。&lt;/p&gt;&lt;p&gt;未来我将继续总结并与大家分享我的总结成果。&lt;/p&gt;&lt;p&gt;未来的博客规划中，上半年将仍以ASP.NET为主，因为我感觉我还没说完......&lt;/p&gt;&lt;p&gt;在此，我要感谢那些关注我的园友们，谢谢你们。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class="articleFooter"&gt;&lt;p&gt;如果，您认为阅读这篇博客让您有些收获，不妨点击一下右下角的&lt;a id="btnRecommendMyBlog" href="javascript:void(0);"&gt;【&lt;b&gt;推荐&lt;/b&gt;】&lt;/a&gt;按钮。&lt;br /&gt;如果，您希望更容易地发现我的新博客，不妨点击一下右下角的&lt;a id="btnFollowFishLi" href="javascript:void(0);"&gt;【&lt;b&gt;关注 Fish Li&lt;/b&gt;】&lt;/a&gt;。&lt;br /&gt;因为，我的写作热情也离不开您的肯定支持。&lt;/p&gt;&lt;p&gt;感谢您的阅读，如果您对我的博客所讲述的内容有兴趣，请继续关注我的后续博客，我是Fish Li 。&lt;span class="icon_smile"&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/fish-li/aggbug/2392321.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/03/12/2392321.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/fish-li/archive/2012/03/11/2390569.html</id><title type="text">ASP.NET页面优化，性能提升８倍的方法</title><summary type="text">今天与大家分享：一种优化页面执行速度的方法。采用这个方法，可以使用页面的执行速度获得【８倍】的提升效果。为了让您对优化的效果有个直观的了解，我准备了下面的测试结果截图：测试环境：1. Windows Server 2003 SP22. Viaual Studio 2008，使用自带的WebDev.WebServer.EXE运行网站程序。3. (ThinkPad SL510)：Core2 T6670 2.2GHz, 4G内存二个红框中的数字反映了优化前后的执行时间。数字表明：优化前后，执行时间有了8倍多的差别。本文的测试结果也仅仅只是一个参考数字，这个结果也只是根据我所设计的测试页面得出的。优化</summary><published>2012-03-11T12:10:00Z</published><updated>2012-03-11T12:10:00Z</updated><author><name>Fish Li</name><uri>http://www.cnblogs.com/fish-li/</uri></author><link rel="alternate" href="http://www.cnblogs.com/fish-li/archive/2012/03/11/2390569.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/fish-li/archive/2012/03/11/2390569.html"/><content type="html">&lt;p&gt;今天与大家分享：一种优化页面执行速度的方法。&lt;br /&gt;采用这个方法，可以使用页面的执行速度获得【８倍】的提升效果。&lt;/p&gt;&lt;p&gt;为了让您对优化的效果有个直观的了解，我准备了下面的测试结果截图：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012031113241692.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;测试环境：&lt;br /&gt;1. Windows Server 2003 SP2&lt;br /&gt;2. Viaual Studio 2008，使用自带的WebDev.WebServer.EXE运行网站程序。&lt;br /&gt;3. (ThinkPad SL510)：Core2 T6670 2.2GHz, 4G内存&lt;/p&gt;&lt;p&gt;二个红框中的数字反映了优化前后的执行时间。&lt;br /&gt;数字表明：优化前后，执行时间有了8倍多的差别。&lt;/p&gt;&lt;p&gt;本文的测试结果也仅仅只是一个参考数字，这个结果也只是根据我所设计的测试页面得出的。&lt;br /&gt;优化的过程中，如果不使用服务器控件，那么给GC减少的压力其实也是无法测试到的。&lt;br /&gt;在测试过程中，我还发现测试结果并不是很稳定，因此截图具有一定的偶然性。&lt;br /&gt;测试页面或许在某些方面存在一些片面性，因此，结果仅供参考。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;测试背景&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;看过了优化结果，再来介绍一下：这个测试到底是在测试什么东西？&lt;/p&gt;&lt;p&gt;现在有很多做ASP.NET的开发人员，应该都是从ASP.NET的WebForm编程模型开始学习的。大家都很喜欢用服务器控件，不管输出什么，都会使用服务器控件。有时候为了让页面呈现干净的HTML代码，有些人会选择使用Repeater，Literal这类简单的服务器控件。或许有些人认为：我已不使用GridView这样强大复杂的控件，页面执行速度已经很快了。&lt;/p&gt;&lt;p&gt;真是这样吗？&lt;/p&gt;&lt;p&gt;今天测试的起点就从使用简单的服务器开始，我会分二次对它做一系列的性能优化。&lt;br /&gt;最终就是上图中的3个结果，它们反映了二次优化的改进过程。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;在继续介绍之前，有一点我想有必要说明一下：&lt;/p&gt;&lt;p class="redText" style="font-size: 13pt; line-height: 150%"&gt;优化的过程涉及到ASP.NET服务器控件的使用，测试结果也仅仅只是一个参考数字。&lt;br /&gt;&lt;b&gt;如果您认为您的开发工作非常依赖于服务器控件的使用，&lt;br /&gt;那么测试结果对您来说其实是无意义的，请不要在意这个结果。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;测试方法&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在这次优化过程中，我并没有设计很复杂的测试页面，而是一个很简单的测试页面，页面显示效果如下：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012031113243664.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;这个页面其实就是显示了一堆超链接，它们来自于我的博客侧边栏的【推荐排行榜】，总共有20条记录，我让页面重复5次输出，也就是生成了100个超链接。&lt;/p&gt;&lt;p&gt;测试的数据是这样获取的：&lt;br /&gt;我复制了我的博客侧边栏的【推荐排行榜】的那段HTML代码，保存到一个文件中：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012031113245069.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;然后，网站在初始化时，从这段HTML代码提取链接地址以及显示文字，保存到一个BlogInfo的列表中，代码如下：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BlogInfo&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;Title;&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;Href;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public static class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;XmlDb&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;public static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;BlogInfo&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;Blogs { &lt;span style="color:blue"&gt;get&lt;/span&gt;; &lt;span style="color:blue"&gt;private set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public static void &lt;/span&gt;LoadBlogs()&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;string &lt;/span&gt;filePath &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Path&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Combine(&lt;span style="color:#2b91af"&gt;HttpRuntime&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;AppDomainAppPath, &lt;span style="color:#a31515"&gt;@"App_Data\RecommendList.html"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;XElement &lt;/span&gt;html &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;XElement&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Parse(System&lt;span style="color:red"&gt;.&lt;/span&gt;IO&lt;span style="color:red"&gt;.&lt;/span&gt;&lt;span style="color:#2b91af"&gt;File&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;ReadAllText(filePath));&lt;br/&gt;&lt;br/&gt;        Blogs &lt;span style="color:red"&gt;=&lt;br/&gt;            &lt;/span&gt;(&lt;span style="color:blue"&gt;from &lt;/span&gt;a &lt;span style="color:blue"&gt;in &lt;/span&gt;html&lt;span style="color:red"&gt;.&lt;/span&gt;Elements(&lt;span style="color:#a31515"&gt;"li"&lt;/span&gt;)&lt;span style="color:red"&gt;.&lt;/span&gt;Elements(&lt;span style="color:#a31515"&gt;"a"&lt;/span&gt;)&lt;br/&gt;             &lt;span style="color:blue"&gt;select new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BlogInfo &lt;/span&gt;{ Title &lt;span style="color:red"&gt;= &lt;/span&gt;a&lt;span style="color:red"&gt;.&lt;/span&gt;Value, Href &lt;span style="color:red"&gt;= &lt;/span&gt;a&lt;span style="color:red"&gt;.&lt;/span&gt;Attribute(&lt;span style="color:#a31515"&gt;"href"&lt;/span&gt;)&lt;span style="color:red"&gt;.&lt;/span&gt;Value })&lt;span style="color:red"&gt;.&lt;/span&gt;ToList();&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;测试时，就把XmlDb.Blogs的内容显示在网页中。&lt;br /&gt;我想这个测试还是比较接近于现实开发的。&lt;/p&gt;&lt;p&gt;这里又有一个问题：我如何测试页面的执行速度？&lt;/p&gt;&lt;p&gt;虽然说创建HttpWebRequest访问页面是个很简单的方法，但我并不打算这样做。&lt;br /&gt;因为从HttpWebRequest发起调用到获取结果，这其中除了有页面的执行时间，还混杂较多的额外调用开销。最终，我选择了在一次HTTP请求中，循环调用Server.Execute来执行页面，并统计时间的方式。其实如何选择测试方法，对于二个测试对象还说，都是公平的。只是说：尽量减少一些额外的调用开销，会让测试结果的差异更大，也更明显。&lt;/p&gt;&lt;p&gt;说明：为了测试代码写起来简单，我使用了&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/21/2361982.html" target="_blank"&gt;&lt;b&gt;MyMVC框架&lt;/b&gt;&lt;/a&gt;。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;测试用例１：WebFromPage.aspx&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;前面介绍了测试背景以及测试方法。现在就来介绍第1个测试用例，它采用了WebForm编程模型中最经典的写法。&lt;/p&gt;&lt;p&gt;页面代码： &lt;a href="javascript:void(0);" codeId="pre-WebFromPage"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;@ &lt;/span&gt;&lt;span style="color:#a31515"&gt;Page &lt;/span&gt;&lt;span style="color:red"&gt;Language&lt;/span&gt;&lt;span style="color:blue"&gt;="C#" &lt;/span&gt;&lt;span style="color:red"&gt;CodeFile&lt;/span&gt;&lt;span style="color:blue"&gt;="WebFromPage.aspx.cs" &lt;/span&gt;&lt;span style="color:red"&gt;Inherits&lt;/span&gt;&lt;span style="color:blue"&gt;="TestPage_WebFromPage" &lt;/span&gt;&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;html &lt;/span&gt;&lt;span style="color:red"&gt;xmlns&lt;/span&gt;&lt;span style="color:blue"&gt;="http://www.w3.org/1999/xhtml"&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;head&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;title&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;PagePerformanceTest   http://www.cnblogs.com/fish-li/&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;title&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;head&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;body&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;This is WebFromPage.aspx&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Repeater &lt;/span&gt;&lt;span style="color:red"&gt;ID&lt;/span&gt;&lt;span style="color:blue"&gt;="repeater1" &lt;/span&gt;&lt;span style="color:red"&gt;runat&lt;/span&gt;&lt;span style="color:blue"&gt;="server" &lt;/span&gt;&lt;span style="color:red"&gt;onitemdatabound&lt;/span&gt;&lt;span style="color:blue"&gt;="repeater1_ItemDataBound"&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;ItemTemplate&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;HyperLink &lt;/span&gt;&lt;span style="color:red"&gt;ID&lt;/span&gt;&lt;span style="color:blue"&gt;="link1" &lt;/span&gt;&lt;span style="color:red"&gt;runat&lt;/span&gt;&lt;span style="color:blue"&gt;="server"&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;HyperLink&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;br &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;ItemTemplate&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;FooterTemplate&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;hr &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;FooterTemplate&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Repeater&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Repeater &lt;/span&gt;&lt;span style="color:red"&gt;ID&lt;/span&gt;&lt;span style="color:blue"&gt;="repeater2" &lt;/span&gt;&lt;span style="color:red"&gt;runat&lt;/span&gt;&lt;span style="color:blue"&gt;="server" &lt;/span&gt;&lt;span style="color:red"&gt;onitemdatabound&lt;/span&gt;&lt;span style="color:blue"&gt;="repeater1_ItemDataBound"&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;ItemTemplate&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;HyperLink &lt;/span&gt;&lt;span style="color:red"&gt;ID&lt;/span&gt;&lt;span style="color:blue"&gt;="link1" &lt;/span&gt;&lt;span style="color:red"&gt;runat&lt;/span&gt;&lt;span style="color:blue"&gt;="server"&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;HyperLink&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;br &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;ItemTemplate&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;FooterTemplate&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;hr &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;FooterTemplate&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Repeater&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Repeater &lt;/span&gt;&lt;span style="color:red"&gt;ID&lt;/span&gt;&lt;span style="color:blue"&gt;="repeater3" &lt;/span&gt;&lt;span style="color:red"&gt;runat&lt;/span&gt;&lt;span style="color:blue"&gt;="server" &lt;/span&gt;&lt;span style="color:red"&gt;onitemdatabound&lt;/span&gt;&lt;span style="color:blue"&gt;="repeater1_ItemDataBound"&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;ItemTemplate&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;HyperLink &lt;/span&gt;&lt;span style="color:red"&gt;ID&lt;/span&gt;&lt;span style="color:blue"&gt;="link1" &lt;/span&gt;&lt;span style="color:red"&gt;runat&lt;/span&gt;&lt;span style="color:blue"&gt;="server"&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;HyperLink&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;br &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;ItemTemplate&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;FooterTemplate&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;hr &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;FooterTemplate&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Repeater&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Repeater &lt;/span&gt;&lt;span style="color:red"&gt;ID&lt;/span&gt;&lt;span style="color:blue"&gt;="repeater4" &lt;/span&gt;&lt;span style="color:red"&gt;runat&lt;/span&gt;&lt;span style="color:blue"&gt;="server" &lt;/span&gt;&lt;span style="color:red"&gt;onitemdatabound&lt;/span&gt;&lt;span style="color:blue"&gt;="repeater1_ItemDataBound"&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;ItemTemplate&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;HyperLink &lt;/span&gt;&lt;span style="color:red"&gt;ID&lt;/span&gt;&lt;span style="color:blue"&gt;="link1" &lt;/span&gt;&lt;span style="color:red"&gt;runat&lt;/span&gt;&lt;span style="color:blue"&gt;="server"&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;HyperLink&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;br &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;ItemTemplate&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;FooterTemplate&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;hr &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;FooterTemplate&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Repeater&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Repeater &lt;/span&gt;&lt;span style="color:red"&gt;ID&lt;/span&gt;&lt;span style="color:blue"&gt;="repeater5" &lt;/span&gt;&lt;span style="color:red"&gt;runat&lt;/span&gt;&lt;span style="color:blue"&gt;="server" &lt;/span&gt;&lt;span style="color:red"&gt;onitemdatabound&lt;/span&gt;&lt;span style="color:blue"&gt;="repeater1_ItemDataBound"&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;ItemTemplate&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;HyperLink &lt;/span&gt;&lt;span style="color:red"&gt;ID&lt;/span&gt;&lt;span style="color:blue"&gt;="link1" &lt;/span&gt;&lt;span style="color:red"&gt;runat&lt;/span&gt;&lt;span style="color:blue"&gt;="server"&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;HyperLink&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;br &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;ItemTemplate&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;FooterTemplate&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;hr &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;FooterTemplate&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Repeater&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;body&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;html&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;页面的CodeFile代码：&lt;a href="javascript:void(0);" codeId="pre-TestPage_WebFromPage"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public partial class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;TestPage_WebFromPage &lt;/span&gt;: System&lt;span style="color:red"&gt;.&lt;/span&gt;Web&lt;span style="color:red"&gt;.&lt;/span&gt;UI&lt;span style="color:red"&gt;.&lt;/span&gt;&lt;span style="color:#2b91af"&gt;Page&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;protected override void &lt;/span&gt;OnLoad(&lt;span style="color:#2b91af"&gt;EventArgs &lt;/span&gt;e)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;base&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;OnLoad(e);&lt;br/&gt;&lt;br/&gt;        repeater1&lt;span style="color:red"&gt;.&lt;/span&gt;DataSource &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;XmlDb&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Blogs;&lt;br/&gt;        repeater1&lt;span style="color:red"&gt;.&lt;/span&gt;DataBind();&lt;br/&gt;        repeater2&lt;span style="color:red"&gt;.&lt;/span&gt;DataSource &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;XmlDb&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Blogs;&lt;br/&gt;        repeater2&lt;span style="color:red"&gt;.&lt;/span&gt;DataBind();&lt;br/&gt;        repeater3&lt;span style="color:red"&gt;.&lt;/span&gt;DataSource &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;XmlDb&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Blogs;&lt;br/&gt;        repeater3&lt;span style="color:red"&gt;.&lt;/span&gt;DataBind();&lt;br/&gt;        repeater4&lt;span style="color:red"&gt;.&lt;/span&gt;DataSource &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;XmlDb&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Blogs;&lt;br/&gt;        repeater4&lt;span style="color:red"&gt;.&lt;/span&gt;DataBind();&lt;br/&gt;        repeater5&lt;span style="color:red"&gt;.&lt;/span&gt;DataSource &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;XmlDb&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Blogs;&lt;br/&gt;        repeater5&lt;span style="color:red"&gt;.&lt;/span&gt;DataBind();&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;protected void &lt;/span&gt;repeater1_ItemDataBound(&lt;span style="color:blue"&gt;object &lt;/span&gt;sender, &lt;span style="color:#2b91af"&gt;RepeaterItemEventArgs &lt;/span&gt;e)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( e&lt;span style="color:red"&gt;.&lt;/span&gt;Item&lt;span style="color:red"&gt;.&lt;/span&gt;ItemType &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ListItemType&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Item ) {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;BlogInfo &lt;/span&gt;blog &lt;span style="color:red"&gt;= &lt;/span&gt;e&lt;span style="color:red"&gt;.&lt;/span&gt;Item&lt;span style="color:red"&gt;.&lt;/span&gt;DataItem &lt;span style="color:blue"&gt;as &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BlogInfo&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;HyperLink &lt;/span&gt;link1 &lt;span style="color:red"&gt;= &lt;/span&gt;e&lt;span style="color:red"&gt;.&lt;/span&gt;Item&lt;span style="color:red"&gt;.&lt;/span&gt;FindControl(&lt;span style="color:#a31515"&gt;"link1"&lt;/span&gt;) &lt;span style="color:blue"&gt;as &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HyperLink&lt;/span&gt;;&lt;br/&gt;            link1&lt;span style="color:red"&gt;.&lt;/span&gt;NavigateUrl &lt;span style="color:red"&gt;= &lt;/span&gt;blog&lt;span style="color:red"&gt;.&lt;/span&gt;Href;&lt;br/&gt;            link1&lt;span style="color:red"&gt;.&lt;/span&gt;Text &lt;span style="color:red"&gt;= &lt;/span&gt;blog&lt;span style="color:red"&gt;.&lt;/span&gt;Title;&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;p&gt;测试代码：&lt;a href="javascript:void(0);" codeId="pre-Test1"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public object &lt;/span&gt;Test1(&lt;span style="color:blue"&gt;string &lt;/span&gt;callTimes)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;int &lt;/span&gt;count &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;;&lt;br/&gt;    &lt;span style="color:blue"&gt;int&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;TryParse(callTimes, &lt;span style="color:blue"&gt;out &lt;/span&gt;count);&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( count &lt;span style="color:red"&gt;&amp;lt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;)&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;count;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpContext&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Current;&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color:green"&gt;// 先执行一次，排除编译时间&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;string &lt;/span&gt;html &lt;span style="color:red"&gt;= &lt;/span&gt;MyMVC&lt;span style="color:red"&gt;.&lt;/span&gt;&lt;span style="color:#2b91af"&gt;PageExecutor&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Render(context, &lt;span style="color:#a31515"&gt;"/TestPage/WebFromPage.aspx"&lt;/span&gt;, &lt;span style="color:blue"&gt;null&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;Stopwatch &lt;/span&gt;watch &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Stopwatch&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;StartNew();&lt;br/&gt;    &lt;span style="color:blue"&gt;for&lt;/span&gt;( &lt;span style="color:blue"&gt;int &lt;/span&gt;i &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;; i &lt;span style="color:red"&gt;&amp;lt; &lt;/span&gt;count; i&lt;span style="color:red"&gt;++ &lt;/span&gt;)&lt;br/&gt;        html &lt;span style="color:red"&gt;= &lt;/span&gt;MyMVC&lt;span style="color:red"&gt;.&lt;/span&gt;&lt;span style="color:#2b91af"&gt;PageExecutor&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Render(context, &lt;span style="color:#a31515"&gt;"/TestPage/WebFromPage.aspx"&lt;/span&gt;, &lt;span style="color:blue"&gt;null&lt;/span&gt;);&lt;br/&gt;    watch&lt;span style="color:red"&gt;.&lt;/span&gt;Stop();&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;watch&lt;span style="color:red"&gt;.&lt;/span&gt;Elapsed&lt;span style="color:red"&gt;.&lt;/span&gt;ToString();&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;当我测试执行&lt;b class="redText"&gt;10000&lt;/b&gt;次时，耗时：&lt;b class="redText"&gt;00:00:07.5607229&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;测试用例２：InlinePage.aspx&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;与测试用例1不同，测试用例2则完全不使用服务器控件。&lt;/p&gt;&lt;p&gt;页面代码：&lt;a href="javascript:void(0);" codeId="pre-InlinePage"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;@ &lt;/span&gt;&lt;span style="color:#a31515"&gt;Page &lt;/span&gt;&lt;span style="color:red"&gt;Language&lt;/span&gt;&lt;span style="color:blue"&gt;="C#" &lt;/span&gt;&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;html &lt;/span&gt;&lt;span style="color:red"&gt;xmlns&lt;/span&gt;&lt;span style="color:blue"&gt;="http://www.w3.org/1999/xhtml"&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;head&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;title&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;PagePerformanceTest   http://www.cnblogs.com/fish-li/&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;title&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;head&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;body&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;This is InlinePage.aspx&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;BlogInfo &lt;/span&gt;b &lt;span style="color:blue"&gt;in &lt;/span&gt;&lt;span style="color:#2b91af"&gt;XmlDb&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Blogs ) { &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;    &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;a &lt;/span&gt;&lt;span style="color:red"&gt;href&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;= b.Href &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;" &lt;/span&gt;&lt;span style="color:red"&gt;target&lt;/span&gt;&lt;span style="color:blue"&gt;="_blank"&amp;gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;b&lt;span style="color:red"&gt;.&lt;/span&gt;Title &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;a&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;br &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;hr &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;BlogInfo &lt;/span&gt;b &lt;span style="color:blue"&gt;in &lt;/span&gt;&lt;span style="color:#2b91af"&gt;XmlDb&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Blogs ) { &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;    &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;a &lt;/span&gt;&lt;span style="color:red"&gt;href&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;= b.Href &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;" &lt;/span&gt;&lt;span style="color:red"&gt;target&lt;/span&gt;&lt;span style="color:blue"&gt;="_blank"&amp;gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;b&lt;span style="color:red"&gt;.&lt;/span&gt;Title &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;a&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;br &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;hr &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;BlogInfo &lt;/span&gt;b &lt;span style="color:blue"&gt;in &lt;/span&gt;&lt;span style="color:#2b91af"&gt;XmlDb&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Blogs ) { &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;    &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;a &lt;/span&gt;&lt;span style="color:red"&gt;href&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;= b.Href &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;" &lt;/span&gt;&lt;span style="color:red"&gt;target&lt;/span&gt;&lt;span style="color:blue"&gt;="_blank"&amp;gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;b&lt;span style="color:red"&gt;.&lt;/span&gt;Title &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;a&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;br &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;hr &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;BlogInfo &lt;/span&gt;b &lt;span style="color:blue"&gt;in &lt;/span&gt;&lt;span style="color:#2b91af"&gt;XmlDb&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Blogs ) { &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;    &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;a &lt;/span&gt;&lt;span style="color:red"&gt;href&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;= b.Href &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;" &lt;/span&gt;&lt;span style="color:red"&gt;target&lt;/span&gt;&lt;span style="color:blue"&gt;="_blank"&amp;gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;b&lt;span style="color:red"&gt;.&lt;/span&gt;Title &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;a&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;br &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;hr &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;BlogInfo &lt;/span&gt;b &lt;span style="color:blue"&gt;in &lt;/span&gt;&lt;span style="color:#2b91af"&gt;XmlDb&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Blogs ) { &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;    &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;a &lt;/span&gt;&lt;span style="color:red"&gt;href&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;= b.Href &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;" &lt;/span&gt;&lt;span style="color:red"&gt;target&lt;/span&gt;&lt;span style="color:blue"&gt;="_blank"&amp;gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;b&lt;span style="color:red"&gt;.&lt;/span&gt;Title &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;a&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;br &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;hr &lt;/span&gt;&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;body&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;html&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;测试代码：&lt;a href="javascript:void(0);" codeId="pre-Test2"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public object &lt;/span&gt;Test2(&lt;span style="color:blue"&gt;string &lt;/span&gt;callTimes)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;int &lt;/span&gt;count &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;;&lt;br/&gt;    &lt;span style="color:blue"&gt;int&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;TryParse(callTimes, &lt;span style="color:blue"&gt;out &lt;/span&gt;count);&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( count &lt;span style="color:red"&gt;&amp;lt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;)&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;count;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpContext&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Current;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 先执行一次，排除编译时间&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;string &lt;/span&gt;html &lt;span style="color:red"&gt;= &lt;/span&gt;MyMVC&lt;span style="color:red"&gt;.&lt;/span&gt;&lt;span style="color:#2b91af"&gt;PageExecutor&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Render(context, &lt;span style="color:#a31515"&gt;"/TestPage/InlinePage.aspx"&lt;/span&gt;, &lt;span style="color:blue"&gt;null&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;Stopwatch &lt;/span&gt;watch &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Stopwatch&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;StartNew();&lt;br/&gt;    &lt;span style="color:blue"&gt;for&lt;/span&gt;( &lt;span style="color:blue"&gt;int &lt;/span&gt;i &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;; i &lt;span style="color:red"&gt;&amp;lt; &lt;/span&gt;count; i&lt;span style="color:red"&gt;++ &lt;/span&gt;)&lt;br/&gt;        html &lt;span style="color:red"&gt;= &lt;/span&gt;MyMVC&lt;span style="color:red"&gt;.&lt;/span&gt;&lt;span style="color:#2b91af"&gt;PageExecutor&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Render(context, &lt;span style="color:#a31515"&gt;"/TestPage/InlinePage.aspx"&lt;/span&gt;, &lt;span style="color:blue"&gt;null&lt;/span&gt;);&lt;br/&gt;    watch&lt;span style="color:red"&gt;.&lt;/span&gt;Stop();&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;watch&lt;span style="color:red"&gt;.&lt;/span&gt;Elapsed&lt;span style="color:red"&gt;.&lt;/span&gt;ToString();&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;当我测试执行&lt;b class="redText"&gt;10000&lt;/b&gt;次时，耗时：&lt;b class="redText"&gt;00:00:01.2345842&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;分析优化结果１&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;测试用例1执行相同次数所花费的时间是测试用例2的6倍，为什么会这样呢？&lt;/p&gt;&lt;p&gt;为了回答这个问题，我们首先要知道前面二个页面在执行时，它们是如何运行的。&lt;br /&gt;说到这里，就不得不谈ASP.NET的页面编译方式了。&lt;/p&gt;&lt;p&gt;ASP.NET的页面编译过程是个复杂的操作，其实我们可以不用关心页面是如何编译的，&lt;br /&gt;但要知道：页面编译后是什么样的。&lt;/p&gt;&lt;p&gt;为了能直观地了解页面编译后的样子，我编译了整个网站，并生成到一个DLL文件中，然后使用Reflector.exe来分析这个DLL的源代码。&lt;/p&gt;&lt;p&gt;将网站编译成一个DLL文件有二个方法：&lt;br /&gt;1. 安装WebDeployment插件。&lt;br /&gt;2. 使用我的工具：FishAspnetTool。&lt;a href="javascript:void(0);" codeId="pre-FishAspnetTool"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div style="display: none;" id="pre-FishAspnetTool"&gt;&lt;p&gt;本文将使用FishAspnetTool来编译测试网站获得编译后的DLL文件。&lt;/p&gt;&lt;p&gt;FishAspnetTool是什么？&lt;br /&gt;FishAspnetTool是我在使用Visual Web Developer 2005时，为了方便编译网站而写的一个小工具。&lt;br /&gt;下载地址：&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/10/30/2229497.html" target="_blank"&gt;http://www.cnblogs.com/fish-li/archive/2011/10/30/2229497.html&lt;/a&gt;&lt;br /&gt;注意：下载的是一个工具包，安装后，从开始菜单中运行FishTools\FishAspnetTool即可。&lt;br /&gt;下面是工具的运行截图。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012031113250444.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;操作方法：&lt;br /&gt;1. 点击粉色按钮，选择网站路径。&lt;br /&gt;2. 单选按钮选择第2项。&lt;br /&gt;3. 点击【发布网站】按钮。&lt;/p&gt;&lt;/div&gt;&lt;p&gt;在编译网站之后，我就可以知道网站在运行时如何运行页面了。 &lt;/p&gt;&lt;p&gt;测试用例1的页面，最后被编译成这样了：&lt;a href="javascript:void(0);" codeId="pre-testpage_webfrompage_aspx"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;namespace &lt;/span&gt;ASP&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;using &lt;/span&gt;System;&lt;br/&gt;    &lt;span style="color:blue"&gt;using &lt;/span&gt;System&lt;span style="color:red"&gt;.&lt;/span&gt;Diagnostics;&lt;br/&gt;    &lt;span style="color:blue"&gt;using &lt;/span&gt;System&lt;span style="color:red"&gt;.&lt;/span&gt;Runtime&lt;span style="color:red"&gt;.&lt;/span&gt;CompilerServices;&lt;br/&gt;    &lt;span style="color:blue"&gt;using &lt;/span&gt;System&lt;span style="color:red"&gt;.&lt;/span&gt;Web;&lt;br/&gt;    &lt;span style="color:blue"&gt;using &lt;/span&gt;System&lt;span style="color:red"&gt;.&lt;/span&gt;Web&lt;span style="color:red"&gt;.&lt;/span&gt;UI;&lt;br/&gt;    &lt;span style="color:blue"&gt;using &lt;/span&gt;System&lt;span style="color:red"&gt;.&lt;/span&gt;Web&lt;span style="color:red"&gt;.&lt;/span&gt;UI&lt;span style="color:red"&gt;.&lt;/span&gt;WebControls;&lt;br/&gt;&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;CompilerGlobalScope&lt;/span&gt;]&lt;br/&gt;    &lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;testpage_webfrompage_aspx &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;TestPage_WebFromPage&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;IHttpHandler&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color:blue"&gt;private static object &lt;/span&gt;__fileDependencies;&lt;br/&gt;        &lt;span style="color:blue"&gt;private static bool &lt;/span&gt;__initialized;&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;public &lt;/span&gt;testpage_webfrompage_aspx()&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;base&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;AppRelativeVirtualPath &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"~/TestPage/WebFromPage.aspx"&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color:blue"&gt;if &lt;/span&gt;(&lt;span style="color:red"&gt;!&lt;/span&gt;__initialized)&lt;br/&gt;            {&lt;br/&gt;                &lt;span style="color:blue"&gt;string&lt;/span&gt;[] virtualFileDependencies &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new string&lt;/span&gt;[] { &lt;span style="color:#a31515"&gt;"~/TestPage/WebFromPage.aspx"&lt;/span&gt;, &lt;span style="color:#a31515"&gt;"~/TestPage/WebFromPage.aspx.cs" &lt;/span&gt;};&lt;br/&gt;                __fileDependencies &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;base&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetWrappedFileDependencies(virtualFileDependencies);&lt;br/&gt;                __initialized &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;true&lt;/span&gt;;&lt;br/&gt;            }&lt;br/&gt;            &lt;span style="color:blue"&gt;base&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Server&lt;span style="color:red"&gt;.&lt;/span&gt;ScriptTimeout &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0x1c9c380&lt;/span&gt;;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;private void &lt;/span&gt;__BuildControl__control10(&lt;span style="color:#2b91af"&gt;Control &lt;/span&gt;__ctrl)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;IParserAccessor &lt;/span&gt;accessor &lt;span style="color:red"&gt;= &lt;/span&gt;__ctrl;&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;LiteralControl&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"&amp;lt;hr /&amp;gt;"&lt;/span&gt;));&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;private void &lt;/span&gt;__BuildControl__control11(&lt;span style="color:#2b91af"&gt;Control &lt;/span&gt;__ctrl)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;IParserAccessor &lt;/span&gt;accessor &lt;span style="color:red"&gt;= &lt;/span&gt;__ctrl;&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;LiteralControl&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"\r\n\t"&lt;/span&gt;));&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;HyperLink &lt;/span&gt;link &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__BuildControl__control12();&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(link);&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;LiteralControl&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"&amp;lt;br /&amp;gt;\r\n"&lt;/span&gt;));&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HyperLink &lt;/span&gt;__BuildControl__control12()&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;HyperLink &lt;/span&gt;link &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HyperLink &lt;/span&gt;{&lt;br/&gt;                TemplateControl &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;br/&gt;            &lt;/span&gt;};&lt;br/&gt;            link&lt;span style="color:red"&gt;.&lt;/span&gt;ApplyStyleSheetSkin(&lt;span style="color:blue"&gt;this&lt;/span&gt;);&lt;br/&gt;            link&lt;span style="color:red"&gt;.&lt;/span&gt;ID &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"link1"&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;link;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;private void &lt;/span&gt;__BuildControl__control13(&lt;span style="color:#2b91af"&gt;Control &lt;/span&gt;__ctrl)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;IParserAccessor &lt;/span&gt;accessor &lt;span style="color:red"&gt;= &lt;/span&gt;__ctrl;&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;LiteralControl&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"&amp;lt;hr /&amp;gt;"&lt;/span&gt;));&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;private void &lt;/span&gt;__BuildControl__control14(&lt;span style="color:#2b91af"&gt;Control &lt;/span&gt;__ctrl)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;IParserAccessor &lt;/span&gt;accessor &lt;span style="color:red"&gt;= &lt;/span&gt;__ctrl;&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;LiteralControl&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"\r\n\t"&lt;/span&gt;));&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;HyperLink &lt;/span&gt;link &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__BuildControl__control15();&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(link);&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;LiteralControl&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"&amp;lt;br /&amp;gt;\r\n"&lt;/span&gt;));&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HyperLink &lt;/span&gt;__BuildControl__control15()&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;HyperLink &lt;/span&gt;link &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HyperLink &lt;/span&gt;{&lt;br/&gt;                TemplateControl &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;br/&gt;            &lt;/span&gt;};&lt;br/&gt;            link&lt;span style="color:red"&gt;.&lt;/span&gt;ApplyStyleSheetSkin(&lt;span style="color:blue"&gt;this&lt;/span&gt;);&lt;br/&gt;            link&lt;span style="color:red"&gt;.&lt;/span&gt;ID &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"link1"&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;link;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;private void &lt;/span&gt;__BuildControl__control16(&lt;span style="color:#2b91af"&gt;Control &lt;/span&gt;__ctrl)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;IParserAccessor &lt;/span&gt;accessor &lt;span style="color:red"&gt;= &lt;/span&gt;__ctrl;&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;LiteralControl&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"&amp;lt;hr /&amp;gt;"&lt;/span&gt;));&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;private void &lt;/span&gt;__BuildControl__control2(&lt;span style="color:#2b91af"&gt;Control &lt;/span&gt;__ctrl)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;IParserAccessor &lt;/span&gt;accessor &lt;span style="color:red"&gt;= &lt;/span&gt;__ctrl;&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;LiteralControl&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"\r\n\t"&lt;/span&gt;));&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;HyperLink &lt;/span&gt;link &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__BuildControl__control3();&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(link);&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;LiteralControl&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"&amp;lt;br /&amp;gt;\r\n"&lt;/span&gt;));&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HyperLink &lt;/span&gt;__BuildControl__control3()&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;HyperLink &lt;/span&gt;link &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HyperLink &lt;/span&gt;{&lt;br/&gt;                TemplateControl &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;br/&gt;            &lt;/span&gt;};&lt;br/&gt;            link&lt;span style="color:red"&gt;.&lt;/span&gt;ApplyStyleSheetSkin(&lt;span style="color:blue"&gt;this&lt;/span&gt;);&lt;br/&gt;            link&lt;span style="color:red"&gt;.&lt;/span&gt;ID &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"link1"&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;link;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;private void &lt;/span&gt;__BuildControl__control4(&lt;span style="color:#2b91af"&gt;Control &lt;/span&gt;__ctrl)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;IParserAccessor &lt;/span&gt;accessor &lt;span style="color:red"&gt;= &lt;/span&gt;__ctrl;&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;LiteralControl&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"&amp;lt;hr /&amp;gt;"&lt;/span&gt;));&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;private void &lt;/span&gt;__BuildControl__control5(&lt;span style="color:#2b91af"&gt;Control &lt;/span&gt;__ctrl)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;IParserAccessor &lt;/span&gt;accessor &lt;span style="color:red"&gt;= &lt;/span&gt;__ctrl;&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;LiteralControl&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"\r\n\t"&lt;/span&gt;));&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;HyperLink &lt;/span&gt;link &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__BuildControl__control6();&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(link);&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;LiteralControl&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"&amp;lt;br /&amp;gt;\r\n"&lt;/span&gt;));&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HyperLink &lt;/span&gt;__BuildControl__control6()&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;HyperLink &lt;/span&gt;link &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HyperLink &lt;/span&gt;{&lt;br/&gt;                TemplateControl &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;br/&gt;            &lt;/span&gt;};&lt;br/&gt;            link&lt;span style="color:red"&gt;.&lt;/span&gt;ApplyStyleSheetSkin(&lt;span style="color:blue"&gt;this&lt;/span&gt;);&lt;br/&gt;            link&lt;span style="color:red"&gt;.&lt;/span&gt;ID &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"link1"&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;link;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;private void &lt;/span&gt;__BuildControl__control7(&lt;span style="color:#2b91af"&gt;Control &lt;/span&gt;__ctrl)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;IParserAccessor &lt;/span&gt;accessor &lt;span style="color:red"&gt;= &lt;/span&gt;__ctrl;&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;LiteralControl&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"&amp;lt;hr /&amp;gt;"&lt;/span&gt;));&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;private void &lt;/span&gt;__BuildControl__control8(&lt;span style="color:#2b91af"&gt;Control &lt;/span&gt;__ctrl)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;IParserAccessor &lt;/span&gt;accessor &lt;span style="color:red"&gt;= &lt;/span&gt;__ctrl;&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;LiteralControl&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"\r\n\t"&lt;/span&gt;));&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;HyperLink &lt;/span&gt;link &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__BuildControl__control9();&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(link);&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;LiteralControl&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"&amp;lt;br /&amp;gt;\r\n"&lt;/span&gt;));&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HyperLink &lt;/span&gt;__BuildControl__control9()&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;HyperLink &lt;/span&gt;link &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HyperLink &lt;/span&gt;{&lt;br/&gt;                TemplateControl &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;br/&gt;            &lt;/span&gt;};&lt;br/&gt;            link&lt;span style="color:red"&gt;.&lt;/span&gt;ApplyStyleSheetSkin(&lt;span style="color:blue"&gt;this&lt;/span&gt;);&lt;br/&gt;            link&lt;span style="color:red"&gt;.&lt;/span&gt;ID &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"link1"&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;link;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Repeater &lt;/span&gt;__BuildControlrepeater1()&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;Repeater &lt;/span&gt;repeater &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Repeater&lt;/span&gt;();&lt;br/&gt;            &lt;span style="color:blue"&gt;base&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;repeater1 &lt;span style="color:red"&gt;= &lt;/span&gt;repeater;&lt;br/&gt;            repeater&lt;span style="color:red"&gt;.&lt;/span&gt;ItemTemplate &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompiledTemplateBuilder&lt;/span&gt;(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BuildTemplateMethod&lt;/span&gt;(&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__BuildControl__control2));&lt;br/&gt;            repeater&lt;span style="color:red"&gt;.&lt;/span&gt;FooterTemplate &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompiledTemplateBuilder&lt;/span&gt;(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BuildTemplateMethod&lt;/span&gt;(&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__BuildControl__control4));&lt;br/&gt;            repeater&lt;span style="color:red"&gt;.&lt;/span&gt;ID &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"repeater1"&lt;/span&gt;;&lt;br/&gt;            repeater&lt;span style="color:red"&gt;.&lt;/span&gt;ItemDataBound &lt;span style="color:red"&gt;+= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;RepeaterItemEventHandler&lt;/span&gt;(&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;repeater1_ItemDataBound);&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;repeater;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Repeater &lt;/span&gt;__BuildControlrepeater2()&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;Repeater &lt;/span&gt;repeater &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Repeater&lt;/span&gt;();&lt;br/&gt;            &lt;span style="color:blue"&gt;base&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;repeater2 &lt;span style="color:red"&gt;= &lt;/span&gt;repeater;&lt;br/&gt;            repeater&lt;span style="color:red"&gt;.&lt;/span&gt;ItemTemplate &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompiledTemplateBuilder&lt;/span&gt;(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BuildTemplateMethod&lt;/span&gt;(&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__BuildControl__control5));&lt;br/&gt;            repeater&lt;span style="color:red"&gt;.&lt;/span&gt;FooterTemplate &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompiledTemplateBuilder&lt;/span&gt;(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BuildTemplateMethod&lt;/span&gt;(&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__BuildControl__control7));&lt;br/&gt;            repeater&lt;span style="color:red"&gt;.&lt;/span&gt;ID &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"repeater2"&lt;/span&gt;;&lt;br/&gt;            repeater&lt;span style="color:red"&gt;.&lt;/span&gt;ItemDataBound &lt;span style="color:red"&gt;+= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;RepeaterItemEventHandler&lt;/span&gt;(&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;repeater1_ItemDataBound);&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;repeater;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Repeater &lt;/span&gt;__BuildControlrepeater3()&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;Repeater &lt;/span&gt;repeater &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Repeater&lt;/span&gt;();&lt;br/&gt;            &lt;span style="color:blue"&gt;base&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;repeater3 &lt;span style="color:red"&gt;= &lt;/span&gt;repeater;&lt;br/&gt;            repeater&lt;span style="color:red"&gt;.&lt;/span&gt;ItemTemplate &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompiledTemplateBuilder&lt;/span&gt;(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BuildTemplateMethod&lt;/span&gt;(&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__BuildControl__control8));&lt;br/&gt;            repeater&lt;span style="color:red"&gt;.&lt;/span&gt;FooterTemplate &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompiledTemplateBuilder&lt;/span&gt;(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BuildTemplateMethod&lt;/span&gt;(&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__BuildControl__control10));&lt;br/&gt;            repeater&lt;span style="color:red"&gt;.&lt;/span&gt;ID &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"repeater3"&lt;/span&gt;;&lt;br/&gt;            repeater&lt;span style="color:red"&gt;.&lt;/span&gt;ItemDataBound &lt;span style="color:red"&gt;+= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;RepeaterItemEventHandler&lt;/span&gt;(&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;repeater1_ItemDataBound);&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;repeater;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Repeater &lt;/span&gt;__BuildControlrepeater4()&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;Repeater &lt;/span&gt;repeater &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Repeater&lt;/span&gt;();&lt;br/&gt;            &lt;span style="color:blue"&gt;base&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;repeater4 &lt;span style="color:red"&gt;= &lt;/span&gt;repeater;&lt;br/&gt;            repeater&lt;span style="color:red"&gt;.&lt;/span&gt;ItemTemplate &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompiledTemplateBuilder&lt;/span&gt;(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BuildTemplateMethod&lt;/span&gt;(&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__BuildControl__control11));&lt;br/&gt;            repeater&lt;span style="color:red"&gt;.&lt;/span&gt;FooterTemplate &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompiledTemplateBuilder&lt;/span&gt;(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BuildTemplateMethod&lt;/span&gt;(&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__BuildControl__control13));&lt;br/&gt;            repeater&lt;span style="color:red"&gt;.&lt;/span&gt;ID &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"repeater4"&lt;/span&gt;;&lt;br/&gt;            repeater&lt;span style="color:red"&gt;.&lt;/span&gt;ItemDataBound &lt;span style="color:red"&gt;+= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;RepeaterItemEventHandler&lt;/span&gt;(&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;repeater1_ItemDataBound);&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;repeater;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Repeater &lt;/span&gt;__BuildControlrepeater5()&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;Repeater &lt;/span&gt;repeater &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Repeater&lt;/span&gt;();&lt;br/&gt;            &lt;span style="color:blue"&gt;base&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;repeater5 &lt;span style="color:red"&gt;= &lt;/span&gt;repeater;&lt;br/&gt;            repeater&lt;span style="color:red"&gt;.&lt;/span&gt;ItemTemplate &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompiledTemplateBuilder&lt;/span&gt;(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BuildTemplateMethod&lt;/span&gt;(&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__BuildControl__control14));&lt;br/&gt;            repeater&lt;span style="color:red"&gt;.&lt;/span&gt;FooterTemplate &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompiledTemplateBuilder&lt;/span&gt;(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BuildTemplateMethod&lt;/span&gt;(&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__BuildControl__control16));&lt;br/&gt;            repeater&lt;span style="color:red"&gt;.&lt;/span&gt;ID &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"repeater5"&lt;/span&gt;;&lt;br/&gt;            repeater&lt;span style="color:red"&gt;.&lt;/span&gt;ItemDataBound &lt;span style="color:red"&gt;+= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;RepeaterItemEventHandler&lt;/span&gt;(&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;repeater1_ItemDataBound);&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;repeater;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;private void &lt;/span&gt;__BuildControlTree(&lt;span style="color:#2b91af"&gt;testpage_webfrompage_aspx &lt;/span&gt;__ctrl)&lt;br/&gt;        {&lt;br/&gt;            __ctrl&lt;span style="color:red"&gt;.&lt;/span&gt;EnableViewState &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;false&lt;/span&gt;;&lt;br/&gt;            __ctrl&lt;span style="color:red"&gt;.&lt;/span&gt;EnableViewStateMac &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;false&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;InitializeCulture();&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;IParserAccessor &lt;/span&gt;accessor &lt;span style="color:red"&gt;= &lt;/span&gt;__ctrl;&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;LiteralControl&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"\r\n\r\n&amp;lt;html xmlns=\"http://www.w3.org/1999/xhtml\"&amp;gt;\r\n&amp;lt;head&amp;gt;\r\n    &amp;lt;title&amp;gt;PagePerformanceTest   http://www.cnblogs.com/fish-li/&amp;lt;/title&amp;gt;\r\n&amp;lt;/head&amp;gt;\r\n&amp;lt;body&amp;gt;\r\n\r\n&amp;lt;p&amp;gt;This is WebFromPage.aspx&amp;lt;/p&amp;gt;\r\n\r\n"&lt;/span&gt;));&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;Repeater &lt;/span&gt;repeater &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__BuildControlrepeater1();&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(repeater);&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;LiteralControl&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"\r\n\r\n"&lt;/span&gt;));&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;Repeater &lt;/span&gt;repeater2 &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__BuildControlrepeater2();&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(repeater2);&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;LiteralControl&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"\r\n\r\n"&lt;/span&gt;));&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;Repeater &lt;/span&gt;repeater3 &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__BuildControlrepeater3();&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(repeater3);&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;LiteralControl&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"\r\n\r\n"&lt;/span&gt;));&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;Repeater &lt;/span&gt;repeater4 &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__BuildControlrepeater4();&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(repeater4);&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;LiteralControl&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"\r\n\r\n"&lt;/span&gt;));&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;Repeater &lt;/span&gt;repeater5 &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__BuildControlrepeater5();&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(repeater5);&lt;br/&gt;            accessor&lt;span style="color:red"&gt;.&lt;/span&gt;AddParsedSubObject(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;LiteralControl&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"\r\n\r\n\r\n&amp;lt;/body&amp;gt;\r\n&amp;lt;/html&amp;gt;\r\n"&lt;/span&gt;));&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;protected override void &lt;/span&gt;FrameworkInitialize()&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;base&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;FrameworkInitialize();&lt;br/&gt;            &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__BuildControlTree(&lt;span style="color:blue"&gt;this&lt;/span&gt;);&lt;br/&gt;            &lt;span style="color:blue"&gt;base&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;AddWrappedFileDependencies(__fileDependencies);&lt;br/&gt;            &lt;span style="color:blue"&gt;base&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;ValidateInput();&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;public override int &lt;/span&gt;GetTypeHashCode()&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:red"&gt;-&lt;/span&gt;&lt;span style="color:purple"&gt;781896338&lt;/span&gt;;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;public override void &lt;/span&gt;ProcessRequest(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;base&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;ProcessRequest(context);&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;protected override bool &lt;/span&gt;SupportAutoEvents&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;get&lt;br/&gt;            &lt;/span&gt;{&lt;br/&gt;                &lt;span style="color:blue"&gt;return false&lt;/span&gt;;&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;从这个编译结果我们可以看出：页面上的所有文字最后也被包装到LiteralControl中。&lt;br /&gt;页面中呈现时，就是循环调用每个控件的Render方法来最终生成HTML结果。&lt;/p&gt;&lt;p&gt;测试用例2的页面被编译成这个样了：&lt;a href="javascript:void(0);" codeId="pre-testpage_inlinepage_aspx"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;namespace &lt;/span&gt;ASP&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;using &lt;/span&gt;System;&lt;br/&gt;    &lt;span style="color:blue"&gt;using &lt;/span&gt;System&lt;span style="color:red"&gt;.&lt;/span&gt;Diagnostics;&lt;br/&gt;    &lt;span style="color:blue"&gt;using &lt;/span&gt;System&lt;span style="color:red"&gt;.&lt;/span&gt;Runtime&lt;span style="color:red"&gt;.&lt;/span&gt;CompilerServices;&lt;br/&gt;    &lt;span style="color:blue"&gt;using &lt;/span&gt;System&lt;span style="color:red"&gt;.&lt;/span&gt;Web;&lt;br/&gt;    &lt;span style="color:blue"&gt;using &lt;/span&gt;System&lt;span style="color:red"&gt;.&lt;/span&gt;Web&lt;span style="color:red"&gt;.&lt;/span&gt;Profile;&lt;br/&gt;    &lt;span style="color:blue"&gt;using &lt;/span&gt;System&lt;span style="color:red"&gt;.&lt;/span&gt;Web&lt;span style="color:red"&gt;.&lt;/span&gt;UI;&lt;br/&gt;&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;CompilerGlobalScope&lt;/span&gt;]&lt;br/&gt;    &lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;testpage_inlinepage_aspx &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;Page&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;IHttpHandler&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color:blue"&gt;private static object &lt;/span&gt;__fileDependencies;&lt;br/&gt;        &lt;span style="color:blue"&gt;private static bool &lt;/span&gt;__initialized;&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;public &lt;/span&gt;testpage_inlinepage_aspx()&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;base&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;AppRelativeVirtualPath &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"~/TestPage/InlinePage.aspx"&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color:blue"&gt;if &lt;/span&gt;(&lt;span style="color:red"&gt;!&lt;/span&gt;__initialized)&lt;br/&gt;            {&lt;br/&gt;                &lt;span style="color:blue"&gt;string&lt;/span&gt;[] virtualFileDependencies &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new string&lt;/span&gt;[] { &lt;span style="color:#a31515"&gt;"~/TestPage/InlinePage.aspx" &lt;/span&gt;};&lt;br/&gt;                __fileDependencies &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;base&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetWrappedFileDependencies(virtualFileDependencies);&lt;br/&gt;                __initialized &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;true&lt;/span&gt;;&lt;br/&gt;            }&lt;br/&gt;            &lt;span style="color:blue"&gt;base&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Server&lt;span style="color:red"&gt;.&lt;/span&gt;ScriptTimeout &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0x1c9c380&lt;/span&gt;;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;private void &lt;/span&gt;__BuildControlTree(&lt;span style="color:#2b91af"&gt;testpage_inlinepage_aspx &lt;/span&gt;__ctrl)&lt;br/&gt;        {&lt;br/&gt;            __ctrl&lt;span style="color:red"&gt;.&lt;/span&gt;EnableViewState &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;false&lt;/span&gt;;&lt;br/&gt;            __ctrl&lt;span style="color:red"&gt;.&lt;/span&gt;EnableViewStateMac &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;false&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;InitializeCulture();&lt;br/&gt;            __ctrl&lt;span style="color:red"&gt;.&lt;/span&gt;SetRenderMethodDelegate(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;RenderMethod&lt;/span&gt;(&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__Render__control1));&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;private void &lt;/span&gt;__Render__control1(&lt;span style="color:#2b91af"&gt;HtmlTextWriter &lt;/span&gt;__w, &lt;span style="color:#2b91af"&gt;Control &lt;/span&gt;parameterContainer)&lt;br/&gt;        {&lt;br/&gt;            __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"\r\n\r\n&amp;lt;html xmlns=\"http://www.w3.org/1999/xhtml\"&amp;gt;\r\n&amp;lt;head&amp;gt;\r\n    &amp;lt;title&amp;gt;PagePerformanceTest   http://www.cnblogs.com/fish-li/&amp;lt;/title&amp;gt;\r\n&amp;lt;/head&amp;gt;\r\n&amp;lt;body&amp;gt;\r\n\r\n&amp;lt;p&amp;gt;This is InlinePage.aspx&amp;lt;/p&amp;gt;\r\n\r\n"&lt;/span&gt;);&lt;br/&gt;            &lt;span style="color:blue"&gt;foreach &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;BlogInfo &lt;/span&gt;info &lt;span style="color:blue"&gt;in &lt;/span&gt;&lt;span style="color:#2b91af"&gt;XmlDb&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Blogs)&lt;br/&gt;            {&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"\r\n\t&amp;lt;a href=\""&lt;/span&gt;);&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(info&lt;span style="color:red"&gt;.&lt;/span&gt;Href);&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"\" target=\"_blank\"&amp;gt;"&lt;/span&gt;);&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(info&lt;span style="color:red"&gt;.&lt;/span&gt;Title);&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"&amp;lt;/a&amp;gt;&amp;lt;br /&amp;gt;\r\n"&lt;/span&gt;);&lt;br/&gt;            }&lt;br/&gt;            __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"\r\n&amp;lt;hr /&amp;gt;\r\n\r\n"&lt;/span&gt;);&lt;br/&gt;            &lt;span style="color:blue"&gt;foreach &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;BlogInfo &lt;/span&gt;info2 &lt;span style="color:blue"&gt;in &lt;/span&gt;&lt;span style="color:#2b91af"&gt;XmlDb&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Blogs)&lt;br/&gt;            {&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"\r\n\t&amp;lt;a href=\""&lt;/span&gt;);&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(info2&lt;span style="color:red"&gt;.&lt;/span&gt;Href);&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"\" target=\"_blank\"&amp;gt;"&lt;/span&gt;);&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(info2&lt;span style="color:red"&gt;.&lt;/span&gt;Title);&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"&amp;lt;/a&amp;gt;&amp;lt;br /&amp;gt;\r\n"&lt;/span&gt;);&lt;br/&gt;            }&lt;br/&gt;            __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"\r\n&amp;lt;hr /&amp;gt;\r\n\r\n"&lt;/span&gt;);&lt;br/&gt;            &lt;span style="color:blue"&gt;foreach &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;BlogInfo &lt;/span&gt;info3 &lt;span style="color:blue"&gt;in &lt;/span&gt;&lt;span style="color:#2b91af"&gt;XmlDb&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Blogs)&lt;br/&gt;            {&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"\r\n\t&amp;lt;a href=\""&lt;/span&gt;);&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(info3&lt;span style="color:red"&gt;.&lt;/span&gt;Href);&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"\" target=\"_blank\"&amp;gt;"&lt;/span&gt;);&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(info3&lt;span style="color:red"&gt;.&lt;/span&gt;Title);&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"&amp;lt;/a&amp;gt;&amp;lt;br /&amp;gt;\r\n"&lt;/span&gt;);&lt;br/&gt;            }&lt;br/&gt;            __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"\r\n&amp;lt;hr /&amp;gt;\r\n\r\n"&lt;/span&gt;);&lt;br/&gt;            &lt;span style="color:blue"&gt;foreach &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;BlogInfo &lt;/span&gt;info4 &lt;span style="color:blue"&gt;in &lt;/span&gt;&lt;span style="color:#2b91af"&gt;XmlDb&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Blogs)&lt;br/&gt;            {&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"\r\n\t&amp;lt;a href=\""&lt;/span&gt;);&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(info4&lt;span style="color:red"&gt;.&lt;/span&gt;Href);&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"\" target=\"_blank\"&amp;gt;"&lt;/span&gt;);&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(info4&lt;span style="color:red"&gt;.&lt;/span&gt;Title);&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"&amp;lt;/a&amp;gt;&amp;lt;br /&amp;gt;\r\n"&lt;/span&gt;);&lt;br/&gt;            }&lt;br/&gt;            __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"\r\n&amp;lt;hr /&amp;gt;\r\n\r\n"&lt;/span&gt;);&lt;br/&gt;            &lt;span style="color:blue"&gt;foreach &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;BlogInfo &lt;/span&gt;info5 &lt;span style="color:blue"&gt;in &lt;/span&gt;&lt;span style="color:#2b91af"&gt;XmlDb&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Blogs)&lt;br/&gt;            {&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"\r\n\t&amp;lt;a href=\""&lt;/span&gt;);&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(info5&lt;span style="color:red"&gt;.&lt;/span&gt;Href);&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"\" target=\"_blank\"&amp;gt;"&lt;/span&gt;);&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(info5&lt;span style="color:red"&gt;.&lt;/span&gt;Title);&lt;br/&gt;                __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"&amp;lt;/a&amp;gt;&amp;lt;br /&amp;gt;\r\n"&lt;/span&gt;);&lt;br/&gt;            }&lt;br/&gt;            __w&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"\r\n&amp;lt;hr /&amp;gt;\r\n\r\n&amp;lt;/body&amp;gt;\r\n&amp;lt;/html&amp;gt;\r\n"&lt;/span&gt;);&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;protected override void &lt;/span&gt;FrameworkInitialize()&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;base&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;FrameworkInitialize();&lt;br/&gt;            &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__BuildControlTree(&lt;span style="color:blue"&gt;this&lt;/span&gt;);&lt;br/&gt;            &lt;span style="color:blue"&gt;base&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;AddWrappedFileDependencies(__fileDependencies);&lt;br/&gt;            &lt;span style="color:blue"&gt;base&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;ValidateInput();&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;public override int &lt;/span&gt;GetTypeHashCode()&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:red"&gt;-&lt;/span&gt;&lt;span style="color:purple"&gt;1307842476&lt;/span&gt;;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;DebuggerNonUserCode&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;public override void &lt;/span&gt;ProcessRequest(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;base&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;ProcessRequest(context);&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;protected &lt;/span&gt;&lt;span style="color:#2b91af"&gt;global_asax &lt;/span&gt;ApplicationInstance&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;get&lt;br/&gt;            &lt;/span&gt;{&lt;br/&gt;                &lt;span style="color:blue"&gt;return &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;global_asax&lt;/span&gt;) &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Context&lt;span style="color:red"&gt;.&lt;/span&gt;ApplicationInstance;&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;protected &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DefaultProfile &lt;/span&gt;Profile&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;get&lt;br/&gt;            &lt;/span&gt;{&lt;br/&gt;                &lt;span style="color:blue"&gt;return &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;DefaultProfile&lt;/span&gt;) &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Context&lt;span style="color:red"&gt;.&lt;/span&gt;Profile;&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;protected override bool &lt;/span&gt;SupportAutoEvents&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;get&lt;br/&gt;            &lt;/span&gt;{&lt;br/&gt;                &lt;span style="color:blue"&gt;return false&lt;/span&gt;;&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;&lt;b&gt;请注意下面这段关键的代码：&lt;/b&gt;&lt;b class="redText"&gt;它们实在太重要了。&lt;/b&gt;&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;private void &lt;/span&gt;__BuildControlTree(&lt;span style="color:#2b91af"&gt;testpage_inlinepage_aspx &lt;/span&gt;__ctrl)&lt;br/&gt;{&lt;br/&gt;   &lt;span style="color:green"&gt;// ....... &lt;br/&gt;    &lt;/span&gt;__ctrl&lt;span style="color:red"&gt;.&lt;/span&gt;SetRenderMethodDelegate(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;RenderMethod&lt;/span&gt;(&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;__Render__control1));&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;private void &lt;/span&gt;__Render__control1(&lt;span style="color:#2b91af"&gt;HtmlTextWriter &lt;/span&gt;__w, &lt;span style="color:#2b91af"&gt;Control &lt;/span&gt;parameterContainer)&lt;br/&gt;{&lt;br/&gt;&lt;br/&gt;&lt;p&gt;testpage_inlinepage_aspx与testpage_webfrompage_aspx的编译结果完全不同。&lt;br /&gt;最大的差别在testpage_inlinepage_aspx有个方法：&lt;b class="redText"&gt;__Render__control1&lt;/b&gt;&lt;br /&gt;在这个方法中，页面的内容将直接被写入到HtmlTextWriter对象中。&lt;br /&gt;还有一点我要告诉您：每个Control的输出最后还是要将自己的显示代码写入到HtmlTextWriter对象中。&lt;br /&gt;因此，从这里就可以明显地看出testpage_inlinepage_aspx的执行速度要快很多，&lt;br /&gt;因为：&lt;br /&gt;1. 它没有服务器控件。&lt;br /&gt;2. 不再需要递归循环每个控件，每个控件的生命周期的调用开销也节省了。&lt;br /&gt;3. 不用再创建那些服务器控件对象，GC的压力会小很多。&lt;br /&gt;4. 输出方式更高效。&lt;/p&gt;&lt;p&gt;通过前面的分析，您现在明白了为什么二个页面的执行速度相差6倍了原因了吧。&lt;/p&gt;&lt;p&gt;好像还有一点没有解释：&lt;b class="redText"&gt;__Render__control1&lt;/b&gt;如何被调用？&lt;/p&gt;&lt;p&gt;我们都知道：以ASPX页面为代表的WebForm编程模型在执行时有一个特点：&lt;b&gt;递归循环每个控件。&lt;/b&gt;&lt;br /&gt;页面是在Render阶段输出的，页面的HTML代码也是在那个阶段输出到HtmlTextWriter对象中的。&lt;br /&gt;可是，testpage_inlinepage_aspx没有任何控件，那又该如何&lt;b&gt;递归&lt;/b&gt;呢？&lt;/p&gt;&lt;p&gt;的确，很多书籍以及技术资料都是说：在Render阶段会&lt;b&gt;递归循环每个控件&lt;/b&gt;并调用控件的Render方法。&lt;/p&gt;&lt;p&gt;其实这种说法是不准确的。Control的Render方法在运行时，会调用下面这个方法：&lt;a href="javascript:void(0);" codeId="pre-RenderChildrenInternal"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal void &lt;/span&gt;RenderChildrenInternal(&lt;span style="color:#2b91af"&gt;HtmlTextWriter &lt;/span&gt;writer, &lt;span style="color:#2b91af"&gt;ICollection &lt;/span&gt;children)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;if &lt;/span&gt;((&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;RareFields &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;) &lt;span style="color:red"&gt;&amp;amp;&amp;amp; &lt;/span&gt;(&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;RareFields&lt;span style="color:red"&gt;.&lt;/span&gt;RenderMethod &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;))&lt;br/&gt;    {&lt;br/&gt;        writer&lt;span style="color:red"&gt;.&lt;/span&gt;BeginRender();&lt;br/&gt;        &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;RareFields&lt;span style="color:red"&gt;.&lt;/span&gt;RenderMethod(writer, &lt;span style="color:blue"&gt;this&lt;/span&gt;);&lt;br/&gt;        writer&lt;span style="color:red"&gt;.&lt;/span&gt;EndRender();&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;else if &lt;/span&gt;(children &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;foreach &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;Control &lt;/span&gt;control &lt;span style="color:blue"&gt;in &lt;/span&gt;children)&lt;br/&gt;        {&lt;br/&gt;            control&lt;span style="color:red"&gt;.&lt;/span&gt;RenderControl(writer);&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;这段代码中，有个重要的if...else...判断，简单说来，就是说要不要调用前面所说的&lt;b class="redText"&gt;__Render__control1&lt;/b&gt;方法。&lt;br /&gt;从代码可以看出，如果是进入了if语句块，则不用&lt;b&gt;递归循环每个控件&lt;/b&gt;并调用控件的Render方法。&lt;/p&gt;&lt;p&gt;那么如何能进入if语句块呢？&lt;br /&gt;答案是：&lt;b&gt;调用Control.SetRenderMethodDelegate方法。&lt;/b&gt;&lt;br /&gt;testpage_inlinepage_aspx的编译生成代码中就有这个调用。&lt;br /&gt;对于这个方法，MSDN的解释很含糊：&lt;/p&gt;&lt;p class="msdnRef"&gt;此 API 支持 .NET Framework 基础结构，不适合在代码中直接使用。&lt;br /&gt;&lt;br /&gt;分配事件处理程序委托，以将服务器控件及其内容呈现到父控件中。 &lt;/p&gt;&lt;p&gt;&lt;strong&gt;测试用例３：InlineUserControl.ascx&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在测试用例3中，我将页面中用于输出的代码移到一个用户控件中。&lt;br /&gt;用户控件的代码此处省略，与测试用例2的代码基本上一致。编译后的结果也基本差不多。&lt;/p&gt;&lt;p&gt;测试代码：&lt;a href="javascript:void(0);" codeId="pre-Test3"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public object &lt;/span&gt;Test3(&lt;span style="color:blue"&gt;string &lt;/span&gt;callTimes)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;int &lt;/span&gt;count &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;;&lt;br/&gt;    &lt;span style="color:blue"&gt;int&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;TryParse(callTimes, &lt;span style="color:blue"&gt;out &lt;/span&gt;count);&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( count &lt;span style="color:red"&gt;&amp;lt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;)&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;count;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 先执行一次，排除编译时间&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;string &lt;/span&gt;html &lt;span style="color:red"&gt;= &lt;/span&gt;MyMVC&lt;span style="color:red"&gt;.&lt;/span&gt;&lt;span style="color:#2b91af"&gt;UcExecutor&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Render(&lt;span style="color:#a31515"&gt;"/UserControl/InlineUserControl.ascx"&lt;/span&gt;, &lt;span style="color:blue"&gt;null&lt;/span&gt;);&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color:#2b91af"&gt;Stopwatch &lt;/span&gt;watch &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Stopwatch&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;StartNew();&lt;br/&gt;    &lt;span style="color:blue"&gt;for&lt;/span&gt;( &lt;span style="color:blue"&gt;int &lt;/span&gt;i &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;; i &lt;span style="color:red"&gt;&amp;lt; &lt;/span&gt;count; i&lt;span style="color:red"&gt;++ &lt;/span&gt;)&lt;br/&gt;        html &lt;span style="color:red"&gt;= &lt;/span&gt;MyMVC&lt;span style="color:red"&gt;.&lt;/span&gt;&lt;span style="color:#2b91af"&gt;UcExecutor&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Render(&lt;span style="color:#a31515"&gt;"/UserControl/InlineUserControl.ascx"&lt;/span&gt;, &lt;span style="color:blue"&gt;null&lt;/span&gt;);&lt;br/&gt;    watch&lt;span style="color:red"&gt;.&lt;/span&gt;Stop();&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;watch&lt;span style="color:red"&gt;.&lt;/span&gt;Elapsed&lt;span style="color:red"&gt;.&lt;/span&gt;ToString();&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;当我测试执行&lt;b class="redText"&gt;10000&lt;/b&gt;次时，耗时：&lt;b class="redText"&gt;00:00:00.9132738&lt;/b&gt;&lt;/p&gt;&lt;p&gt;又快了一点。&lt;/p&gt;&lt;p&gt;说明：为了这次的性能优化，&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/21/2361982.html" target="_blank"&gt;&lt;b&gt;MyMVC框架&lt;/b&gt;&lt;/a&gt;也做了一点调整。如果您以前下载过这个框架，请重新下载。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;分析优化结果２&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;经过前面的分析，我们知道：不创建服务器控件对象以及不调用它们的生命周期，可以让页面的执行速度快很多。&lt;/p&gt;&lt;p&gt;有没有再想像一下：页面也有生命周期啊，而且生命周期的步骤更长，省略它，会不会更快呢？&lt;/p&gt;&lt;p&gt;不过，Render方法并不是个public方法，我们还不能直接调用，但可以调用RenderControl方法来实现这一过程。&lt;/p&gt;&lt;p&gt;由于跳过页面的生命周期，任何服务器控件都不能使用了，包括母板页。所以我选择将前面测试用的那段代码移到用户控件中，然后将用户控件加载到Page中来测试。&lt;/p&gt;&lt;p&gt;测试用例3与测试用例2相比，在测试过程中，由于跳过了页面的生命周期，因此速度也就更快了。&lt;br /&gt;注意：&lt;b&gt;事实上，动态加载用户控件也会有一定的调用开销。&lt;/b&gt;这种方法也仅供参考，可以根据实际情况来选择。&lt;/p&gt;&lt;p&gt;嗯，基本上，就是这个简单的原因吧。&lt;/p&gt;&lt;p&gt;&lt;b&gt;由于这种方法没有任何的控件生命周期，因此速度是最快的。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;经过这一系列的优化，页面的执行时间最终由 &lt;b class="redText"&gt;00:00:07.5607229&lt;/b&gt; 减少到 &lt;b class="redText"&gt;00:00:00.9132738&lt;/b&gt;&lt;/p&gt;&lt;p class="redText" style="font-size: 13pt; line-height: 150%"&gt;再次申明：测试结果也仅仅只是一个参考数字。&lt;br /&gt;事实上，使用服务器控件产生的对象涉及到GC的回收以及内存占用的影响也是不可忽视的。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://files.cnblogs.com/fish-li/PagePerformanceTest.cab.7z"&gt;点击此处下载示例代码&lt;/a&gt;&lt;/p&gt;&lt;div class="articleFooter"&gt;&lt;p&gt;如果，您认为阅读这篇博客让您有些收获，不妨点击一下右下角的&lt;a id="btnRecommendMyBlog" href="javascript:void(0);"&gt;【&lt;b&gt;推荐&lt;/b&gt;】&lt;/a&gt;按钮。&lt;br /&gt;如果，您希望更容易地发现我的新博客，不妨点击一下右下角的&lt;a id="btnFollowFishLi" href="javascript:void(0);"&gt;【&lt;b&gt;关注 Fish Li&lt;/b&gt;】&lt;/a&gt;。&lt;br /&gt;因为，我的写作热情也离不开您的肯定支持。&lt;/p&gt;&lt;p&gt;感谢您的阅读，如果您对我的博客所讲述的内容有兴趣，请继续关注我的后续博客，我是Fish Li 。&lt;span class="icon_smile"&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/fish-li/aggbug/2390569.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/03/11/2390569.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/fish-li/archive/2012/03/04/2379612.html</id><title type="text">用ASP.NET写个SQLSERVER的小工具</title><summary type="text">2001年4月份，我在博客中发过一个小工具，它是一个用ASP.NET写的SQL SERVER的辅助小工具。在这期间，有些人貌似对那个工具比较有兴趣，所以我常能收到索要源代码的邮件。正好，我上月又发布了我的MVC框架，因此打算用【我的ASP.NET MVC框架】来重写这个工具，并开源。工具的特点：1. 采用ASP.NET编写，并借助MyMVC框架。2. 为了更好地接近桌面程序的操作体验，网站采用纯AJAX的方式实现。3. 界面使用了 JQuery Easy UI4. 代码的语法着色使用了 syntaxhighlighter (JavaScript类库)工具的定位：只是辅助工具，因此功能有限，但要</summary><published>2012-03-04T13:24:00Z</published><updated>2012-03-04T13:24:00Z</updated><author><name>Fish Li</name><uri>http://www.cnblogs.com/fish-li/</uri></author><link rel="alternate" href="http://www.cnblogs.com/fish-li/archive/2012/03/04/2379612.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/fish-li/archive/2012/03/04/2379612.html"/><content type="html">&lt;p&gt;2001年4月份，我在博客中发过一个小工具，它是一个用ASP.NET写的SQL SERVER的辅助小工具。在这期间，有些人貌似对那个工具比较有兴趣，所以我常能收到索要源代码的邮件。正好，我上月又发布了我的MVC框架，因此打算用&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/21/2361982.html" target="_blank"&gt;【我的ASP.NET MVC框架】&lt;/a&gt;来重写这个工具，&lt;b class="redText"&gt;并开源。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;工具的特点：&lt;br /&gt;1. 采用ASP.NET编写，并借助&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/21/2361982.html" target="_blank"&gt;&lt;b&gt;MyMVC框架&lt;/b&gt;&lt;/a&gt;。&lt;br /&gt;2. 为了更好地接近桌面程序的操作体验，网站采用纯AJAX的方式实现。&lt;br /&gt;3. 界面使用了 JQuery Easy UI&lt;br /&gt;4. 代码的语法着色使用了 syntaxhighlighter (JavaScript类库)&lt;/p&gt;&lt;p&gt;工具的定位：&lt;b class="redText"&gt;只是辅助工具，因此功能有限，但要将有限的功能做得尽量好。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;下面将分别介绍工具所能完成的功能，以及&lt;b&gt;关键的实现代码。&lt;/b&gt;&lt;br /&gt;说明：工具的所有源代码可以在本文的结尾处下载。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;项目介绍&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;整个工具的源代码结构如下：&lt;/p&gt;&lt;table border="0" cellspacing="8"&gt;&lt;tr&gt;&lt;td&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012030421112720.png" alt="" /&gt;&lt;/td&gt;&lt;td style="padding: 10px; vertical-align: top;"&gt;项目由Visual Studio 2008创建，包含三个部分：&lt;br /&gt;&lt;br /&gt;1. WebApp：一个ASP.NET网站，它是工具的可运行部分。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;网站只包含一些HTML, CSS, JavaScript，DLL文件。&lt;br /&gt;&lt;br /&gt;2. MyMvcEx：一个类库项目，它提供了&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/21/2361982.html" target="_blank"&gt;&lt;b&gt;MyMVC框架&lt;/b&gt;&lt;/a&gt;的二个IActionResult接口的实现类，&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;用于向浏览器客户端输出DataTable, DataSet&lt;br /&gt;&lt;br /&gt;3. SqlServerSmallToolLib：运行网站所需的所有后台代码，&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;包括：Controller，BLL类，等等。&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;p&gt;&lt;strong&gt;MyMVC框架发挥的作用&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;从前面的项目介绍中，我们可以看到，整个网站没有一个ASPX文件，只有HTML文件，&lt;br /&gt;所有对服务器的调用全由AJAX来实现，比如：下面的【比较数据库】的代码片段：&lt;/p&gt;&lt;br/&gt;$.ajax({&lt;br/&gt;    cache&lt;span style="color:red"&gt;: &lt;/span&gt;&lt;span style="color:blue"&gt;false&lt;/span&gt;&lt;span style="color:red"&gt;, &lt;/span&gt;dataType&lt;span style="color:red"&gt;: &lt;/span&gt;&lt;span style="color:#a31515"&gt;"json"&lt;/span&gt;&lt;span style="color:red"&gt;, &lt;/span&gt;type&lt;span style="color:red"&gt;: &lt;/span&gt;&lt;span style="color:#a31515"&gt;"GET"&lt;/span&gt;&lt;span style="color:red"&gt;,&lt;br/&gt;    &lt;/span&gt;&lt;span style="font-size: large"&gt;&lt;b&gt;url&lt;/b&gt;&lt;span &lt;br/&gt;style="color:red; font-weight: bold;"&gt;: &lt;/span&gt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;&lt;span &lt;br/&gt;style="font-size: large; font-weight: bold"&gt;'/AjaxService/CompareDB.cspx'&lt;/span&gt;&lt;/span&gt;&lt;span style="color:red"&gt;,&lt;br/&gt;    &lt;/span&gt;data&lt;span style="color:red"&gt;:&lt;/span&gt;{  srcConnId&lt;span style="color:red"&gt;: &lt;/span&gt;$(&lt;span style="color:#a31515"&gt;"#hfSrcConnId"&lt;/span&gt;).val()&lt;span style="color:red"&gt;, &lt;br/&gt;            &lt;/span&gt;destConnId&lt;span style="color:red"&gt;: &lt;/span&gt;$(&lt;span style="color:#a31515"&gt;"#hfDestConnId"&lt;/span&gt;).val()&lt;span style="color:red"&gt;, &lt;br/&gt;            &lt;/span&gt;srcDB&lt;span style="color:red"&gt;: &lt;/span&gt;$(&lt;span style="color:#a31515"&gt;"#cboSrcDB"&lt;/span&gt;).combobox(&lt;span style="color:#a31515"&gt;"getValue"&lt;/span&gt;)&lt;span style="color:red"&gt;, &lt;br/&gt;            &lt;/span&gt;destDB&lt;span style="color:red"&gt;: &lt;/span&gt;$(&lt;span style="color:#a31515"&gt;"#cboDestDB"&lt;/span&gt;).combobox(&lt;span style="color:#a31515"&gt;"getValue"&lt;/span&gt;) &lt;span style="color:red"&gt;,&lt;br/&gt;            &lt;/span&gt;flag&lt;span style="color:red"&gt;: &lt;/span&gt;flag&lt;br/&gt;    }&lt;span style="color:red"&gt;,&lt;/span&gt;&lt;br/&gt;&lt;p&gt;在服务端，我只要实现这样一个C#方法就可以响应客户端的请求了：&lt;/p&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public object &lt;/span&gt;&lt;span &lt;br/&gt;style="font-size: large; font-weight: bold"&gt;CompareDB&lt;/span&gt;(&lt;span style="color:blue"&gt;string &lt;/span&gt;srcConnId, &lt;span style="color:blue"&gt;string &lt;/span&gt;destConnId, &lt;span style="color:blue"&gt;string &lt;/span&gt;srcDB, &lt;span style="color:blue"&gt;string &lt;/span&gt;destDB, &lt;span style="color:blue"&gt;string &lt;/span&gt;flag)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;var &lt;/span&gt;result &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompareDBHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;CompareDB(srcConnId, destConnId, srcDB, destDB, flag);&lt;br/&gt;    &lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;JsonResult&lt;/span&gt;(result);&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;至于说：JS发起的请求是如何调用到这个C#方法的，以及这个C#方法在调用时的参数和返回值的处理，全由&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/21/2361982.html" target="_blank"&gt;&lt;b&gt;MyMVC框架&lt;/b&gt;&lt;/a&gt;来实现。&lt;br /&gt;对于开发AJAX来说，可以不用关心这个问题，只要写出一个C#方法给JS调用就可以了。&lt;/p&gt;&lt;p&gt;引用MyMVC是件很简单的事情，只需要在web.config中做如下的配置即可：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;add &lt;/span&gt;&lt;span style="color:red"&gt;path&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*.cspx&lt;/span&gt;" &lt;span style="color:red"&gt;verb&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*&lt;/span&gt;" &lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;MyMVC.AjaxHandlerFactory, MyMVC&lt;/span&gt;" &lt;span style="color:red"&gt;validate&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;true&lt;/span&gt;" &lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;再补充一点：如果不喜欢看到Action方法包含较多的输入参数，也可以使用下面的方法：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompareDbOption&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;SrcConnId;&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;DestConnId;&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;SrcDb;&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;DestDb;&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;Flag;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public object &lt;/span&gt;CompareDB(&lt;span style="color:#2b91af"&gt;CompareDbOption &lt;/span&gt;option)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;var &lt;/span&gt;result &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompareDBHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;CompareDB(option&lt;span style="color:red"&gt;.&lt;/span&gt;SrcConnId, option&lt;span style="color:red"&gt;.&lt;/span&gt;DestConnId, &lt;br/&gt;                                            option&lt;span style="color:red"&gt;.&lt;/span&gt;SrcDb, option&lt;span style="color:red"&gt;.&lt;/span&gt;DestDb, option&lt;span style="color:red"&gt;.&lt;/span&gt;Flag);&lt;br/&gt;    &lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;JsonResult&lt;/span&gt;(result);&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;如果您喜欢在浏览器的客户端中使用jquery以及jquery.form.js插件，&lt;br /&gt;您会发现在服务端再借助&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/21/2361982.html" target="_blank"&gt;&lt;b&gt;MyMVC框架&lt;/b&gt;&lt;/a&gt;来实现AJAX实在是太方便了。&lt;br /&gt;再来一个添加连接的代码片段：&lt;/p&gt;&lt;p&gt;Html表单代码：&lt;a href="javascript:void(0);" codeId="pre-formConnection"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;div &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="divConnectionDialog" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;padding&lt;/span&gt;:&lt;span style="color:blue"&gt;10px&lt;/span&gt;; &lt;span style="color:red"&gt;width&lt;/span&gt;: &lt;span style="color:blue"&gt;420px&lt;/span&gt;; &lt;span style="color:red"&gt;height&lt;/span&gt;: &lt;span style="color:blue"&gt;320px&lt;/span&gt;; &lt;span style="color:red"&gt;display&lt;/span&gt;: &lt;span style="color:blue"&gt;none&lt;/span&gt;;&lt;span style="color:blue"&gt;" &lt;/span&gt;&lt;span style="color:red"&gt;title&lt;/span&gt;&lt;span style="color:blue"&gt;="新增/编辑 数据库连接信息"&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;form &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="formConnection" &lt;/span&gt;&lt;span style="color:red"&gt;method&lt;/span&gt;&lt;span style="color:blue"&gt;="post" &lt;/span&gt;&lt;span style="color:red"&gt;&lt;span &lt;br/&gt;style="font-size: large; font-weight: bold"&gt;action&lt;/span&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&lt;span &lt;br/&gt;style="font-size: large; font-weight: bold"&gt;="/AjaxService/SubmitConnectionInfo.cspx"&lt;/span&gt;&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;table &lt;/span&gt;&lt;span style="color:red"&gt;cellpadding&lt;/span&gt;&lt;span style="color:blue"&gt;="4" &lt;/span&gt;&lt;span style="color:red"&gt;cellspacing&lt;/span&gt;&lt;span style="color:blue"&gt;="0" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;: &lt;span style="color:blue"&gt;100%&lt;/span&gt;; &lt;span style="color:red"&gt;border&lt;/span&gt;: &lt;span style="color:blue"&gt;0px&lt;/span&gt;;&lt;span style="color:blue"&gt;"&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;服务器IP/Name&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="txtServerIP" &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="ServerIP" &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text" &lt;/span&gt;&lt;span style="color:red"&gt;class&lt;/span&gt;&lt;span style="color:blue"&gt;="myTextbox" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;: &lt;span style="color:blue"&gt;220px" /&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;登录方式&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;select &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="cboSSPI" &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="SSPI" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;: &lt;span style="color:blue"&gt;222px" &lt;/span&gt;&lt;span style="color:red"&gt;panelWidth&lt;/span&gt;&lt;span style="color:blue"&gt;="222"&amp;gt;&lt;br/&gt;            &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;option &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="false"&amp;gt;&lt;/span&gt;用户名／密码&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;option&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;            &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;option &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="true"&amp;gt;&lt;/span&gt;Windows连接&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;option&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;select&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;登录名&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="txtUserName" &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="UserName" &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text" &lt;/span&gt;&lt;span style="color:red"&gt;class&lt;/span&gt;&lt;span style="color:blue"&gt;="myTextbox" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;: &lt;span style="color:blue"&gt;220px" /&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;登录密码&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="txtPassword" &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="Password" &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text" &lt;/span&gt;&lt;span style="color:red"&gt;class&lt;/span&gt;&lt;span style="color:blue"&gt;="myTextbox" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;: &lt;span style="color:blue"&gt;220px" /&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="hfConnectionId" &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="ConnectionId" &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="hidden" &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="" /&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;table&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;div&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;span &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="spanWait" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;display&lt;/span&gt;: &lt;span style="color:blue"&gt;none&lt;/span&gt;;&lt;span style="color:blue"&gt;" &lt;/span&gt;&lt;span style="color:red"&gt;class&lt;/span&gt;&lt;span style="color:blue"&gt;="waitText"&amp;gt;&lt;/span&gt;请稍后......&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;span&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;div&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;form&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;div&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;JavaScript提交表单代码：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;function &lt;/span&gt;SubmitConnectionForm(){&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( ValidateForm() &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;) &lt;span style="color:blue"&gt;return false&lt;/span&gt;;&lt;br/&gt;    &lt;span style="font-size: large"&gt;&lt;b&gt;$(&lt;/b&gt;&lt;span &lt;br/&gt;style="color:#a31515; font-weight: bold;"&gt;"#formConnection"&lt;/span&gt;&lt;b&gt;).ajaxSubmit({&lt;/b&gt;&lt;/span&gt;&lt;br/&gt;        success&lt;span style="color:red"&gt;: &lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt;(responseText&lt;span style="color:red"&gt;, &lt;/span&gt;statusText) {            &lt;br/&gt;            &lt;span style="color:blue"&gt;if &lt;/span&gt;(responseText &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:#a31515"&gt;"update OK" &lt;/span&gt;){&lt;br/&gt;                $(&lt;span style="color:#a31515"&gt;'#divConnectionDialog'&lt;/span&gt;).dialog(&lt;span style="color:#a31515"&gt;'close'&lt;/span&gt;);&lt;br/&gt;                &lt;span style="color:green"&gt;// 省略后面的代码。&lt;/span&gt;&lt;br/&gt;&lt;p&gt;服务端C#代码：&lt;/p&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public string &lt;/span&gt;&lt;span &lt;br/&gt;style="font-size: large; font-weight: bold"&gt;SubmitConnectionInfo&lt;/span&gt;(&lt;span style="color:#2b91af"&gt;ConnectionInfo &lt;/span&gt;info)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(info&lt;span style="color:red"&gt;.&lt;/span&gt;ServerIP) )&lt;br/&gt;        &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyMessageException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"ServerIP is empty."&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( info&lt;span style="color:red"&gt;.&lt;/span&gt;SSPI &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;&lt;span style="color:red"&gt;&amp;amp;&amp;amp; &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(info&lt;span style="color:red"&gt;.&lt;/span&gt;UserName) )&lt;br/&gt;        &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyMessageException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"UserName is empty."&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;bool &lt;/span&gt;isAdd &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(info&lt;span style="color:red"&gt;.&lt;/span&gt;ConnectionId);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( isAdd ) {&lt;br/&gt;        info&lt;span style="color:red"&gt;.&lt;/span&gt;ConnectionId &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Guid&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;NewGuid()&lt;span style="color:red"&gt;.&lt;/span&gt;ToString();&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;ConnectionManager&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;AddConnection(info);&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;info&lt;span style="color:red"&gt;.&lt;/span&gt;ConnectionId;&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;else &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;ConnectionManager&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;UpdateConnection(info);&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:#a31515"&gt;"update OK"&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public sealed class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ConnectionInfo&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;ConnectionId;&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;ServerIP;&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;UserName;&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;Password;&lt;br/&gt;    &lt;span style="color:blue"&gt;public bool &lt;/span&gt;SSPI;&lt;br/&gt;    &lt;span style="color:blue"&gt;public int &lt;/span&gt;Priority;&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;在整个工具的开发过程中，由于使用了&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/21/2361982.html" target="_blank"&gt;&lt;b&gt;MyMVC框架&lt;/b&gt;&lt;/a&gt;以及JQuery，AJAX的实现简直是太容易了。&lt;/p&gt;&lt;p&gt;MyMVC框架的下载地址：&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/21/2361982.html" target="_blank"&gt;http://www.cnblogs.com/fish-li/archive/2012/02/21/2361982.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;工具主界面&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;工具启动后，将能看到下面的主界面：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012030421120927.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;主界面的左边的【工具列表】中包含二个独立的功能模块。&lt;br /&gt;右边的上方区域是所有的数据库连接的列表。&lt;br /&gt;建议在初次使用时，将自己所需要访问的SQL SERVER连接参数配置好。&lt;/p&gt;&lt;p&gt;这个工具可以管理多个连接，而且会根据连接的使用频率来排序，以方便操作。&lt;br /&gt;如果需要创建一个连接，可以点击工具栏中的【新增连接】按键，将出现以下对话框。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012030421122856.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;工具可以支持二种连接方式：1. Windows信任连接，2. 用户名/密码连接。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012030421124833.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;数据库连接列表的部分网页代码：&lt;a href="javascript:void(0);" codeId="pre-connection-html"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;div &lt;/span&gt;&lt;span style="color:red"&gt;region&lt;/span&gt;&lt;span style="color:blue"&gt;="center" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;overflow&lt;/span&gt;:&lt;span style="color:blue"&gt;hidden&lt;/span&gt;;&lt;span style="color:blue"&gt;" &lt;/span&gt;&lt;span style="color:red"&gt;title&lt;/span&gt;&lt;span style="color:blue"&gt;="数据库连接列表" &lt;/span&gt;&lt;span style="color:red"&gt;iconCls&lt;/span&gt;&lt;span style="color:blue"&gt;="icon-Relation"&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;div &lt;/span&gt;&lt;span style="color:red"&gt;class&lt;/span&gt;&lt;span style="color:blue"&gt;="easyui-layout" &lt;/span&gt;&lt;span style="color:red"&gt;fit&lt;/span&gt;&lt;span style="color:blue"&gt;="true" &lt;/span&gt;&lt;span style="color:red"&gt;border&lt;/span&gt;&lt;span style="color:blue"&gt;="false"&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;div &lt;/span&gt;&lt;span style="color:red"&gt;region&lt;/span&gt;&lt;span style="color:blue"&gt;="center"&amp;gt;&lt;br/&gt;            &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;table &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="tblConnList"&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;table&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;div&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;div &lt;/span&gt;&lt;span style="color:red"&gt;region&lt;/span&gt;&lt;span style="color:blue"&gt;="south" &lt;/span&gt;&lt;span style="color:red"&gt;split&lt;/span&gt;&lt;span style="color:blue"&gt;="true" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;height&lt;/span&gt;:&lt;span style="color:blue"&gt;220px&lt;/span&gt;; &lt;span style="color:red"&gt;padding&lt;/span&gt;: &lt;span style="color:blue"&gt;10px&lt;/span&gt;;&lt;span style="color:blue"&gt;" &lt;/span&gt;&lt;span style="color:red"&gt;title&lt;/span&gt;&lt;span style="color:blue"&gt;="操作说明" &lt;/span&gt;&lt;span style="color:red"&gt;iconCls&lt;/span&gt;&lt;span style="color:blue"&gt;="icon-help"&amp;gt;&lt;br/&gt;            &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;1. “新增连接”，“删除连接”，“设置连接”用于维护连接记录。&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;            &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;2. “打开连接”将根据选择的连接，打开 Database 对象浏览页面。&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;div&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;div&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;div&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;连接采用XML文件来保存，相关的操作代码：&lt;a href="javascript:void(0);" codeId="pre-ConnectionManager"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal static class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ConnectionManager&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;private static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ConnectionInfo&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;s_list &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;    &lt;span style="color:blue"&gt;private static readonly &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Encoding &lt;/span&gt;DefaultEncoding &lt;span style="color:red"&gt;= &lt;/span&gt;System&lt;span style="color:red"&gt;.&lt;/span&gt;Text&lt;span style="color:red"&gt;.&lt;/span&gt;&lt;span style="color:#2b91af"&gt;Encoding&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Unicode;&lt;br/&gt;    &lt;span style="color:blue"&gt;private static readonly string &lt;/span&gt;s_savePath &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Path&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Combine(&lt;span style="color:#2b91af"&gt;HttpRuntime&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;AppDomainAppPath, &lt;span style="color:#a31515"&gt;@"App_Data\Connection.xml"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;static &lt;/span&gt;ConnectionManager()&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;try &lt;/span&gt;{&lt;br/&gt;            &lt;span style="color:blue"&gt;string &lt;/span&gt;appDataPath &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Path&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Combine(&lt;span style="color:#2b91af"&gt;HttpRuntime&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;AppDomainAppPath, &lt;span style="color:#a31515"&gt;"App_Data"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;Directory&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Exists(appDataPath) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;)&lt;br/&gt;                &lt;span style="color:#2b91af"&gt;Directory&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;CreateDirectory(appDataPath);&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color:blue"&gt;catch &lt;/span&gt;{ }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;MethodImpl&lt;/span&gt;(&lt;span style="color:#2b91af"&gt;MethodImplOptions&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Synchronized)]&lt;br/&gt;    &lt;span style="color:blue"&gt;public static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ConnectionInfo&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;GetList()&lt;br/&gt;    {&lt;br/&gt;        EnsureListLoaded();&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 调用这个方法应该会比“修改”的次数会少很多，所以决定在这里排序。&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:blue"&gt;return &lt;/span&gt;(&lt;span style="color:blue"&gt;from &lt;/span&gt;c &lt;span style="color:blue"&gt;in &lt;/span&gt;s_list &lt;span style="color:blue"&gt;orderby &lt;/span&gt;c&lt;span style="color:red"&gt;.&lt;/span&gt;Priority &lt;span style="color:blue"&gt;descending select &lt;/span&gt;c)&lt;span style="color:red"&gt;.&lt;/span&gt;ToList();&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;MethodImpl&lt;/span&gt;(&lt;span style="color:#2b91af"&gt;MethodImplOptions&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Synchronized)]&lt;br/&gt;    &lt;span style="color:blue"&gt;public static void &lt;/span&gt;AddConnection(&lt;span style="color:#2b91af"&gt;ConnectionInfo &lt;/span&gt;info)&lt;br/&gt;    {&lt;br/&gt;        EnsureListLoaded();&lt;br/&gt;&lt;br/&gt;        s_list&lt;span style="color:red"&gt;.&lt;/span&gt;Add(info);&lt;br/&gt;        SaveListToFile();&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;MethodImpl&lt;/span&gt;(&lt;span style="color:#2b91af"&gt;MethodImplOptions&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Synchronized)]&lt;br/&gt;    &lt;span style="color:blue"&gt;public static void &lt;/span&gt;RemoveConnection(&lt;span style="color:blue"&gt;string &lt;/span&gt;ConnectionId)&lt;br/&gt;    {&lt;br/&gt;        EnsureListLoaded();&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;int &lt;/span&gt;index &lt;span style="color:red"&gt;= -&lt;/span&gt;&lt;span style="color:purple"&gt;1&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color:blue"&gt;for&lt;/span&gt;( &lt;span style="color:blue"&gt;int &lt;/span&gt;i &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;; i &lt;span style="color:red"&gt;&amp;lt; &lt;/span&gt;s_list&lt;span style="color:red"&gt;.&lt;/span&gt;Count; i&lt;span style="color:red"&gt;++ &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( s_list[i]&lt;span style="color:red"&gt;.&lt;/span&gt;ConnectionId &lt;span style="color:red"&gt;== &lt;/span&gt;ConnectionId ) {&lt;br/&gt;                index &lt;span style="color:red"&gt;= &lt;/span&gt;i;&lt;br/&gt;                &lt;span style="color:blue"&gt;break&lt;/span&gt;;&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( index &lt;span style="color:red"&gt;&amp;gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;) {&lt;br/&gt;            s_list&lt;span style="color:red"&gt;.&lt;/span&gt;RemoveAt(index);&lt;br/&gt;            SaveListToFile();&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;MethodImpl&lt;/span&gt;(&lt;span style="color:#2b91af"&gt;MethodImplOptions&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Synchronized)]&lt;br/&gt;    &lt;span style="color:blue"&gt;public static void &lt;/span&gt;UpdateConnection(&lt;span style="color:#2b91af"&gt;ConnectionInfo &lt;/span&gt;info)&lt;br/&gt;    {&lt;br/&gt;        EnsureListLoaded();&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;ConnectionInfo &lt;/span&gt;exist &lt;span style="color:red"&gt;= &lt;/span&gt;s_list&lt;span style="color:red"&gt;.&lt;/span&gt;FirstOrDefault(x &lt;span style="color:red"&gt;=&amp;gt; &lt;/span&gt;x&lt;span style="color:red"&gt;.&lt;/span&gt;ConnectionId &lt;span style="color:red"&gt;== &lt;/span&gt;info&lt;span style="color:red"&gt;.&lt;/span&gt;ConnectionId);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( exist &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) {&lt;br/&gt;            exist&lt;span style="color:red"&gt;.&lt;/span&gt;ServerIP &lt;span style="color:red"&gt;= &lt;/span&gt;info&lt;span style="color:red"&gt;.&lt;/span&gt;ServerIP;&lt;br/&gt;            exist&lt;span style="color:red"&gt;.&lt;/span&gt;UserName &lt;span style="color:red"&gt;= &lt;/span&gt;info&lt;span style="color:red"&gt;.&lt;/span&gt;UserName;&lt;br/&gt;            exist&lt;span style="color:red"&gt;.&lt;/span&gt;Password &lt;span style="color:red"&gt;= &lt;/span&gt;info&lt;span style="color:red"&gt;.&lt;/span&gt;Password;&lt;br/&gt;            exist&lt;span style="color:red"&gt;.&lt;/span&gt;SSPI &lt;span style="color:red"&gt;= &lt;/span&gt;info&lt;span style="color:red"&gt;.&lt;/span&gt;SSPI;&lt;br/&gt;            &lt;span style="color:green"&gt;// 注意：其它没列出的成员，表示不需要在此更新。&lt;br/&gt;            &lt;/span&gt;SaveListToFile();&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;MethodImpl&lt;/span&gt;(&lt;span style="color:#2b91af"&gt;MethodImplOptions&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Synchronized)]&lt;br/&gt;    &lt;span style="color:blue"&gt;public static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ConnectionInfo &lt;/span&gt;GetConnectionInfoById(&lt;span style="color:blue"&gt;string &lt;/span&gt;connectionId, &lt;span style="color:blue"&gt;bool &lt;/span&gt;increasePriority)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(connectionId) )&lt;br/&gt;            &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"connectionId"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;        EnsureListLoaded();&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;ConnectionInfo &lt;/span&gt;exist &lt;span style="color:red"&gt;= &lt;/span&gt;s_list&lt;span style="color:red"&gt;.&lt;/span&gt;FirstOrDefault(x &lt;span style="color:red"&gt;=&amp;gt; &lt;/span&gt;x&lt;span style="color:red"&gt;.&lt;/span&gt;ConnectionId &lt;span style="color:red"&gt;== &lt;/span&gt;connectionId);&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( exist &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyMessageException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"connectionId is invalid."&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( increasePriority ) {&lt;br/&gt;            exist&lt;span style="color:red"&gt;.&lt;/span&gt;Priority&lt;span style="color:red"&gt;++&lt;/span&gt;;&lt;br/&gt;            SaveListToFile();&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;exist;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;private static void &lt;/span&gt;EnsureListLoaded()&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( s_list &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) {&lt;br/&gt;            &lt;span style="color:blue"&gt;try &lt;/span&gt;{&lt;br/&gt;                s_list &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;XmlHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;XmlDeserializeFromFile&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ConnectionInfo&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt;&amp;gt;&lt;/span&gt;(s_savePath, DefaultEncoding);&lt;br/&gt;            }&lt;br/&gt;            &lt;span style="color:blue"&gt;catch &lt;/span&gt;{&lt;br/&gt;                s_list &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ConnectionInfo&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt;&lt;/span&gt;();&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;private static void &lt;/span&gt;SaveListToFile()&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( s_list &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;&lt;span style="color:red"&gt;|| &lt;/span&gt;s_list&lt;span style="color:red"&gt;.&lt;/span&gt;Count &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;) {&lt;br/&gt;            &lt;span style="color:blue"&gt;try &lt;/span&gt;{&lt;br/&gt;                &lt;span style="color:#2b91af"&gt;File&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Delete(s_savePath);&lt;br/&gt;            }&lt;br/&gt;            &lt;span style="color:blue"&gt;catch &lt;/span&gt;{ }&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color:blue"&gt;else &lt;/span&gt;{&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;XmlHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;XmlSerializeToFile(s_list, s_savePath, DefaultEncoding);&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;服务端的Action实现代码：&lt;a href="javascript:void(0);" codeId="pre-Connection-action"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public object &lt;/span&gt;GetAllConnectionInfo()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ConnectionInfo&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;list &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ConnectionManager&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetList();&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;ConnectionInfoDataGridJsonResult &lt;/span&gt;result &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ConnectionInfoDataGridJsonResult&lt;/span&gt;();&lt;br/&gt;    result&lt;span style="color:red"&gt;.&lt;/span&gt;total &lt;span style="color:red"&gt;= &lt;/span&gt;list&lt;span style="color:red"&gt;.&lt;/span&gt;Count;&lt;br/&gt;    result&lt;span style="color:red"&gt;.&lt;/span&gt;rows &lt;span style="color:red"&gt;= &lt;/span&gt;list;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;JsonResult&lt;/span&gt;(result);&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public string &lt;/span&gt;SubmitConnectionInfo(&lt;span style="color:#2b91af"&gt;ConnectionInfo &lt;/span&gt;info)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(info&lt;span style="color:red"&gt;.&lt;/span&gt;ServerIP) )&lt;br/&gt;        &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyMessageException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"ServerIP is empty."&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( info&lt;span style="color:red"&gt;.&lt;/span&gt;SSPI &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;&lt;span style="color:red"&gt;&amp;amp;&amp;amp; &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(info&lt;span style="color:red"&gt;.&lt;/span&gt;UserName) )&lt;br/&gt;        &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyMessageException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"UserName is empty."&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;bool &lt;/span&gt;isAdd &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(info&lt;span style="color:red"&gt;.&lt;/span&gt;ConnectionId);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( isAdd ) {&lt;br/&gt;        info&lt;span style="color:red"&gt;.&lt;/span&gt;ConnectionId &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Guid&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;NewGuid()&lt;span style="color:red"&gt;.&lt;/span&gt;ToString();&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;ConnectionManager&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;AddConnection(info);&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;info&lt;span style="color:red"&gt;.&lt;/span&gt;ConnectionId;&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;else &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;ConnectionManager&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;UpdateConnection(info);&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:#a31515"&gt;"update OK"&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public void &lt;/span&gt;DeleteConnection(&lt;span style="color:blue"&gt;string &lt;/span&gt;connectionId)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(connectionId) )&lt;br/&gt;        &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyMessageException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"connectionId is empty."&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;ConnectionManager&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;RemoveConnection(connectionId);&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public string &lt;/span&gt;TestConnection(&lt;span style="color:#2b91af"&gt;ConnectionInfo &lt;/span&gt;info)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;BaseBLL &lt;/span&gt;instance &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BaseBLL&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetInstance(&lt;span style="color:blue"&gt;null&lt;/span&gt;);&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;instance&lt;span style="color:red"&gt;.&lt;/span&gt;TestConnection(info);&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&lt;strong&gt;Database 浏览器&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在主界面的【数据库连接列表】中，选择一个连接，然后点击工具栏上的【打开连接】按键，即可进入【Database 浏览器】界面。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012030421130727.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;在这个工具中，如果需要查看某个数据库对象的定义，只需要点击相应的对象节点就可以了：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012030421132543.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;为了操作方便，工具提供多标签查看功能：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012030421134615.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;获取数据库对象列表的关键代码：&lt;a href="javascript:void(0);" codeId="pre-s_QueryDatabaseListScript"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;private static readonly string &lt;/span&gt;s_QueryDatabaseListScript &lt;span style="color:red"&gt;=&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#a31515"&gt;"SELECT dtb.name AS [Database_Name] FROM master.sys.databases AS dtb " &lt;/span&gt;&lt;span style="color:red"&gt;+&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#a31515"&gt;"WHERE (CAST(case when dtb.name in ('master','model','msdb','tempdb') then 1 else dtb.is_distributor end AS bit)=0 " &lt;/span&gt;&lt;span style="color:red"&gt;+&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#a31515"&gt;"    and CAST(isnull(dtb.source_database_id, 0) AS bit)=0) " &lt;/span&gt;&lt;span style="color:red"&gt;+&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#a31515"&gt;"ORDER BY [Database_Name] ASC"&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;protected override &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;GetDatabaseNames(&lt;span style="color:#2b91af"&gt;DbConnection &lt;/span&gt;connection)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;ExecuteQueryToStringList(connection, s_QueryDatabaseListScript);&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;private static readonly string &lt;/span&gt;s_GetObjectNamesFormat &lt;span style="color:red"&gt;=&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#a31515"&gt;"select name from ( SELECT obj.name AS [Name],  " &lt;/span&gt;&lt;span style="color:red"&gt;+&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#a31515"&gt;"CAST( case when obj.is_ms_shipped = 1 then 1 " &lt;/span&gt;&lt;span style="color:red"&gt;+&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#a31515"&gt;"    when ( select major_id from sys.extended_properties  " &lt;/span&gt;&lt;span style="color:red"&gt;+&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#a31515"&gt;"        where major_id = obj.object_id and  minor_id = 0 and class = 1 and name = N'microsoft_database_tools_support')  " &lt;/span&gt;&lt;span style="color:red"&gt;+&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#a31515"&gt;"        is not null then 1  else 0 " &lt;/span&gt;&lt;span style="color:red"&gt;+&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#a31515"&gt;"end  AS bit) AS [IsSystemObject] " &lt;/span&gt;&lt;span style="color:red"&gt;+&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#a31515"&gt;"FROM sys.all_objects AS obj where obj.type in ({0}) )as tables where [IsSystemObject] = 0 ORDER BY [Name] ASC "&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;private static readonly string &lt;/span&gt;s_ProcedureType &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;" N'P', N'PC' "&lt;/span&gt;;&lt;br/&gt;&lt;span style="color:blue"&gt;private static readonly string &lt;/span&gt;s_FunctionType &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;" N'FN', N'IF', N'TF', N'FS', N'FT' "&lt;/span&gt;;&lt;br/&gt;&lt;span style="color:blue"&gt;private static readonly string &lt;/span&gt;s_TableType &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;" N'U' "&lt;/span&gt;;&lt;br/&gt;&lt;span style="color:blue"&gt;private static readonly string &lt;/span&gt;s_ViewType &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;" N'V' "&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;protected override &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;GetDbProcedureNames(&lt;span style="color:#2b91af"&gt;DbConnection &lt;/span&gt;connection)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;//string sql = "select name from sys.objects where type='P' order by name";&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;string &lt;/span&gt;sql &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Format(s_GetObjectNamesFormat, s_ProcedureType);&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;ExecuteQueryToStringList(connection, sql);&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;protected override &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;GetDbFunctionNames(&lt;span style="color:#2b91af"&gt;DbConnection &lt;/span&gt;connection)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;//string sql = "select name from sys.objects where type='FN' order by name";&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;string &lt;/span&gt;sql &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Format(s_GetObjectNamesFormat, s_FunctionType);&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;ExecuteQueryToStringList(connection, sql);&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;protected override &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;GetDbTableNames(&lt;span style="color:#2b91af"&gt;DbConnection &lt;/span&gt;connection)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;//string sql = "select name from sys.objects where type='U' where name != 'sysdiagrams' order by name";&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;string &lt;/span&gt;sql &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Format(s_GetObjectNamesFormat, s_TableType);&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;ExecuteQueryToStringList(connection, sql);&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;protected override &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;GetDbViewNames(&lt;span style="color:#2b91af"&gt;DbConnection &lt;/span&gt;connection)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;//string sql = "select name from sys.objects where type='V' order by name";&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;string &lt;/span&gt;sql &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Format(s_GetObjectNamesFormat, s_ViewType);&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;ExecuteQueryToStringList(connection, sql);&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;p&gt;查看数据库对象的定义脚本的实现代码：&lt;a href="javascript:void(0);" codeId="pre-GetProcedureItem"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;protected override &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ItemCode &lt;/span&gt;GetProcedureItem(&lt;span style="color:#2b91af"&gt;DbConnection &lt;/span&gt;connection, &lt;span style="color:blue"&gt;string &lt;/span&gt;name)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;string &lt;/span&gt;query &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Format(&lt;span style="color:#a31515"&gt;"SELECT definition FROM sys.sql_modules JOIN sys.objects ON sys.sql_modules.object_id = sys.objects.object_id AND type in ({1}) and name = '{0}'"&lt;/span&gt;, name, s_ProcedureType);&lt;br/&gt;    &lt;span style="color:blue"&gt;string &lt;/span&gt;script &lt;span style="color:red"&gt;= &lt;/span&gt;TryExecuteQuery(connection, query);&lt;br/&gt;    &lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ItemCode&lt;/span&gt;(name, &lt;span style="color:#2b91af"&gt;ItemType&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Procedure, script);&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;protected override &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ItemCode &lt;/span&gt;GetFunctionItem(&lt;span style="color:#2b91af"&gt;DbConnection &lt;/span&gt;connection, &lt;span style="color:blue"&gt;string &lt;/span&gt;name)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;string &lt;/span&gt;query &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Format(&lt;span style="color:#a31515"&gt;"SELECT definition FROM sys.sql_modules JOIN sys.objects ON sys.sql_modules.object_id = sys.objects.object_id AND type in ({1}) and name = '{0}'"&lt;/span&gt;, name, s_FunctionType);&lt;br/&gt;    &lt;span style="color:blue"&gt;string &lt;/span&gt;script &lt;span style="color:red"&gt;= &lt;/span&gt;TryExecuteQuery(connection, query);&lt;br/&gt;    &lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ItemCode&lt;/span&gt;(name, &lt;span style="color:#2b91af"&gt;ItemType&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Function, script);&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;protected override &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ItemCode &lt;/span&gt;GetViewItem(&lt;span style="color:#2b91af"&gt;DbConnection &lt;/span&gt;connection, &lt;span style="color:blue"&gt;string &lt;/span&gt;name)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;string &lt;/span&gt;query &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Format(&lt;span style="color:#a31515"&gt;"SELECT definition FROM sys.sql_modules JOIN sys.objects ON sys.sql_modules.object_id = sys.objects.object_id AND type in ({1}) and name = '{0}'"&lt;/span&gt;, name, s_ViewType);&lt;br/&gt;    &lt;span style="color:blue"&gt;string &lt;/span&gt;script &lt;span style="color:red"&gt;= &lt;/span&gt;TryExecuteQuery(connection, query);&lt;br/&gt;    &lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ItemCode&lt;/span&gt;(name, &lt;span style="color:#2b91af"&gt;ItemType&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;View, script);&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;protected override &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ItemCode &lt;/span&gt;GetTableItem(&lt;span style="color:#2b91af"&gt;DbConnection &lt;/span&gt;connection, &lt;span style="color:blue"&gt;string &lt;/span&gt;name)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;string &lt;/span&gt;script &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;    &lt;span style="color:blue"&gt;try &lt;/span&gt;{&lt;br/&gt;        script &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;SmoHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;ScriptTable(connection, &lt;span style="color:blue"&gt;null&lt;/span&gt;, name);&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(script) )&lt;br/&gt;            script &lt;span style="color:red"&gt;= &lt;/span&gt;s_CannotGetScript;&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;catch&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;Exception &lt;/span&gt;ex ) {&lt;br/&gt;        script &lt;span style="color:red"&gt;= &lt;/span&gt;ex&lt;span style="color:red"&gt;.&lt;/span&gt;Message;&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ItemCode&lt;/span&gt;(name, &lt;span style="color:#2b91af"&gt;ItemType&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Table, script);&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&lt;strong&gt;搜索数据库&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;您可以在上图所示界面的左边树控件中，选择一个节点，右击，然后选择“在数据库中搜索”，此时会出现如下对话框：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012030421140712.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;在上图的对话框中，点击确定按键后，可出现下面的查找结果：&lt;br /&gt;&lt;b&gt;说明：匹配行就会高亮显示。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012030421142450.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;搜索数据库对象的相关代码：&lt;a href="javascript:void(0);" codeId="pre-SearchDB"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public object &lt;/span&gt;SearchDB(&lt;span style="color:blue"&gt;string &lt;/span&gt;connectionId, &lt;span style="color:blue"&gt;string &lt;/span&gt;dbName, &lt;span style="color:blue"&gt;string &lt;/span&gt;searchWord,&lt;br/&gt;        &lt;span style="color:blue"&gt;int &lt;/span&gt;wholeMatch, &lt;span style="color:blue"&gt;int &lt;/span&gt;caseSensitive, &lt;span style="color:blue"&gt;string &lt;/span&gt;searchScope, &lt;span style="color:blue"&gt;string &lt;/span&gt;limitCount)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(searchWord) )&lt;br/&gt;        &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"searchWord"&lt;/span&gt;);&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color:#2b91af"&gt;BaseBLL &lt;/span&gt;instance &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BaseBLL&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetInstance(connectionId);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;DbOjbectType &lt;/span&gt;types &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompareDBHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetDbOjbectTypeByFlag(searchScope);&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ItemCode&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;list &lt;span style="color:red"&gt;= &lt;/span&gt;instance&lt;span style="color:red"&gt;.&lt;/span&gt;GetDbAllObjectScript(instance&lt;span style="color:red"&gt;.&lt;/span&gt;ConnectionInfo, dbName, types);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;SearchResultItem&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;result &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;SearchResultItem&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt;&lt;/span&gt;(list&lt;span style="color:red"&gt;.&lt;/span&gt;Count);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;int &lt;/span&gt;limitResultCount &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;;&lt;br/&gt;    &lt;span style="color:blue"&gt;int&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;TryParse(limitCount, &lt;span style="color:blue"&gt;out &lt;/span&gt;limitResultCount);&lt;br/&gt;&lt;br/&gt;    FishWebLib&lt;span style="color:red"&gt;.&lt;/span&gt;&lt;span style="color:#2b91af"&gt;StringSearcher &lt;/span&gt;searcher &lt;span style="color:red"&gt;= &lt;br/&gt;        &lt;/span&gt;FishWebLib&lt;span style="color:red"&gt;.&lt;/span&gt;&lt;span style="color:#2b91af"&gt;StringSearcher&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetStringSearcher(searchWord, (wholeMatch &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:purple"&gt;1&lt;/span&gt;), (caseSensitive &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:purple"&gt;1&lt;/span&gt;));&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;ItemCode &lt;/span&gt;code &lt;span style="color:blue"&gt;in &lt;/span&gt;list ) {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( limitResultCount &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;&lt;span style="color:red"&gt;&amp;amp;&amp;amp; &lt;/span&gt;result&lt;span style="color:red"&gt;.&lt;/span&gt;Count &lt;span style="color:red"&gt;&amp;gt;= &lt;/span&gt;limitResultCount )&lt;br/&gt;            &lt;span style="color:blue"&gt;break&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( code&lt;span style="color:red"&gt;.&lt;/span&gt;SqlScript&lt;span style="color:red"&gt;.&lt;/span&gt;IndexOf(searchWord, &lt;span style="color:#2b91af"&gt;StringComparison&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;OrdinalIgnoreCase) &lt;span style="color:red"&gt;&amp;gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;) {&lt;br/&gt;            &lt;span style="color:blue"&gt;string&lt;/span&gt;[] lines &lt;span style="color:red"&gt;= &lt;/span&gt;instance&lt;span style="color:red"&gt;.&lt;/span&gt;SplitCodeToLineArray(code&lt;span style="color:red"&gt;.&lt;/span&gt;SqlScript);&lt;br/&gt;            &lt;span style="color:blue"&gt;for&lt;/span&gt;( &lt;span style="color:blue"&gt;int &lt;/span&gt;i &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;; i &lt;span style="color:red"&gt;&amp;lt; &lt;/span&gt;lines&lt;span style="color:red"&gt;.&lt;/span&gt;Length; i&lt;span style="color:red"&gt;++ &lt;/span&gt;)&lt;br/&gt;                &lt;span style="color:blue"&gt;if&lt;/span&gt;( searcher&lt;span style="color:red"&gt;.&lt;/span&gt;IsMatch(lines[i]) ) {&lt;br/&gt;                    &lt;span style="color:#2b91af"&gt;SearchResultItem &lt;/span&gt;item &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;SearchResultItem&lt;/span&gt;();&lt;br/&gt;                    item&lt;span style="color:red"&gt;.&lt;/span&gt;LineNumber &lt;span style="color:red"&gt;= &lt;/span&gt;i &lt;span style="color:red"&gt;+ &lt;/span&gt;&lt;span style="color:purple"&gt;1&lt;/span&gt;;&lt;br/&gt;                    item&lt;span style="color:red"&gt;.&lt;/span&gt;ObjectName &lt;span style="color:red"&gt;= &lt;/span&gt;code&lt;span style="color:red"&gt;.&lt;/span&gt;Name;&lt;br/&gt;                    item&lt;span style="color:red"&gt;.&lt;/span&gt;ObjectType &lt;span style="color:red"&gt;= &lt;/span&gt;code&lt;span style="color:red"&gt;.&lt;/span&gt;Type&lt;span style="color:red"&gt;.&lt;/span&gt;ToString();&lt;br/&gt;                    item&lt;span style="color:red"&gt;.&lt;/span&gt;SqlScript &lt;span style="color:red"&gt;= &lt;/span&gt;code&lt;span style="color:red"&gt;.&lt;/span&gt;SqlScript;&lt;br/&gt;                    result&lt;span style="color:red"&gt;.&lt;/span&gt;Add(item);&lt;br/&gt;                    &lt;span style="color:blue"&gt;break&lt;/span&gt;;&lt;br/&gt;                }&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;JsonResult&lt;/span&gt;(result);&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ItemCode&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;GetDbAllObjectScript(&lt;span style="color:#2b91af"&gt;ConnectionInfo &lt;/span&gt;info, &lt;span style="color:blue"&gt;string &lt;/span&gt;dbName, &lt;span style="color:#2b91af"&gt;DbOjbectType &lt;/span&gt;type)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ItemCode&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;list &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ItemCode&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt;&lt;/span&gt;();&lt;br/&gt;    &lt;span style="color:blue"&gt;string &lt;/span&gt;connectionString &lt;span style="color:red"&gt;= &lt;/span&gt;GetDbConnectionString(info, dbName);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;using&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;DbConnection &lt;/span&gt;connection &lt;span style="color:red"&gt;= &lt;/span&gt;CreateConnection(connectionString) ) {&lt;br/&gt;        connection&lt;span style="color:red"&gt;.&lt;/span&gt;Open();&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( (type &lt;span style="color:red"&gt;&amp;amp; &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DbOjbectType&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Table) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DbOjbectType&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Table ) {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;nameList &lt;span style="color:red"&gt;= &lt;/span&gt;GetDbTableNames(connection);&lt;br/&gt;            &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:blue"&gt;string &lt;/span&gt;name &lt;span style="color:blue"&gt;in &lt;/span&gt;nameList )&lt;br/&gt;                list&lt;span style="color:red"&gt;.&lt;/span&gt;Add(GetTableItem(connection, name));&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( (type &lt;span style="color:red"&gt;&amp;amp; &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DbOjbectType&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Procedure) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DbOjbectType&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Procedure ) {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;nameList &lt;span style="color:red"&gt;= &lt;/span&gt;GetDbProcedureNames(connection);&lt;br/&gt;            &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:blue"&gt;string &lt;/span&gt;name &lt;span style="color:blue"&gt;in &lt;/span&gt;nameList )&lt;br/&gt;                list&lt;span style="color:red"&gt;.&lt;/span&gt;Add(GetProcedureItem(connection, name));&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( (type &lt;span style="color:red"&gt;&amp;amp; &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DbOjbectType&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Function) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DbOjbectType&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Function ) {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;nameList &lt;span style="color:red"&gt;= &lt;/span&gt;GetDbFunctionNames(connection);&lt;br/&gt;            &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:blue"&gt;string &lt;/span&gt;name &lt;span style="color:blue"&gt;in &lt;/span&gt;nameList )&lt;br/&gt;                list&lt;span style="color:red"&gt;.&lt;/span&gt;Add(GetFunctionItem(connection, name));&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( (type &lt;span style="color:red"&gt;&amp;amp; &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DbOjbectType&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;View) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DbOjbectType&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;View ) {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;nameList &lt;span style="color:red"&gt;= &lt;/span&gt;GetDbViewNames(connection);&lt;br/&gt;            &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:blue"&gt;string &lt;/span&gt;name &lt;span style="color:blue"&gt;in &lt;/span&gt;nameList )&lt;br/&gt;                list&lt;span style="color:red"&gt;.&lt;/span&gt;Add(GetViewItem(connection, name));&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;list;&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&lt;strong&gt;复制存储过程工具&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;为了演示这个功能，先需要创建一个数据库。我创建了一个数据库：TestMyTool，它没有任何数据库对象，如下图&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012030421144162.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;然后，从主界面中启动【复制存储过程工具】，&lt;br /&gt;接着选择：&lt;b&gt;数据库连接，数据库对象&lt;/b&gt;，&lt;br /&gt;点击【刷新列表】按键，将看到以下结果：&lt;/p&gt;&lt;p&gt;我们可以选择要复制的（存储过程，视图，自定义函数）对象：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012030421150319.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;最后点击【开始复制】按键，即可完成复制过程。&lt;br /&gt;此时数据库TestMyTool的显示结果为：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012030421152030.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;此功能的核心部分实现代码：&lt;a href="javascript:void(0);" codeId="pre-CopyProcedures"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public string &lt;/span&gt;CopyProcedures(&lt;span style="color:blue"&gt;string &lt;/span&gt;srcConnId, &lt;span style="color:blue"&gt;string &lt;/span&gt;destConnId, &lt;span style="color:blue"&gt;string &lt;/span&gt;srcDB, &lt;span style="color:blue"&gt;string &lt;/span&gt;destDB, &lt;br/&gt;        &lt;span style="color:blue"&gt;string &lt;/span&gt;spNames, &lt;span style="color:blue"&gt;string &lt;/span&gt;viewNames, &lt;span style="color:blue"&gt;string &lt;/span&gt;funcNames)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;BaseBLL &lt;/span&gt;instance1 &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BaseBLL&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetInstance(srcConnId);&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;BaseBLL &lt;/span&gt;instance2 &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BaseBLL&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetInstance(destConnId);&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( instance1&lt;span style="color:red"&gt;.&lt;/span&gt;GetType() &lt;span style="color:red"&gt;!= &lt;/span&gt;instance2&lt;span style="color:red"&gt;.&lt;/span&gt;GetType() )&lt;br/&gt;        &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Exception&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"数据库的种类不一致，不能执行复制操作。"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( srcConnId &lt;span style="color:red"&gt;== &lt;/span&gt;destConnId &lt;span style="color:red"&gt;&amp;amp;&amp;amp; &lt;/span&gt;srcDB &lt;span style="color:red"&gt;== &lt;/span&gt;destDB )&lt;br/&gt;        &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Exception&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"无效的操作。"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ItemCode&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;procedures &lt;span style="color:red"&gt;= &lt;/span&gt;instance1&lt;span style="color:red"&gt;.&lt;/span&gt;GetDbAllObjectScript(instance1&lt;span style="color:red"&gt;.&lt;/span&gt;ConnectionInfo, srcDB,    spNames, viewNames, funcNames);&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;instance2&lt;span style="color:red"&gt;.&lt;/span&gt;UpdateProcedures(instance2&lt;span style="color:red"&gt;.&lt;/span&gt;ConnectionInfo, destDB, procedures);&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ItemCode&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;GetDbAllObjectScript(&lt;span style="color:#2b91af"&gt;ConnectionInfo &lt;/span&gt;info, &lt;br/&gt;                        &lt;span style="color:blue"&gt;string &lt;/span&gt;dbName, &lt;span style="color:blue"&gt;string &lt;/span&gt;spNames, &lt;span style="color:blue"&gt;string &lt;/span&gt;viewNames, &lt;span style="color:blue"&gt;string &lt;/span&gt;funcNames)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ItemCode&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;list &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ItemCode&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt;&lt;/span&gt;();&lt;br/&gt;    &lt;span style="color:blue"&gt;string &lt;/span&gt;connectionString &lt;span style="color:red"&gt;= &lt;/span&gt;GetDbConnectionString(info, dbName);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;using&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;DbConnection &lt;/span&gt;connection &lt;span style="color:red"&gt;= &lt;/span&gt;CreateConnection(connectionString) ) {&lt;br/&gt;        connection&lt;span style="color:red"&gt;.&lt;/span&gt;Open();&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(spNames) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;) {&lt;br/&gt;            &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:blue"&gt;string &lt;/span&gt;name &lt;span style="color:blue"&gt;in &lt;/span&gt;spNames&lt;span style="color:red"&gt;.&lt;/span&gt;Split(&lt;span style="color:blue"&gt;new char&lt;/span&gt;[] { &lt;span style="color:#a31515"&gt;';' &lt;/span&gt;}, &lt;span style="color:#2b91af"&gt;StringSplitOptions&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;RemoveEmptyEntries) )&lt;br/&gt;                list&lt;span style="color:red"&gt;.&lt;/span&gt;Add(GetProcedureItem(connection, name));&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(funcNames) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;) {&lt;br/&gt;            &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:blue"&gt;string &lt;/span&gt;name &lt;span style="color:blue"&gt;in &lt;/span&gt;funcNames&lt;span style="color:red"&gt;.&lt;/span&gt;Split(&lt;span style="color:blue"&gt;new char&lt;/span&gt;[] { &lt;span style="color:#a31515"&gt;';' &lt;/span&gt;}, &lt;span style="color:#2b91af"&gt;StringSplitOptions&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;RemoveEmptyEntries) )&lt;br/&gt;                list&lt;span style="color:red"&gt;.&lt;/span&gt;Add(GetFunctionItem(connection, name));&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(viewNames) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;) {&lt;br/&gt;            &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:blue"&gt;string &lt;/span&gt;name &lt;span style="color:blue"&gt;in &lt;/span&gt;viewNames&lt;span style="color:red"&gt;.&lt;/span&gt;Split(&lt;span style="color:blue"&gt;new char&lt;/span&gt;[] { &lt;span style="color:#a31515"&gt;';' &lt;/span&gt;}, &lt;span style="color:#2b91af"&gt;StringSplitOptions&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;RemoveEmptyEntries) )&lt;br/&gt;                list&lt;span style="color:red"&gt;.&lt;/span&gt;Add(GetViewItem(connection, name));&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;list;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public override string &lt;/span&gt;UpdateProcedures(&lt;span style="color:#2b91af"&gt;ConnectionInfo &lt;/span&gt;info, &lt;span style="color:blue"&gt;string &lt;/span&gt;dbName, &lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ItemCode&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;list)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;string &lt;/span&gt;connectionString &lt;span style="color:red"&gt;= &lt;/span&gt;GetDbConnectionString(info, dbName);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;using&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;DbConnection &lt;/span&gt;connection &lt;span style="color:red"&gt;= &lt;/span&gt;CreateConnection(connectionString) ) {&lt;br/&gt;        connection&lt;span style="color:red"&gt;.&lt;/span&gt;Open();&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;DbCommand &lt;/span&gt;command &lt;span style="color:red"&gt;= &lt;/span&gt;connection&lt;span style="color:red"&gt;.&lt;/span&gt;CreateCommand();&lt;br/&gt;        &lt;br/&gt;        &lt;span style="color:blue"&gt;foreach&lt;/span&gt;(&lt;span style="color:#2b91af"&gt;ItemCode &lt;/span&gt;item &lt;span style="color:blue"&gt;in &lt;/span&gt;list) {&lt;br/&gt;            command&lt;span style="color:red"&gt;.&lt;/span&gt;CommandText &lt;span style="color:red"&gt;= &lt;/span&gt;GetDeleteObjectScript(item&lt;span style="color:red"&gt;.&lt;/span&gt;Name, item&lt;span style="color:red"&gt;.&lt;/span&gt;Type);&lt;br/&gt;            command&lt;span style="color:red"&gt;.&lt;/span&gt;ExecuteNonQuery();&lt;br/&gt;&lt;br/&gt;            command&lt;span style="color:red"&gt;.&lt;/span&gt;CommandText &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Format(s_CreateObjectFormat, item&lt;span style="color:red"&gt;.&lt;/span&gt;SqlScript&lt;span style="color:red"&gt;.&lt;/span&gt;Replace(&lt;span style="color:#a31515"&gt;"'"&lt;/span&gt;, &lt;span style="color:#a31515"&gt;"''"&lt;/span&gt;));&lt;br/&gt;            command&lt;span style="color:red"&gt;.&lt;/span&gt;ExecuteNonQuery();&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;return string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Format(&lt;span style="color:#a31515"&gt;"操作成功，共复制了 {0} 个对象。"&lt;/span&gt;, list&lt;span style="color:red"&gt;.&lt;/span&gt;Count);&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&lt;strong&gt;数据库比较工具&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;为了方便后面的介绍，我将复制全部的存储过程到TestMyTool，这个过程将省略贴图。&lt;br /&gt;不仅如此，我还对其中的一个存储过程做了一点修改。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012030421153847.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;然后，在程序主界面中，启动【数据库比较工具】，&lt;br /&gt;接着选择：&lt;b&gt;数据库连接，数据库对象&lt;/b&gt;，&lt;br /&gt;点击【开始比较数据库】按钮后，将能看到以下比较结果。&lt;br /&gt;每个数据库对象的定义中，第一个不匹配的行将以高亮行显示。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012030421155791.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;为了能让您知道不匹配行的出现位置，工具还会显示不匹配行的前后5行代码。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;此功能的核心部分实现代码：&lt;a href="javascript:void(0);" codeId="pre-CompareDBHelper"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal static class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompareDBHelper&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;public sealed class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ThreadParam&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color:blue"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BaseBLL &lt;/span&gt;Instance;&lt;br/&gt;        &lt;span style="color:blue"&gt;public string &lt;/span&gt;DbName;&lt;br/&gt;        &lt;span style="color:blue"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DbOjbectType &lt;/span&gt;DbOjbectType;&lt;br/&gt;        &lt;span style="color:blue"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ItemCode&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;Result;&lt;br/&gt;        &lt;span style="color:blue"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Exception &lt;/span&gt;Exception;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;public &lt;/span&gt;ThreadParam(&lt;span style="color:#2b91af"&gt;BaseBLL &lt;/span&gt;instance, &lt;span style="color:blue"&gt;string &lt;/span&gt;dbName, &lt;span style="color:#2b91af"&gt;DbOjbectType &lt;/span&gt;type)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Instance &lt;span style="color:red"&gt;= &lt;/span&gt;instance;&lt;br/&gt;            &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;DbName &lt;span style="color:red"&gt;= &lt;/span&gt;dbName;&lt;br/&gt;            &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;DbOjbectType &lt;span style="color:red"&gt;= &lt;/span&gt;type;&lt;br/&gt;            &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Result &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ItemCode&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt;&lt;/span&gt;();&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;private static void &lt;/span&gt;ThreadWorkAction(&lt;span style="color:blue"&gt;object &lt;/span&gt;obj)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;ThreadParam &lt;/span&gt;param &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;ThreadParam&lt;/span&gt;)obj;&lt;br/&gt;        &lt;span style="color:blue"&gt;try &lt;/span&gt;{&lt;br/&gt;            param&lt;span style="color:red"&gt;.&lt;/span&gt;Result &lt;span style="color:red"&gt;= &lt;/span&gt;param&lt;span style="color:red"&gt;.&lt;/span&gt;Instance&lt;span style="color:red"&gt;.&lt;/span&gt;GetDbAllObjectScript(param&lt;span style="color:red"&gt;.&lt;/span&gt;Instance&lt;span style="color:red"&gt;.&lt;/span&gt;ConnectionInfo, param&lt;span style="color:red"&gt;.&lt;/span&gt;DbName, param&lt;span style="color:red"&gt;.&lt;/span&gt;DbOjbectType);&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color:blue"&gt;catch&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;Exception &lt;/span&gt;ex ) {&lt;br/&gt;            param&lt;span style="color:red"&gt;.&lt;/span&gt;Exception &lt;span style="color:red"&gt;= &lt;/span&gt;ex;&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DbOjbectType &lt;/span&gt;GetDbOjbectTypeByFlag(&lt;span style="color:blue"&gt;string &lt;/span&gt;flag)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(flag) )&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DbOjbectType&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;None;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;DbOjbectType &lt;/span&gt;types &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DbOjbectType&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;None;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( flag&lt;span style="color:red"&gt;.&lt;/span&gt;IndexOf(&lt;span style="color:#a31515"&gt;'T'&lt;/span&gt;) &lt;span style="color:red"&gt;&amp;gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;)&lt;br/&gt;            types &lt;span style="color:red"&gt;|= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DbOjbectType&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Table;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( flag&lt;span style="color:red"&gt;.&lt;/span&gt;IndexOf(&lt;span style="color:#a31515"&gt;'V'&lt;/span&gt;) &lt;span style="color:red"&gt;&amp;gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;)&lt;br/&gt;            types &lt;span style="color:red"&gt;|= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DbOjbectType&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;View;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( flag&lt;span style="color:red"&gt;.&lt;/span&gt;IndexOf(&lt;span style="color:#a31515"&gt;'P'&lt;/span&gt;) &lt;span style="color:red"&gt;&amp;gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;)&lt;br/&gt;            types &lt;span style="color:red"&gt;|= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DbOjbectType&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Procedure;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( flag&lt;span style="color:red"&gt;.&lt;/span&gt;IndexOf(&lt;span style="color:#a31515"&gt;'F'&lt;/span&gt;) &lt;span style="color:red"&gt;&amp;gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;)&lt;br/&gt;            types &lt;span style="color:red"&gt;|= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DbOjbectType&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Function;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;types;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompareResultItem&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;CompareDB(&lt;span style="color:blue"&gt;string &lt;/span&gt;srcConnId, &lt;span style="color:blue"&gt;string &lt;/span&gt;destConnId, &lt;span style="color:blue"&gt;string &lt;/span&gt;srcDB, &lt;span style="color:blue"&gt;string &lt;/span&gt;destDB, &lt;span style="color:blue"&gt;string &lt;/span&gt;flag)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;BaseBLL &lt;/span&gt;instance1 &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BaseBLL&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetInstance(srcConnId);&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;BaseBLL &lt;/span&gt;instance2 &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BaseBLL&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetInstance(destConnId);&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( instance1&lt;span style="color:red"&gt;.&lt;/span&gt;GetType() &lt;span style="color:red"&gt;!= &lt;/span&gt;instance2&lt;span style="color:red"&gt;.&lt;/span&gt;GetType() )&lt;br/&gt;            &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Exception&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"数据库的种类不一致，比较没有意义。"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;DbOjbectType &lt;/span&gt;types &lt;span style="color:red"&gt;= &lt;/span&gt;GetDbOjbectTypeByFlag(flag);&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;ThreadParam &lt;/span&gt;param1 &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ThreadParam&lt;/span&gt;(instance1, srcDB, types);&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;ThreadParam &lt;/span&gt;param2 &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ThreadParam&lt;/span&gt;(instance2, destDB, types);&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;Thread &lt;/span&gt;thread1 &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Thread&lt;/span&gt;(ThreadWorkAction);&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;Thread &lt;/span&gt;thread2 &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Thread&lt;/span&gt;(ThreadWorkAction);&lt;br/&gt;        thread1&lt;span style="color:red"&gt;.&lt;/span&gt;Start(param1);&lt;br/&gt;        thread2&lt;span style="color:red"&gt;.&lt;/span&gt;Start(param2);&lt;br/&gt;        thread1&lt;span style="color:red"&gt;.&lt;/span&gt;Join();&lt;br/&gt;        thread2&lt;span style="color:red"&gt;.&lt;/span&gt;Join();&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( param1&lt;span style="color:red"&gt;.&lt;/span&gt;Exception &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;throw &lt;/span&gt;param1&lt;span style="color:red"&gt;.&lt;/span&gt;Exception;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( param2&lt;span style="color:red"&gt;.&lt;/span&gt;Exception &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;throw &lt;/span&gt;param2&lt;span style="color:red"&gt;.&lt;/span&gt;Exception;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ItemCode&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;list1 &lt;span style="color:red"&gt;= &lt;/span&gt;param1&lt;span style="color:red"&gt;.&lt;/span&gt;Result;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ItemCode&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;list2 &lt;span style="color:red"&gt;= &lt;/span&gt;param2&lt;span style="color:red"&gt;.&lt;/span&gt;Result;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompareResultItem&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;result &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompareResultItem&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt;&lt;/span&gt;();&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;ItemCode &lt;/span&gt;dest &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 按数据库对象类别分次比较。&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:blue"&gt;for&lt;/span&gt;( &lt;span style="color:blue"&gt;int &lt;/span&gt;typeIndex &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;; typeIndex &lt;span style="color:red"&gt;&amp;lt; &lt;/span&gt;&lt;span style="color:purple"&gt;4&lt;/span&gt;; typeIndex&lt;span style="color:red"&gt;++ &lt;/span&gt;) {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;ItemType &lt;/span&gt;currentType &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;ItemType&lt;/span&gt;)typeIndex;&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;ItemCode &lt;/span&gt;item1 &lt;span style="color:blue"&gt;in &lt;/span&gt;list1 ) {&lt;br/&gt;                &lt;span style="color:green"&gt;// 如果不是当前要比较的对象类别，则跳过。&lt;br/&gt;                &lt;/span&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( item1&lt;span style="color:red"&gt;.&lt;/span&gt;Type &lt;span style="color:red"&gt;!= &lt;/span&gt;currentType )&lt;br/&gt;                    &lt;span style="color:blue"&gt;continue&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;                dest &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;                &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;ItemCode &lt;/span&gt;item2 &lt;span style="color:blue"&gt;in &lt;/span&gt;list2 ) {&lt;br/&gt;                    &lt;span style="color:blue"&gt;if&lt;/span&gt;( item1&lt;span style="color:red"&gt;.&lt;/span&gt;Type &lt;span style="color:red"&gt;== &lt;/span&gt;item2&lt;span style="color:red"&gt;.&lt;/span&gt;Type &lt;span style="color:red"&gt;&amp;amp;&amp;amp; &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Compare(item1&lt;span style="color:red"&gt;.&lt;/span&gt;Name, item2&lt;span style="color:red"&gt;.&lt;/span&gt;Name, &lt;span style="color:blue"&gt;true&lt;/span&gt;) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;) {&lt;br/&gt;                        dest &lt;span style="color:red"&gt;= &lt;/span&gt;item2;&lt;br/&gt;                        &lt;span style="color:blue"&gt;break&lt;/span&gt;;&lt;br/&gt;                    }&lt;br/&gt;                }&lt;br/&gt;&lt;br/&gt;                &lt;span style="color:blue"&gt;if&lt;/span&gt;( dest &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) {&lt;br/&gt;                    &lt;span style="color:#2b91af"&gt;CompareResultItem &lt;/span&gt;cri &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompareResultItem&lt;/span&gt;();&lt;br/&gt;                    cri&lt;span style="color:red"&gt;.&lt;/span&gt;ObjectType &lt;span style="color:red"&gt;= &lt;/span&gt;item1&lt;span style="color:red"&gt;.&lt;/span&gt;TypeText;&lt;br/&gt;                    cri&lt;span style="color:red"&gt;.&lt;/span&gt;ObjectName &lt;span style="color:red"&gt;= &lt;/span&gt;item1&lt;span style="color:red"&gt;.&lt;/span&gt;Name;&lt;br/&gt;                    cri&lt;span style="color:red"&gt;.&lt;/span&gt;LineNumber &lt;span style="color:red"&gt;= -&lt;/span&gt;&lt;span style="color:purple"&gt;1&lt;/span&gt;;&lt;br/&gt;                    cri&lt;span style="color:red"&gt;.&lt;/span&gt;SrcLine &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Empty;&lt;br/&gt;                    cri&lt;span style="color:red"&gt;.&lt;/span&gt;DestLine &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Empty;&lt;br/&gt;                    cri&lt;span style="color:red"&gt;.&lt;/span&gt;Reason &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"源数据库中存在，而目标数据库中不存在。"&lt;/span&gt;;&lt;br/&gt;                    result&lt;span style="color:red"&gt;.&lt;/span&gt;Add(cri);&lt;br/&gt;                    &lt;span style="color:blue"&gt;continue&lt;/span&gt;;&lt;br/&gt;                }&lt;br/&gt;                &lt;span style="color:blue"&gt;else &lt;/span&gt;{&lt;br/&gt;                    &lt;span style="color:blue"&gt;if&lt;/span&gt;( item1&lt;span style="color:red"&gt;.&lt;/span&gt;SqlScript &lt;span style="color:red"&gt;== &lt;/span&gt;dest&lt;span style="color:red"&gt;.&lt;/span&gt;SqlScript )&lt;br/&gt;                        &lt;span style="color:blue"&gt;continue&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;                    &lt;span style="color:green"&gt;// 开始比较代码了。&lt;br/&gt;                    &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompareResultItem &lt;/span&gt;cri &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;                    &lt;span style="color:blue"&gt;string&lt;/span&gt;[] lines1 &lt;span style="color:red"&gt;= &lt;/span&gt;instance1&lt;span style="color:red"&gt;.&lt;/span&gt;SplitCodeToLineArray(item1&lt;span style="color:red"&gt;.&lt;/span&gt;SqlScript);&lt;br/&gt;                    &lt;span style="color:blue"&gt;string&lt;/span&gt;[] lines2 &lt;span style="color:red"&gt;= &lt;/span&gt;instance1&lt;span style="color:red"&gt;.&lt;/span&gt;SplitCodeToLineArray(dest&lt;span style="color:red"&gt;.&lt;/span&gt;SqlScript);&lt;br/&gt;&lt;br/&gt;                    &lt;span style="color:blue"&gt;for&lt;/span&gt;( &lt;span style="color:blue"&gt;int &lt;/span&gt;i &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;; i &lt;span style="color:red"&gt;&amp;lt; &lt;/span&gt;lines1&lt;span style="color:red"&gt;.&lt;/span&gt;Length; i&lt;span style="color:red"&gt;++ &lt;/span&gt;) {&lt;br/&gt;                        &lt;span style="color:blue"&gt;if&lt;/span&gt;( i &lt;span style="color:red"&gt;&amp;gt;= &lt;/span&gt;lines2&lt;span style="color:red"&gt;.&lt;/span&gt;Length ) {&lt;br/&gt;                            &lt;span style="color:green"&gt;// 目标对象的代码行数比较少&lt;br/&gt;                            &lt;/span&gt;cri &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompareResultItem&lt;/span&gt;();&lt;br/&gt;                            cri&lt;span style="color:red"&gt;.&lt;/span&gt;ObjectType &lt;span style="color:red"&gt;= &lt;/span&gt;item1&lt;span style="color:red"&gt;.&lt;/span&gt;TypeText;&lt;br/&gt;                            cri&lt;span style="color:red"&gt;.&lt;/span&gt;ObjectName &lt;span style="color:red"&gt;= &lt;/span&gt;item1&lt;span style="color:red"&gt;.&lt;/span&gt;Name;&lt;br/&gt;                            cri&lt;span style="color:red"&gt;.&lt;/span&gt;LineNumber &lt;span style="color:red"&gt;= &lt;/span&gt;i &lt;span style="color:red"&gt;+ &lt;/span&gt;&lt;span style="color:purple"&gt;1&lt;/span&gt;;&lt;br/&gt;                            GetNearLines(lines1, lines2, i, cri);&lt;br/&gt;                            cri&lt;span style="color:red"&gt;.&lt;/span&gt;Reason &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"目标对象中已没有对应行数的代码。"&lt;/span&gt;;&lt;br/&gt;                            result&lt;span style="color:red"&gt;.&lt;/span&gt;Add(cri);&lt;br/&gt;                            &lt;span style="color:blue"&gt;break&lt;/span&gt;;&lt;br/&gt;                        }&lt;br/&gt;&lt;br/&gt;                        &lt;span style="color:blue"&gt;string &lt;/span&gt;s1 &lt;span style="color:red"&gt;= &lt;/span&gt;lines1[i]&lt;span style="color:red"&gt;.&lt;/span&gt;Trim();&lt;br/&gt;                        &lt;span style="color:blue"&gt;string &lt;/span&gt;s2 &lt;span style="color:red"&gt;= &lt;/span&gt;lines2[i]&lt;span style="color:red"&gt;.&lt;/span&gt;Trim();&lt;br/&gt;                        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Compare(s1, s2, &lt;span style="color:blue"&gt;true&lt;/span&gt;) &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;) {&lt;br/&gt;                            cri &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompareResultItem&lt;/span&gt;();&lt;br/&gt;                            cri&lt;span style="color:red"&gt;.&lt;/span&gt;ObjectType &lt;span style="color:red"&gt;= &lt;/span&gt;item1&lt;span style="color:red"&gt;.&lt;/span&gt;TypeText;&lt;br/&gt;                            cri&lt;span style="color:red"&gt;.&lt;/span&gt;ObjectName &lt;span style="color:red"&gt;= &lt;/span&gt;item1&lt;span style="color:red"&gt;.&lt;/span&gt;Name;&lt;br/&gt;                            cri&lt;span style="color:red"&gt;.&lt;/span&gt;LineNumber &lt;span style="color:red"&gt;= &lt;/span&gt;i &lt;span style="color:red"&gt;+ &lt;/span&gt;&lt;span style="color:purple"&gt;1&lt;/span&gt;;&lt;br/&gt;                            GetNearLines(lines1, lines2, i, cri);&lt;br/&gt;                            cri&lt;span style="color:red"&gt;.&lt;/span&gt;Reason &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"代码不一致。"&lt;/span&gt;;&lt;br/&gt;                            result&lt;span style="color:red"&gt;.&lt;/span&gt;Add(cri);&lt;br/&gt;                            &lt;span style="color:blue"&gt;break&lt;/span&gt;;&lt;br/&gt;                        }&lt;br/&gt;                    }&lt;br/&gt;&lt;br/&gt;                    &lt;span style="color:blue"&gt;if&lt;/span&gt;( cri &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;                        &lt;span style="color:blue"&gt;continue&lt;/span&gt;;    &lt;span style="color:green"&gt;// 比较下一个对象&lt;br/&gt;&lt;br/&gt;                    &lt;/span&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( lines2&lt;span style="color:red"&gt;.&lt;/span&gt;Length &lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;lines1&lt;span style="color:red"&gt;.&lt;/span&gt;Length ) {&lt;br/&gt;                        &lt;span style="color:green"&gt;// 目标对象的代码行数比较少&lt;br/&gt;                        &lt;/span&gt;cri &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompareResultItem&lt;/span&gt;();&lt;br/&gt;                        cri&lt;span style="color:red"&gt;.&lt;/span&gt;ObjectType &lt;span style="color:red"&gt;= &lt;/span&gt;item1&lt;span style="color:red"&gt;.&lt;/span&gt;TypeText;&lt;br/&gt;                        cri&lt;span style="color:red"&gt;.&lt;/span&gt;ObjectName &lt;span style="color:red"&gt;= &lt;/span&gt;item1&lt;span style="color:red"&gt;.&lt;/span&gt;Name;&lt;br/&gt;                        cri&lt;span style="color:red"&gt;.&lt;/span&gt;LineNumber &lt;span style="color:red"&gt;= &lt;/span&gt;lines1&lt;span style="color:red"&gt;.&lt;/span&gt;Length &lt;span style="color:red"&gt;+ &lt;/span&gt;&lt;span style="color:purple"&gt;1&lt;/span&gt;;&lt;br/&gt;                        GetNearLines(lines1, lines2, lines1&lt;span style="color:red"&gt;.&lt;/span&gt;Length, cri);&lt;br/&gt;                        cri&lt;span style="color:red"&gt;.&lt;/span&gt;Reason &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"源对象中已没有对应行数的代码。"&lt;/span&gt;;&lt;br/&gt;                        result&lt;span style="color:red"&gt;.&lt;/span&gt;Add(cri);&lt;br/&gt;                        &lt;span style="color:blue"&gt;break&lt;/span&gt;;&lt;br/&gt;                    }&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;ItemCode &lt;/span&gt;item2 &lt;span style="color:blue"&gt;in &lt;/span&gt;list2 ) {&lt;br/&gt;                &lt;span style="color:green"&gt;// 如果不是当前要比较的对象类别，则跳过。&lt;br/&gt;                &lt;/span&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( item2&lt;span style="color:red"&gt;.&lt;/span&gt;Type &lt;span style="color:red"&gt;!= &lt;/span&gt;currentType )&lt;br/&gt;                    &lt;span style="color:blue"&gt;continue&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;                dest &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;                &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;ItemCode &lt;/span&gt;item1 &lt;span style="color:blue"&gt;in &lt;/span&gt;list1 ) {&lt;br/&gt;                    &lt;span style="color:blue"&gt;if&lt;/span&gt;( item1&lt;span style="color:red"&gt;.&lt;/span&gt;Type &lt;span style="color:red"&gt;== &lt;/span&gt;item2&lt;span style="color:red"&gt;.&lt;/span&gt;Type &lt;span style="color:red"&gt;&amp;amp;&amp;amp; &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Compare(item1&lt;span style="color:red"&gt;.&lt;/span&gt;Name, item2&lt;span style="color:red"&gt;.&lt;/span&gt;Name, &lt;span style="color:blue"&gt;true&lt;/span&gt;) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;) {&lt;br/&gt;                        dest &lt;span style="color:red"&gt;= &lt;/span&gt;item2;&lt;br/&gt;                        &lt;span style="color:blue"&gt;break&lt;/span&gt;;&lt;br/&gt;                    }&lt;br/&gt;                }&lt;br/&gt;&lt;br/&gt;                &lt;span style="color:blue"&gt;if&lt;/span&gt;( dest &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) {&lt;br/&gt;                    &lt;span style="color:#2b91af"&gt;CompareResultItem &lt;/span&gt;cri &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompareResultItem&lt;/span&gt;();&lt;br/&gt;                    cri&lt;span style="color:red"&gt;.&lt;/span&gt;ObjectType &lt;span style="color:red"&gt;= &lt;/span&gt;item2&lt;span style="color:red"&gt;.&lt;/span&gt;TypeText;&lt;br/&gt;                    cri&lt;span style="color:red"&gt;.&lt;/span&gt;ObjectName &lt;span style="color:red"&gt;= &lt;/span&gt;item2&lt;span style="color:red"&gt;.&lt;/span&gt;Name;&lt;br/&gt;                    cri&lt;span style="color:red"&gt;.&lt;/span&gt;LineNumber &lt;span style="color:red"&gt;= -&lt;/span&gt;&lt;span style="color:purple"&gt;2&lt;/span&gt;;&lt;br/&gt;                    cri&lt;span style="color:red"&gt;.&lt;/span&gt;SrcLine &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Empty;&lt;br/&gt;                    cri&lt;span style="color:red"&gt;.&lt;/span&gt;DestLine &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Empty;&lt;br/&gt;                    cri&lt;span style="color:red"&gt;.&lt;/span&gt;Reason &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"目标数据库中存在，而源数据库中不存在。"&lt;/span&gt;;&lt;br/&gt;                    result&lt;span style="color:red"&gt;.&lt;/span&gt;Add(cri);&lt;br/&gt;                    &lt;span style="color:blue"&gt;continue&lt;/span&gt;;&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;result;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;private static void &lt;/span&gt;GetNearLines(&lt;span style="color:blue"&gt;string&lt;/span&gt;[] lines1, &lt;span style="color:blue"&gt;string&lt;/span&gt;[] lines2, &lt;span style="color:blue"&gt;int &lt;/span&gt;index, &lt;span style="color:#2b91af"&gt;CompareResultItem &lt;/span&gt;cri)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;int &lt;/span&gt;firstLine;&lt;br/&gt;        cri&lt;span style="color:red"&gt;.&lt;/span&gt;SrcLine &lt;span style="color:red"&gt;= &lt;/span&gt;GetOneNearLines(lines1, index, &lt;span style="color:blue"&gt;out &lt;/span&gt;firstLine);&lt;br/&gt;        cri&lt;span style="color:red"&gt;.&lt;/span&gt;SrcFirstLine &lt;span style="color:red"&gt;= &lt;/span&gt;firstLine;&lt;br/&gt;&lt;br/&gt;        cri&lt;span style="color:red"&gt;.&lt;/span&gt;DestLine &lt;span style="color:red"&gt;= &lt;/span&gt;GetOneNearLines(lines2, index, &lt;span style="color:blue"&gt;out &lt;/span&gt;firstLine);&lt;br/&gt;        cri&lt;span style="color:red"&gt;.&lt;/span&gt;DestFirstLine &lt;span style="color:red"&gt;= &lt;/span&gt;firstLine;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;private static string &lt;/span&gt;GetOneNearLines(&lt;span style="color:blue"&gt;string&lt;/span&gt;[] lines, &lt;span style="color:blue"&gt;int &lt;/span&gt;index, &lt;span style="color:blue"&gt;out int &lt;/span&gt;firstLine)&lt;br/&gt;    {&lt;br/&gt;        firstLine &lt;span style="color:red"&gt;= -&lt;/span&gt;&lt;span style="color:purple"&gt;1&lt;/span&gt;;&lt;br/&gt;        System&lt;span style="color:red"&gt;.&lt;/span&gt;Text&lt;span style="color:red"&gt;.&lt;/span&gt;&lt;span style="color:#2b91af"&gt;StringBuilder &lt;/span&gt;sb &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;System&lt;span style="color:red"&gt;.&lt;/span&gt;Text&lt;span style="color:red"&gt;.&lt;/span&gt;&lt;span style="color:#2b91af"&gt;StringBuilder&lt;/span&gt;();&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;int &lt;/span&gt;start &lt;span style="color:red"&gt;= &lt;/span&gt;index &lt;span style="color:red"&gt;- &lt;/span&gt;&lt;span style="color:purple"&gt;5&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color:blue"&gt;for&lt;/span&gt;( &lt;span style="color:blue"&gt;int &lt;/span&gt;i &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;; i &lt;span style="color:red"&gt;&amp;lt; &lt;/span&gt;&lt;span style="color:purple"&gt;11&lt;/span&gt;; i&lt;span style="color:red"&gt;++ &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( start &lt;span style="color:red"&gt;+ &lt;/span&gt;i &lt;span style="color:red"&gt;&amp;gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;&lt;span style="color:red"&gt;&amp;amp;&amp;amp; &lt;/span&gt;start &lt;span style="color:red"&gt;+ &lt;/span&gt;i &lt;span style="color:red"&gt;&amp;lt; &lt;/span&gt;lines&lt;span style="color:red"&gt;.&lt;/span&gt;Length ) {&lt;br/&gt;                &lt;span style="color:blue"&gt;if&lt;/span&gt;( firstLine &lt;span style="color:red"&gt;&amp;lt; &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;)&lt;br/&gt;                    firstLine &lt;span style="color:red"&gt;= &lt;/span&gt;start &lt;span style="color:red"&gt;+ &lt;/span&gt;i &lt;span style="color:red"&gt;+ &lt;/span&gt;&lt;span style="color:purple"&gt;1&lt;/span&gt;;&lt;br/&gt;                sb&lt;span style="color:red"&gt;.&lt;/span&gt;AppendLine(lines[start &lt;span style="color:red"&gt;+ &lt;/span&gt;i]);&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;sb&lt;span style="color:red"&gt;.&lt;/span&gt;ToString();&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&lt;strong&gt;查看表结构定义&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;工具可以让您轻松地查看一个表结构的定义：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012030421161366.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;也可以一次查看多个表的定义：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012030421162792.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;还可一下子得到整个数据库的所有对象的创建脚本：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012030421164227.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;此功能的核心部分实现代码：&lt;a href="javascript:void(0);" codeId="pre-AjaxDataTable"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;AjaxDataTable&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;    &lt;span style="color:blue"&gt;public object &lt;/span&gt;TableDescribe(&lt;span style="color:blue"&gt;string &lt;/span&gt;connectionId, &lt;span style="color:blue"&gt;string &lt;/span&gt;dbName, &lt;span style="color:blue"&gt;string &lt;/span&gt;tableName)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(connectionId) &lt;span style="color:red"&gt;|| &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(dbName) &lt;span style="color:red"&gt;|| &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(tableName) )&lt;br/&gt;            &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"connString or tableName is null."&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;BaseBLL &lt;/span&gt;instance &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BaseBLL&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetInstance(connectionId);&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;DataTable &lt;/span&gt;table &lt;span style="color:red"&gt;= &lt;/span&gt;instance&lt;span style="color:red"&gt;.&lt;/span&gt;GetTableFields(instance&lt;span style="color:red"&gt;.&lt;/span&gt;ConnectionInfo, dbName, tableName);&lt;br/&gt;        &lt;span style="color:blue"&gt;return new &lt;/span&gt;MyMvcEx&lt;span style="color:red"&gt;.&lt;/span&gt;&lt;span style="color:#2b91af"&gt;DataTableResult&lt;/span&gt;(table);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;    &lt;span style="color:blue"&gt;public object &lt;/span&gt;MultiTableDescribe(&lt;span style="color:blue"&gt;string &lt;/span&gt;connectionId, &lt;span style="color:blue"&gt;string &lt;/span&gt;dbName, &lt;span style="color:blue"&gt;string &lt;/span&gt;tableNames)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(connectionId) &lt;span style="color:red"&gt;|| &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(dbName) &lt;span style="color:red"&gt;|| &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(tableNames) )&lt;br/&gt;            &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"connString or tableName is null."&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;BaseBLL &lt;/span&gt;instance &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BaseBLL&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetInstance(connectionId);&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;DataSet &lt;/span&gt;ds &lt;span style="color:red"&gt;= &lt;/span&gt;instance&lt;span style="color:red"&gt;.&lt;/span&gt;GetTables(instance&lt;span style="color:red"&gt;.&lt;/span&gt;ConnectionInfo, dbName, tableNames);&lt;br/&gt;        &lt;span style="color:blue"&gt;return new &lt;/span&gt;MyMvcEx&lt;span style="color:red"&gt;.&lt;/span&gt;&lt;span style="color:#2b91af"&gt;DataSetResult&lt;/span&gt;(ds);&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&lt;strong&gt;修改运行环境&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;到目前为止，这个工具还只能在Visual Studio中运行，显然它与我们经常见到的【工具】有较大的差别。&lt;/p&gt;&lt;p&gt;如果您希望可以方便地运行这个工具，那么可以安装我的另一个小工具来快速地启动当前这个工具，那个工具的下载地址：&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/10/26/2225848.html" target="_blank"&gt;【ASP.NET程序也能像WinForm程序一样运行】&lt;/a&gt;&lt;/p&gt;&lt;p&gt;然后，就可以在Windows资源管理器中启动这个小工具：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012030423114474.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012030423115821.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;现在是不是很像一个桌面程序了？&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012030423121477.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;您甚至也可以创建一个开始菜单项，或者一个快捷方式来启动这个小工具，具体方法可参考博客：&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/10/26/2225848.html" target="_blank"&gt;【ASP.NET程序也能像WinForm程序一样运行】&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;关于此工具的补充说明&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;这个小工具只实现了一些简单的功能，而且主要集中在查看数据库的定义这块。&lt;br /&gt;这个工具的早期版本中，有些人提到了要求实现查看数据表的功能。&lt;br /&gt;在今天的版本中，我并没有实现，但我提供了实现这个功能所必要的一些基础代码。&lt;br /&gt;例如，我提供了二个ActionResult  （&lt;b&gt;注意：前面小节的Action代码中，就使用了下面的二个实现类&lt;/b&gt;）：&lt;a href="javascript:void(0);" codeId="pre-DataTableResult"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DataTableResult &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IActionResult&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DataTable &lt;/span&gt;_table;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;public &lt;/span&gt;DataTableResult(&lt;span style="color:#2b91af"&gt;DataTable &lt;/span&gt;table)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( table &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;                &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"table"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;            _table &lt;span style="color:red"&gt;= &lt;/span&gt;table;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;void &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IActionResult&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Ouput(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context)&lt;br/&gt;        {&lt;br/&gt;            context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;ContentType &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"text/html"&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color:blue"&gt;string &lt;/span&gt;html &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DataTableHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;TableToHtml(_table);&lt;br/&gt;            context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Write(html);&lt;br/&gt;        }                &lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DataSetResult &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IActionResult&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DataSet &lt;/span&gt;_ds;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;public &lt;/span&gt;DataSetResult(&lt;span style="color:#2b91af"&gt;DataSet &lt;/span&gt;ds)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( ds &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;                &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"ds"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;            _ds &lt;span style="color:red"&gt;= &lt;/span&gt;ds;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;void &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IActionResult&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Ouput(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;DataSetJsonItem&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;list &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;DataSetJsonItem&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt;&lt;/span&gt;();&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:blue"&gt;for&lt;/span&gt;( &lt;span style="color:blue"&gt;int &lt;/span&gt;i &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;; i &lt;span style="color:red"&gt;&amp;lt; &lt;/span&gt;_ds&lt;span style="color:red"&gt;.&lt;/span&gt;Tables&lt;span style="color:red"&gt;.&lt;/span&gt;Count; i&lt;span style="color:red"&gt;++ &lt;/span&gt;) {&lt;br/&gt;                &lt;span style="color:#2b91af"&gt;DataTable &lt;/span&gt;table &lt;span style="color:red"&gt;= &lt;/span&gt;_ds&lt;span style="color:red"&gt;.&lt;/span&gt;Tables[i];&lt;br/&gt;                &lt;span style="color:blue"&gt;string &lt;/span&gt;html &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DataTableHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;TableToHtml(table);&lt;br/&gt;                list&lt;span style="color:red"&gt;.&lt;/span&gt;Add(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DataSetJsonItem &lt;/span&gt;{ TableName &lt;span style="color:red"&gt;= &lt;/span&gt;table&lt;span style="color:red"&gt;.&lt;/span&gt;TableName, Html &lt;span style="color:red"&gt;= &lt;/span&gt;html });&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;JsonResult &lt;/span&gt;json &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;JsonResult&lt;/span&gt;(list);&lt;br/&gt;            (json &lt;span style="color:blue"&gt;as &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IActionResult&lt;/span&gt;)&lt;span style="color:red"&gt;.&lt;/span&gt;Ouput(context);&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DataSetJsonItem&lt;br/&gt;        &lt;/span&gt;{&lt;br/&gt;            &lt;span style="color:blue"&gt;public string &lt;/span&gt;TableName;&lt;br/&gt;            &lt;span style="color:blue"&gt;public string &lt;/span&gt;Html;&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public static class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DataTableHelper&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color:blue"&gt;public static string &lt;/span&gt;TableToHtml(&lt;span style="color:#2b91af"&gt;DataTable &lt;/span&gt;table)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( table &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;                &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"table"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;StringBuilder &lt;/span&gt;html &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;StringBuilder&lt;/span&gt;();&lt;br/&gt;            html&lt;span style="color:red"&gt;.&lt;/span&gt;AppendLine(&lt;span style="color:#a31515"&gt;"&amp;lt;table cellpadding=\"2\" cellspacing=\"1\" class=\"myGridVew\"&amp;gt;&amp;lt;thead&amp;gt;&amp;lt;tr&amp;gt;"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:blue"&gt;for&lt;/span&gt;( &lt;span style="color:blue"&gt;int &lt;/span&gt;i &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;; i &lt;span style="color:red"&gt;&amp;lt; &lt;/span&gt;table&lt;span style="color:red"&gt;.&lt;/span&gt;Columns&lt;span style="color:red"&gt;.&lt;/span&gt;Count; i&lt;span style="color:red"&gt;++ &lt;/span&gt;)&lt;br/&gt;                html&lt;span style="color:red"&gt;.&lt;/span&gt;AppendFormat(&lt;span style="color:#a31515"&gt;"&amp;lt;th&amp;gt;{0}&amp;lt;/th&amp;gt;"&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;HttpUtility&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode(table&lt;span style="color:red"&gt;.&lt;/span&gt;Columns[i]&lt;span style="color:red"&gt;.&lt;/span&gt;ColumnName));&lt;br/&gt;&lt;br/&gt;            html&lt;span style="color:red"&gt;.&lt;/span&gt;AppendLine(&lt;span style="color:#a31515"&gt;"&amp;lt;/tr&amp;gt;&amp;lt;/thead&amp;gt;&amp;lt;tbody&amp;gt;"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:blue"&gt;object &lt;/span&gt;cell &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color:blue"&gt;for&lt;/span&gt;( &lt;span style="color:blue"&gt;int &lt;/span&gt;j &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;; j &lt;span style="color:red"&gt;&amp;lt; &lt;/span&gt;table&lt;span style="color:red"&gt;.&lt;/span&gt;Rows&lt;span style="color:red"&gt;.&lt;/span&gt;Count; j&lt;span style="color:red"&gt;++ &lt;/span&gt;) {&lt;br/&gt;                html&lt;span style="color:red"&gt;.&lt;/span&gt;AppendLine(&lt;span style="color:#a31515"&gt;"&amp;lt;tr&amp;gt;"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;                &lt;span style="color:blue"&gt;for&lt;/span&gt;( &lt;span style="color:blue"&gt;int &lt;/span&gt;i &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;; i &lt;span style="color:red"&gt;&amp;lt; &lt;/span&gt;table&lt;span style="color:red"&gt;.&lt;/span&gt;Columns&lt;span style="color:red"&gt;.&lt;/span&gt;Count; i&lt;span style="color:red"&gt;++ &lt;/span&gt;) {&lt;br/&gt;                    cell &lt;span style="color:red"&gt;= &lt;/span&gt;table&lt;span style="color:red"&gt;.&lt;/span&gt;Rows[j][i];&lt;br/&gt;                    &lt;span style="color:blue"&gt;if&lt;/span&gt;( cell &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;&lt;span style="color:red"&gt;|| &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DBNull&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Value&lt;span style="color:red"&gt;.&lt;/span&gt;Equals(cell) )&lt;br/&gt;                        html&lt;span style="color:red"&gt;.&lt;/span&gt;Append(&lt;span style="color:#a31515"&gt;"&amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;"&lt;/span&gt;);&lt;br/&gt;                    &lt;span style="color:blue"&gt;else&lt;br/&gt;                        &lt;/span&gt;html&lt;span style="color:red"&gt;.&lt;/span&gt;AppendFormat(&lt;span style="color:#a31515"&gt;"&amp;lt;td&amp;gt;{0}&amp;lt;/td&amp;gt;"&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;HttpUtility&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode(cell&lt;span style="color:red"&gt;.&lt;/span&gt;ToString()));&lt;br/&gt;                }&lt;br/&gt;                html&lt;span style="color:red"&gt;.&lt;/span&gt;AppendLine(&lt;span style="color:#a31515"&gt;"&amp;lt;/tr&amp;gt;"&lt;/span&gt;);&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            html&lt;span style="color:red"&gt;.&lt;/span&gt;AppendLine(&lt;span style="color:#a31515"&gt;"&amp;lt;/tbody&amp;gt;&amp;lt;/table&amp;gt;"&lt;/span&gt;);&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;html&lt;span style="color:red"&gt;.&lt;/span&gt;ToString();&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;p&gt;为了方便地在客户端将表格显示地漂亮些，我还提供了一个JS函数：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;function &lt;/span&gt;SetGridViewColor(){&lt;br/&gt;    $(&lt;span style="color:#a31515"&gt;"table.myGridVew"&lt;/span&gt;).each(&lt;span style="color:blue"&gt;function&lt;/span&gt;(){&lt;br/&gt;        $(&lt;span style="color:blue"&gt;this&lt;/span&gt;).removeClass(&lt;span style="color:#a31515"&gt;"myGridVew"&lt;/span&gt;).addClass(&lt;span style="color:#a31515"&gt;"GridView"&lt;/span&gt;)&lt;br/&gt;            .find(&lt;span style="color:#a31515"&gt;"&amp;gt;thead&amp;gt;tr"&lt;/span&gt;).addClass(&lt;span style="color:#a31515"&gt;"GridView_HeaderStyle"&lt;/span&gt;).end()&lt;br/&gt;            .find(&lt;span style="color:#a31515"&gt;"&amp;gt;tbody&amp;gt;tr"&lt;/span&gt;)&lt;br/&gt;            .filter(&lt;span style="color:#a31515"&gt;':odd'&lt;/span&gt;).addClass(&lt;span style="color:#a31515"&gt;"GridView_AlternatingRowStyle"&lt;/span&gt;).end()&lt;br/&gt;            .filter(&lt;span style="color:#a31515"&gt;':even'&lt;/span&gt;).addClass(&lt;span style="color:#a31515"&gt;"GridView_RowStyle"&lt;/span&gt;);&lt;br/&gt;    });&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;p&gt;如果您认为很有必要在这个工具中集成数据表的查看（或者查询数据）的功能，那么可以自行实现（工具是开源的）。&lt;br /&gt;友情提示：使用上面的代码以及&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/21/2361982.html" target="_blank"&gt;&lt;b&gt;MyMVC框架&lt;/b&gt;&lt;/a&gt;，实现一个&lt;b&gt;简单的查看数据&lt;/b&gt;是会比较容易的。&lt;/p&gt;&lt;p&gt;今天就写到这里，希望大家能喜欢这个小工具，以及 &lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/21/2361982.html" target="_blank"&gt;&lt;b&gt;MyMVC框架&lt;/b&gt;&lt;/a&gt;。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://files.cnblogs.com/fish-li/SqlServerSmallTool.cab.7z"&gt;点击此处下载全部代码&lt;/a&gt;&lt;/p&gt;&lt;div class="articleFooter"&gt;&lt;p&gt;如果，您认为阅读这篇博客让您有些收获，不妨点击一下右下角的&lt;a id="btnRecommendMyBlog" href="javascript:void(0);"&gt;【&lt;b&gt;推荐&lt;/b&gt;】&lt;/a&gt;按钮。&lt;br /&gt;如果，您希望更容易地发现我的新博客，不妨点击一下右下角的&lt;a id="btnFollowFishLi" href="javascript:void(0);"&gt;【&lt;b&gt;关注 Fish Li&lt;/b&gt;】&lt;/a&gt;。&lt;br /&gt;因为，我的写作热情也离不开您的肯定支持。&lt;/p&gt;&lt;p&gt;感谢您的阅读，如果您对我的博客所讲述的内容有兴趣，请继续关注我的后续博客，我是Fish Li 。&lt;span class="icon_smile"&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/fish-li/aggbug/2379612.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/03/04/2379612.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/fish-li/archive/2012/02/26/2368989.html</id><title type="text">如何在IIS6,7中部署ASP.NET网站</title><summary type="text">在我的第一篇博客中，我发布过一个示例项目，主要演示了我的我的AJAX框架和我的通用数据访问层。虽然在当初我认为我已考虑地比较周全了，而且还提供了足够的说明文档，但在发布后的将近一年的时间里，还是有不少人给我发邮件，问我一些关于不能运行示例的问题。在所有问题中，主要集中在IIS和SQL SERVER的配置方面。因此，我认为还是有必要再来谈一下在IIS6/7以及SQL SERVER中部署ASP.NET网站的过程了。在上篇博客【写自己的ASP.NET MVC框架（下）】中，我又发布了一个示例项目，它也包含一个网站项目，今天的介绍过程将主要以这个示例为主。对于以前的示例所需配置的相同部分将不会重复介绍</summary><published>2012-02-26T12:20:00Z</published><updated>2012-02-26T12:20:00Z</updated><author><name>Fish Li</name><uri>http://www.cnblogs.com/fish-li/</uri></author><link rel="alternate" href="http://www.cnblogs.com/fish-li/archive/2012/02/26/2368989.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/fish-li/archive/2012/02/26/2368989.html"/><content type="html">&lt;p&gt;在我的第一篇博客中，我发布过一个&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/05/02/2034010.html" target="_blank"&gt;示例项目&lt;/a&gt;，主要演示了我的&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/03/12/1982434.html" target="_blank"&gt;我的AJAX框架&lt;/a&gt;和&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/03/28/1998104.html" target="_blank"&gt;我的通用数据访问层&lt;/a&gt;。虽然在当初我认为我已考虑地比较周全了，而且还提供了足够的说明文档，但在发布后的将近一年的时间里，还是有不少人给我发邮件，问我一些关于不能运行示例的问题。在所有问题中，主要集中在IIS和SQL SERVER的配置方面。因此，我认为还是有必要再来谈一下在IIS6/7以及SQL SERVER中部署ASP.NET网站的过程了。&lt;/p&gt;&lt;p&gt;在上篇博客&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/21/2361982.html" target="_blank"&gt;【写自己的ASP.NET MVC框架（下）】&lt;/a&gt;中，我又发布了一个示例项目，它也包含一个网站项目，&lt;b&gt;今天的介绍过程将主要以这个示例为主。&lt;/b&gt;对于以前的示例所需配置的相同部分将不会重复介绍，不同点则会额外补充。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;查看web.config文件&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;ASP.NET网站与一般的桌面程序不同，不是拷贝过来就能运行的（数据库连接除外）。要想运行它，通常需要一些配置过程。&lt;br /&gt;但是，我们到底需要配置什么呢？&lt;br /&gt;答案是：查看web.config &lt;/p&gt;&lt;p&gt;web.config通常会放在网站的根目录，这个文件中包含了一最重要的网站运行参数。比如：connectionStrings，httpHandlers，httpModules ，这些参数都是网站开发人员认为运行网站所必需的参数。因此，如果我们想将一个网站部署到IIS中，必须首先打开web.config文件，逐个确认这些重要的参数是否符合要求。&lt;/p&gt;&lt;p&gt;这里要补充一点的是：有些开发人员喜欢将各类参数放在appSettings配置节中，即便是数据库的连接字符串也放在appSettings中。我只能说：&lt;b&gt;这是个很不好的习惯。&lt;/b&gt;因此，在部署这类网站时，可能还要注意一下appSettings是否包含数据库的连接字符串，这就需要人工识别了。当然了，appSettings中还可能包含一些重要目录配置，同样，也只能人工识别了。&lt;/p&gt;&lt;p&gt;今天要讲述的参数主要涉及到IIS和SQL SERVER，因此本文将会分开介绍它们。&lt;br /&gt;而且IIS还会分为6和7.5二个版本来单独演示。&lt;br /&gt;SQL SERVER则以 2005 Express版本来演示。&lt;br /&gt;我演示所用的操作系统为：Windows Server 2003和Windows 7 ，它们分别附带了IIS 6和IIS 7.5&lt;/p&gt;&lt;p&gt;说明：通常我们在部署网站时，都应该先根据web.config定义的那些重要参数来配置网站。但为了让您能对这些参数有较深刻的印象，下面的演示中，不是先根据web.config来配置网站，而是采用【从创建一个站点后，一步一步地发现问题并解决】的方式来讲解这个过程。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;在IIS中创建网站&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;每个ASP.NET程序都是一个网站，要想运行它们，都需要在IIS中部署它们，部署的第一步就是要在IIS创建一个网站。在IIS中创建网站的过程比较简单，因为IIS都提供向导界面来帮助我们完成这个配置过程，因此，本文打算省略那些无意义的贴图。&lt;/p&gt;&lt;p&gt;说明，我们先从IIS6开始。这里只要求您在IIS中创建一个网站，把它配置成网站就可以了，其它的配置我们后面再谈。&lt;br /&gt;示例项目：&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/21/2361982.html" target="_blank"&gt;点击此处进入 MyMVC DEMO 下载页面&lt;/a&gt;&lt;/p&gt;&lt;p&gt;网站创建好了吗？我停下来等一下吧。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;我的网站配置好了，现在已经可以用浏览器访问它。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620045855.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;现在我们可以切换风格来试试效果，点击页面右上角的【3】试试看。&lt;/p&gt;&lt;p&gt;噢，怎么一开始就出错了：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620051780.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;看到这个提示，不要茫然。为了界面友好，我用JavaScript捕获了这个错误，但现在我们需要知道错误的原因是什么，怎么办呢？&lt;/p&gt;&lt;p&gt;有FireBug或者Fiddler2吗？&lt;br /&gt;如果有，就打开它们吧。下图是我用FireBug看到的错误原因（需要重新执行刚才的操作）：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620053345.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;从FireBug中，我们可以看到，刚才的操作触发了一次请求，请求的地址是：/AjaxStyle/SetStyle.cspx&lt;br /&gt;cspx是个什么扩展名呢？还是打开web.config看一下吧。&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;add &lt;/span&gt;&lt;span style="color:red"&gt;path&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*.cspx&lt;/span&gt;" &lt;span style="color:red"&gt;verb&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*&lt;/span&gt;" &lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;MyMVC.AjaxHandlerFactory, MyMVC&lt;/span&gt;" &lt;span style="color:red"&gt;validate&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;true&lt;/span&gt;" &lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;add &lt;/span&gt;&lt;span style="color:red"&gt;path&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*.aspx&lt;/span&gt;" &lt;span style="color:red"&gt;verb&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*&lt;/span&gt;" &lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;MyMVC.MvcPageHandlerFactory, MyMVC&lt;/span&gt;" &lt;span style="color:red"&gt;validate&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;true&lt;/span&gt;" &lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;add &lt;/span&gt;&lt;span style="color:red"&gt;path&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;/mvc/*&lt;/span&gt;" &lt;span style="color:red"&gt;verb&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*&lt;/span&gt;" &lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;MyMVC.MvcPageHandlerFactory, MyMVC&lt;/span&gt;" &lt;span style="color:red"&gt;validate&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;true&lt;/span&gt;" &lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;在web.config中，网站要求配置的一些httpHandlers中，第一个便是针对【cspx】扩展名的。&lt;/p&gt;&lt;p&gt;这里我要解释一下【cspx】这个扩展名了。在以前的示例中，我选择了【cs】这个扩展名表示一个AJAX调用，但是，后来发现很多人在IIS中部署中遇到问题了（原因后面再说）。于是，这次我换了个扩展名。然而，又有人问我：&lt;b&gt;cspx, 是不是写错了？&lt;/b&gt; 或许他认为应该是【aspx】才对。&lt;/p&gt;&lt;p&gt;这个问题我用邮件回答过多次了，今天用博客的形式再回答一次：&lt;br /&gt;取什么扩展名都不重要，我只要选择没有用过的扩展名来区分是AJAX调用就可以了。我也可以取【fish】来做为AJAX请求地址的扩展名，只是担心一些人认为俗气而已。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;IIS6 添加扩展名映射&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;回到IIS，在网站节点上，右击，从弹出的菜单中，选择【属性】，然后在弹出的对话框中，选择【主目录】选项卡，并点击【配置】按钮。此时的界面应该是这样的：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620055164.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;找到【ascx】这个扩展名，双击它，是不是弹出下面这个对话框？&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620060578.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;照着图片的操作去完成：复制【可执行文件】的设置路径。&lt;b&gt;然后点击【取消】关闭对话框。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;此时将回到【应用程序配置】对话框，点击【添加...】按钮，&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620061862.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;照着图片操作吧。对话框中的【可执行文件】的参数，此时已在Windows剪切板中，现在只要粘贴就可以了。&lt;/p&gt;&lt;p&gt;全部【确定】，关闭所有对话框，再回到浏览器，然后再试一次。&lt;/p&gt;&lt;p&gt;现在可以操作了吧？&lt;span class="icon_smile"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;先不要点击其它链接，还是来对刚才的操作做个小结吧。&lt;/p&gt;&lt;p&gt;在ASP.NET中，有时候我们可能会需要创建自己所需的HttpHandler来处理一些特殊的请求。&lt;br /&gt;我的MyMVC框架就有这个需求：将AJAX请求与页面的请求分开来处理。&lt;br /&gt;所以我们需要一些特殊格式的URL。通常选择一个没用过的扩展名会比较方便，因此我选择了 cspx&lt;br /&gt;为了能告诉ASP.NET将以下格式的ULR映射到AjaxHandlerFactory&lt;/p&gt;&lt;br/&gt;&lt;span style="color:green"&gt;/Fish.AA.AjaxTest/Add.cspx&lt;br/&gt;/Fish.BB.AjaxTest.Add.cspx&lt;br/&gt;/Fish/BB/AjaxTest/Add.cspx&lt;br/&gt;/AjaxDemo/GetMd5.cspx&lt;br/&gt;/AjaxDemo.GetMd5.cspx&lt;/span&gt;&lt;br/&gt;&lt;p&gt;我就需要在web.config中注册这种URL模式，并且为了能最好的匹配这些URL，我可以使用下面的配置：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;add &lt;/span&gt;&lt;span style="color:red"&gt;path&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*Ajax*/*.cspx,*Ajax*.*.cspx&lt;/span&gt;" &lt;span style="color:red"&gt;verb&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*&lt;/span&gt;" &lt;br/&gt;                                &lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;MyMVC.AjaxHandlerFactory, MyMVC&lt;/span&gt;" &lt;span style="color:red"&gt;validate&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;true&lt;/span&gt;"&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;我们可以用Visual Studio自带的WebDev.WebServer.EXE来运行网站程序。&lt;br /&gt;本来，这一切都是很完美的。&lt;br /&gt;可是，IIS中并不支持这么复杂的path设置，它只能支持简单的扩展名映射。&lt;br /&gt;所以，我也只好使用简单的扩展名：【.cspx】来向IIS注册。&lt;/p&gt;&lt;p&gt;我再来解释一下，为什么在ASP.NET中，前面那个path能够识别我上面所说的5种格式的URL？&lt;br /&gt;在ASP.NET管线的处理器映射阶段，ASP.NET会将【*Ajax*/*.cspx,*Ajax*.*.cspx】转换成下面的正则表达式，再来检查每个请求的URL是否匹配。&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;(?:\A|(?&amp;lt;=/))[^/]*Ajax[^/]*/[^/]*\.cspx\z|(?:\A|(?&amp;lt;=/))[^/]*Ajax[^/]*\.[^/]*\.cspx\z&lt;br/&gt;&lt;br/&gt;&lt;p&gt;有兴趣的话，您也可以检验一下，这个正则表达式与前面的URL都能匹配。&lt;br /&gt;从这里也可以看出ASP.NET对处理器的映射实现，是可以支持比较复杂的URL模式的。&lt;br /&gt;关于处理器的映射过程可以参考我的博客&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/01/29/2331477.html" target="_blank"&gt;【细说 HttpHandler 的映射过程】&lt;/a&gt;&lt;/p&gt;&lt;p&gt;前面解释了我为什么最终选择【.cspx】来向IIS注册处理器了。&lt;br /&gt;在注册时，还有二个参数也比较重要：&lt;br /&gt;1. 可执行文件：其实就是一个实现了ISAPI的模块，IIS会将匹配的请求交给它，然后由它再交给ASP.NET。这个参数的路径比较长，我们根本不需要记住它，只需要找个已有配置中，将它COPY出来就可以了。&lt;br /&gt;2. 确认文件是否存在：&lt;b class="redText"&gt;这个参数一定不要选择。&lt;/b&gt;因为我们请求的URL并没有对应的文件存在。&lt;/p&gt;&lt;p&gt;这里要补充一点：&lt;br /&gt;我以前发布的&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/05/02/2034010.html" target="_blank"&gt;FishWebLib DEMO&lt;/a&gt;中，使用了【cc】这样的扩展名，可以按照上面的方法注册。&lt;br /&gt;但我还使用了【cs】和【ascx】这二个扩展名。由于这二个扩展名的注册已经存在了，所以，我需要修改它们的配置：双击配置项，确保不要勾选【确认文件是否存在】即可。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620064056.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;IIS6 无扩展名的映射&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;让我们再回到前面已配置好的示例中，此时页面的显示应该是这个样子的：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620065856.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;点击一下页面上的链接【/mvc/Customers】试试。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620071397.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;不要以为我是在故意设置陷阱哦。我在设计示例程序时，根本也没想到会这样。&lt;/p&gt;&lt;p&gt;到这里，可能有人会想，在httpHandlers中不是还有个【path="/mvc/*"】没有配置吗？&lt;br /&gt;继续按照前面的方法去配置就能解决问题了。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620072937.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;好吧，我再照着前面的方法再试着注册【path="/mvc/*"】试试，结果如下：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620074351.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;因此，前面的方法对于这类【无扩展名】的URL来说，&lt;b&gt;是无效的。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;对于这类无扩展名的URL，在IIS6中可以使用添加【通配符应用程序映射】的方法来解决。&lt;br /&gt;回到【应用程序配置】对话框，点击【插入...】按钮，弹出下面的对话框：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620075941.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;按照图片来设置一下吧。然后，【确定】关闭对话框。此时的设置应该是这样的：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620081296.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;全部点击【确定】关闭所有对话框。&lt;/p&gt;&lt;p&gt;让我们再次回到示例程序，此时可以发现，什么问题都没有了。&lt;span class="icon_smile"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;再补充一句：如果使用这种方法，前面注册cspx的过程就不需要了。因为此时所有的请求都会交给ASP.NET，而ASP.NET会识别我在web.config中所做的配置。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;目录的写入权限&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;为了方便&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/21/2361982.html" target="_blank"&gt;MyMVC DEMO&lt;/a&gt;的部署过程，这次我选择了XML文件做为数据源。写入XML的时机是在ASP.NET被停止运行的时候（Application_End事件中）。&lt;/p&gt;&lt;p&gt;让一个在IIS中运行的网站停止运行的方法就是停止网站所使用的【应用程序池】。&lt;br /&gt;可以在网站属性对话框中找到网站所使用的【应用程序池】：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620082869.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;再切到IIS的【应用程序池】的列表，找到前面那个【应用程序池】，右击鼠标，&lt;br /&gt;从弹出的菜单中点击【属性】菜单，然后在出现的对话框中选择【标识】选项卡：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620084089.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;从这个图片中，我们可以知道网站以哪个Windows帐号在运行。记住这里，后面会用到。&lt;/p&gt;&lt;p&gt;好吧，&lt;b&gt;点击【取消】关闭对话框。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;补充一点：要想知道网站以什么帐号运行，还可以查看【Windows任务管理器】，找到w3wp.exe所在进程即可：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620085476.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;回到示例程序中，我们可以随便添加一些数据。&lt;br /&gt;然后，在【应用程序池】列表中，停止网站所使用的应用程序池。再启动它。&lt;br /&gt;重新刷新示例程序的页面。&lt;/p&gt;&lt;p&gt;发现什么了？是不是数据没有保存下来？&lt;/p&gt;&lt;p&gt;如果发现数据没有保存起来，可以继续阅读。&lt;/p&gt;&lt;p&gt;数据不能保存的原因并不是因为代码没有执行，而是因为，&lt;b&gt;网站运行的帐号没有权限写数据文件。&lt;/b&gt;&lt;br /&gt;XML是放在网站的App_Data目录中，为了检查网站是否有写入权限，可以在App_Data目录上右击，然后选择【属性】菜单，切换到【安全】选项卡：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620090938.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;经过前面的分析，我们已经知道网站是以【NETWORK SERVICE】帐号运行，然而，在这个目录的安全设置中，并没有允许【NETWORK SERVICE】帐号能有写入权限，所以，网站在停止运行时，是由于没有权限才导致不能保存数据的。&lt;/p&gt;&lt;p&gt;此时，我们可以赋予【NETWORK SERVICE】帐号对App_Data目录有写入权限。设置如下图：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620092496.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;好了，您可以再去重启网站所在的【应用程序池】，会发现现在数据能正常保存了。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;SQL SERVER的配置&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/05/02/2034010.html" target="_blank"&gt;FishWebLib DEMO&lt;/a&gt;中，我为了演示&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/03/28/1998104.html" target="_blank"&gt;我的通用数据访问层&lt;/a&gt;而引入了SQL SERVER，因此，示例程序需要SQL SERVER的支持。&lt;/p&gt;&lt;p&gt;首先，还是回到web.config，来看一下示例程序需要访问什么样的数据库：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620094531.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;注意：示例程序需要连接的SQL SERVER服务器是：&lt;b class="redText"&gt;localhost\sqlexpress&lt;/b&gt;&lt;/p&gt;&lt;p&gt;我的机器上安装了三个SQL SERVER的实例：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620100097.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;因此，我需要以【命名实例】的方式来访问。&lt;br /&gt;&lt;b&gt;如果您的机器将SQL SERVER做为【默认实例】来安装，则需要修改为：&lt;/b&gt;&lt;b class="redText"&gt;localhost&lt;/b&gt;&lt;/p&gt;&lt;p&gt;在示例的压缩包中，我提供了SQL SERVER所需的数据文件：db\MyNorthwind.mdf&lt;br /&gt;在运行示例前，我需要将它【附加】到SQL SERVER中。&lt;/p&gt;&lt;p&gt;现在需要先启动 SQL Server Management Studio ，连接SQL SERVER的实例后，&lt;br /&gt;在【对象资源管理器】的树型控件中，找到【数据库】节点，右击，然后点击【附加...】菜单，&lt;br /&gt;在出现的对话框中，点击【添加...】按钮，选择MyNorthwind.mdf文件，然后点击【确定】按钮。&lt;/p&gt;&lt;p&gt;我这边出错了。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620101635.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;再仔细地看一下，发现是日志文件没有找到造成的。&lt;br /&gt;是的，我并没将日志文件也放在压缩包中。&lt;br /&gt;好吧，在对话框中删除日志文件就可以了，再次【确定】。&lt;/p&gt;&lt;p&gt;还是出错：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620103093.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;注意了：这次的错误与前面的错误并不一样。&lt;/b&gt;&lt;b class="redText"&gt;这次是说没有目录的写入权限。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;当遇到没有目录的访问权限时，我们首先要知道程序是以什么帐号在运行。&lt;/b&gt;&lt;br /&gt;这是非常重要的。要不然，如何配置目录的访问权限呢？&lt;/p&gt;&lt;p&gt;判断程序以什么帐号运行最简单方法就是：打开【Windows任务管理器】，然后去找进程。&lt;br /&gt;这个方法可参考前面的过程。最终我们可以发现sqlserver.exe是以【NETWORK SERVICE】帐号在运行（我的机器是这样）。&lt;br /&gt;好吧，再按照前面设置App_Data目录权限的方法再设置MyNorthwind.mdf文件所在目录的访问权限。&lt;/p&gt;&lt;p&gt;再次尝试【附加】数据库，将能成功完成。&lt;br /&gt;在我机器上，现在已经可以运行示例程序了。&lt;/p&gt;&lt;p&gt;说明：如果由于种种原因，不使用【Integrated Security=SSPI】的连接认证方式，还可以使用【用户名/密码】的方式，那就需要修改web.config中的连接字符串了。&lt;/p&gt;&lt;p&gt;小结：&lt;br /&gt;1. 由于SQL SERVER的数据文件保存在Windows操作系统中，因此必须授予运行SQL SERVER进程的帐号所必需的目录访问权限。&lt;br /&gt;2. 连接到SQL SERVER时，也可能会因为SQL SERVER验证连接身份而失败，那么也必须配置需要的访问权限。&lt;/p&gt;&lt;p&gt;到此为止，示例所需的IIS配置以及SQL SERVER的配置都介绍完了。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;在IIS7中部署ASP.NET程序&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;前面介绍了如何在IIS6中部署一个ASP.NET网站，现来看一下在IIS7.5中如何完成这个过程。&lt;br /&gt;接下来的演示将以Windows 7的IIS7.5为准。&lt;/p&gt;&lt;p&gt;IIS7.5相对于IIS6的改进，给我的感觉是：&lt;b&gt;部署ASP.NET网站简直太容易了。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;IIS7为了兼容老版本，它支持二种模式来运行ASP.NET程序：集成模式，经典模式。&lt;br /&gt;所谓的经典模式，其实就是为了兼容IIS6的模式。下文将着重介绍集成模式，这样才能体现IIS改进的优势。&lt;/p&gt;&lt;p&gt;在IIS6中，我们需要配置扩展名的映射或者通配符映射，将请求交给一个ISAPI筛选器，然后由它再交给ASP.NET，最终由ASP.NET再将请求交给我们的httpHandlers, httpModules。我们在web.config中配置的httpHandlers, httpModules，对于IIS6来说是不可见的，所以，只能再次到IIS中配置。&lt;/p&gt;&lt;p&gt;从IIS7开始，IIS支持以一种称为【集成模式】的方式运行ASP.NET程序，此时，IIS能直接将请求交给ASP.NET的httpHandlers和httpModules，而且还可以直接从web.config中直接读取配置，因此，只要我们把web.config准备好，配置任务就非常简单了。&lt;/p&gt;&lt;p&gt;由于这个缘故，我在后来提供的示例中，在web.config中已增加对IIS7的支持。&lt;br /&gt;以下就是二个示例项目所需的IIS7的配置部分。&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/05/02/2034010.html" target="_blank"&gt;FishWebLib DEMO&lt;/a&gt;只需要下面的配置就可以了：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620111268.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/21/2361982.html" target="_blank"&gt;MyMVC DEMO&lt;/a&gt;所需的配置如下：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620113119.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;以上这些配置会反映在IIS7.5的哪些地方看到呢？&lt;br /&gt;请看下图：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620114547.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;在这个【处理器映射】列表中，前三个不正是我在web.config中的配置嘛。&lt;/p&gt;&lt;p&gt;前面还有一块fileExtensions的配置又是做什么的呢？&lt;br /&gt;请看下图：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620115834.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;对于&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/05/02/2034010.html" target="_blank"&gt;FishWebLib DEMO&lt;/a&gt;来说，它使用了 cs, ascx 这样的扩展名，而且这二个扩展名按照默认的配置是禁止访问的，所以在那个示例中，这段配置的用途是将这二个扩展名变成允许访问。&lt;/p&gt;&lt;p&gt;我在使用Windows7的IIS7.5时，还发现一个与IIS6不同的地方，它会默认为每个网站创建一个独立的应用程序池，而且运行帐号也不是NETWORK SERVICE，不过，我们可以容易地在【应用程序池】的属性中去修改它。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620121137.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;小结：&lt;br /&gt;在IIS7.5中部署ASP.NET网站是件容易的事，前提是：事先准备好web.config中的system.webServer配置节。&lt;br /&gt;然后只需要创建在IIS中创建一个网站，并指向程序目录即可。&lt;br /&gt;注意：如果程序需要访问本地文件或者数据库，那么还需要设置文件系统或者数据库的访问权限，具体可参考前面相关小节。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;80端口和域名&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在前面的演示中，为了简单，选择了25678这个端口，那是因为80端口已被使用。这样做实际上不影响网站的运行，不过，URL看起来就不美观了。通常HTTP默认是使用80端口，如果使用这个端口，那么URL中就不会出现端口号了。为了让URL地址看起来更美观，按下来我将演示如何使用80端口。&lt;/p&gt;&lt;p&gt;在IIS中，为了能让一个网站程序运行在80号端口中，有2个办法：&lt;br /&gt;1. 为网站程序使用其它的IP地址的80端口。&lt;br /&gt;2. 为网站指定域名绑定。&lt;/p&gt;&lt;p&gt;我们可以在网卡的配置中新增一个IP地址（如果已经有多个IP就不用这样做了）：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620122710.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;然后在IIS中，为网站设置【绑定】，使用这个IP地址了。请参考下图：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620124132.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;除了使用新IP地址的方式外，我们还可以使用域名的方式让网站可以在80端口下面运行。&lt;br /&gt;方法还是在IIS中设置网站的【绑定】操作，给网站指定一个域名即可：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620125381.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;最终的设置应该是下面这个样子的：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620131051.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;此时我们就可以使用下面二种方式来访问我的示例网站了：&lt;br /&gt;http://192.168.0.222&lt;br /&gt;http://www.mymvc-demo.com&lt;/p&gt;&lt;p&gt;不过这里又有个新问题：域名从哪里来？&lt;/p&gt;&lt;p&gt;答案有二个（对于演示来说）：&lt;br /&gt;1. 修改 C:\Windows\System32\drivers\etc\hosts 文件，&lt;br /&gt;增加一个映射条目：&lt;b&gt;127.0.0.1  www.mymvc-demo.com&lt;/b&gt; 即可。&lt;br /&gt;2. 如果您使用的是Windows Server的操作系统，也可以自己给自己分配域名，请继续阅读。&lt;/p&gt;&lt;p&gt;在Windows Server的操作系统中，我们可以使用DNS服务创建自己的域名，大致的过程是：&lt;br /&gt;1. 创建一个反向查找区域。&lt;br /&gt;2. 创建一个正向查找区域。&lt;br /&gt;3. 在正向查找区域新建一个WWW的主机。&lt;br /&gt;4. 在IIS中为网站设置绑定，指向新的域名。&lt;br /&gt;5. 设置网卡的DNS服务器地址，指向有DNS服务的机器。&lt;br /&gt;这种方式或许对于单台机器来说，比直接修改host文件要麻烦，但如果是在局域网内部使用将会非常方便。&lt;/p&gt;&lt;p&gt;DNS配置的相关过程如下：（向导中没有贴图的步骤可以直接确定）&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620132946.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620134112.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620135361.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620140570.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;现在我们就可以使用域名的方式来浏览我的示例了：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022620141725.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class="articleFooter"&gt;&lt;p&gt;如果，您认为阅读这篇博客让您有些收获，不妨点击一下右下角的&lt;a id="btnRecommendMyBlog" href="javascript:void(0);"&gt;【&lt;b&gt;推荐&lt;/b&gt;】&lt;/a&gt;按钮。&lt;br /&gt;如果，您希望更容易地发现我的新博客，不妨点击一下右下角的&lt;a id="btnFollowFishLi" href="javascript:void(0);"&gt;【&lt;b&gt;关注 Fish Li&lt;/b&gt;】&lt;/a&gt;。&lt;br /&gt;因为，我的写作热情也离不开您的肯定支持。&lt;/p&gt;&lt;p&gt;感谢您的阅读，如果您对我的博客所讲述的内容有兴趣，请继续关注我的后续博客，我是Fish Li 。&lt;span class="icon_smile"&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/fish-li/aggbug/2368989.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/26/2368989.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/fish-li/archive/2012/02/21/2361982.html</id><title type="text">写自己的ASP.NET MVC框架（下）</title><summary type="text">上篇博客【写自己的ASP.NET MVC框架（上）】我给大家介绍我的MVC框架对于Ajax的支持与实现原理。今天的博客将介绍我的MVC框架对UI部分的支持。注意：由于这篇博客是基于前篇博客的，因此有些已说过的内容将会直接跳过，也不会给出提示。所以，如果要想理解这篇博客，那么阅读上篇博客【写自己的ASP.NET MVC框架（上）】则是必要的。MyMVC的特点在开发MyMVC的过程中，我吸取了一些ASP.NET WebForm的使用经验，也参考了ASP.NET MVC，也接受了Martin Fowler对于MVC思想的总结。在设计过程中，我只实现了一些必要的功能，而且没有引入其它的类库与组件，因此</summary><published>2012-02-21T13:38:00Z</published><updated>2012-02-21T13:38:00Z</updated><author><name>Fish Li</name><uri>http://www.cnblogs.com/fish-li/</uri></author><link rel="alternate" href="http://www.cnblogs.com/fish-li/archive/2012/02/21/2361982.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/fish-li/archive/2012/02/21/2361982.html"/><content type="html">&lt;p&gt;上篇博客&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/12/2348395.html" target="_blank"&gt;【写自己的ASP.NET MVC框架（上）】&lt;/a&gt;我给大家介绍我的MVC框架对于Ajax的支持与实现原理。今天的博客将介绍我的MVC框架对UI部分的支持。&lt;/p&gt;&lt;p&gt;&lt;b&gt;注意：&lt;/b&gt;由于这篇博客是基于前篇博客的，因此有些已说过的内容将会直接跳过，也不会给出提示。&lt;br /&gt;所以，如果要想理解这篇博客，那么阅读上篇博客&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/12/2348395.html" target="_blank"&gt;【写自己的ASP.NET MVC框架（上）】&lt;/a&gt;则是必要的。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;MyMVC的特点&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在开发MyMVC的过程中，我吸取了一些ASP.NET WebForm的使用经验，也参考了ASP.NET MVC，也接受了Martin Fowler对于MVC思想的总结。在设计过程中，我只实现了一些必要的功能，而且没有引入其它的类库与组件，因此，它非常简单，且容易使用。&lt;/p&gt;&lt;p&gt;我们可以这样理解MyMVC：&lt;b class="redText"&gt;它是一个简单，容易使用，且符合MVC思想的框架。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;在MyMVC框架中，View仍然采用了WebForm中的Page，毕竟Page已经使用了十年，能经得起时间的检验，它仍然是我们可信赖的技术。另一方面，Page也是ASP.NET中默认的HTML输出技术，使用它会比较方便。&lt;/p&gt;&lt;p&gt;MyMVC与微软的ASP.NET MVC不同的是：&lt;br /&gt;1. 不依赖于URL路由组件。&lt;br /&gt;2. 不提供任何HtmlHelper&lt;br /&gt;3. Controller只是一个Action的容器，没有基类的要求。&lt;br /&gt;4. Action处理的请求不区分POST, GET&lt;br /&gt;5. URL可以直接对应一个网站目录中的aspx页面（View）。&lt;br /&gt;6. View的使用是使用路径来指定，与Controller,Action的名字无关。&lt;/p&gt;&lt;p&gt;说明：URL虽然可以与网站中的页面对应，但这种对应并不是必须的，也可以不对应。&lt;br /&gt;而且本质上与WebFrom中的页面执行过程并不相同。&lt;br /&gt;下图反映了在MyMVC中，一个页面请求的执行过程：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012021222062872.png" /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;介绍示例项目&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;为了让大家对MyMVC有兴趣，也为了检验MyMVC的设计，我在开发MyMVC的过程，还专门开发一个基于MyMVC的ASP.NET网站示例项目。网站提供了三种显示风格（也就是三种View），下面以“客户管理”页面为例来展示三种View的不同：&lt;/p&gt;&lt;p&gt;风格１&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022121082863.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;View对应的代码如下：&lt;a href="javascript:void(0);" codeId="pre-style1"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;@ &lt;/span&gt;&lt;span style="color:#a31515"&gt;Page &lt;/span&gt;&lt;span style="color:red"&gt;Title&lt;/span&gt;&lt;span style="color:blue"&gt;="客户管理" &lt;/span&gt;&lt;span style="color:red"&gt;Language&lt;/span&gt;&lt;span style="color:blue"&gt;="C#" &lt;/span&gt;&lt;span style="color:red"&gt;MasterPageFile&lt;/span&gt;&lt;span style="color:blue"&gt;="MasterPage.master" &lt;br/&gt;        &lt;/span&gt;&lt;span style="color:red"&gt;Inherits&lt;/span&gt;&lt;span style="color:blue"&gt;="MyPageView&amp;lt;CustomersPageModel&amp;gt;" &lt;/span&gt;&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Content &lt;/span&gt;&lt;span style="color:red"&gt;ID&lt;/span&gt;&lt;span style="color:blue"&gt;="Content1" &lt;/span&gt;&lt;span style="color:red"&gt;ContentPlaceHolderID&lt;/span&gt;&lt;span style="color:blue"&gt;="head" &lt;/span&gt;&lt;span style="color:red"&gt;Runat&lt;/span&gt;&lt;span style="color:blue"&gt;="Server"&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HtmlExtension&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;RefJsFileHtml(&lt;span style="color:#a31515"&gt;"/js/MyPage/Customers.js"&lt;/span&gt;)&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Content&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Content &lt;/span&gt;&lt;span style="color:red"&gt;ID&lt;/span&gt;&lt;span style="color:blue"&gt;="Content2" &lt;/span&gt;&lt;span style="color:red"&gt;ContentPlaceHolderID&lt;/span&gt;&lt;span style="color:blue"&gt;="ContentPlaceHolder1" &lt;/span&gt;&lt;span style="color:red"&gt;Runat&lt;/span&gt;&lt;span style="color:blue"&gt;="Server"&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;a &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="btnCreateItem" &lt;/span&gt;&lt;span style="color:red"&gt;href&lt;/span&gt;&lt;span style="color:blue"&gt;="#" &lt;/span&gt;&lt;span style="color:red"&gt;class&lt;/span&gt;&lt;span style="color:blue"&gt;="easyui-linkbutton" &lt;/span&gt;&lt;span style="color:red"&gt;iconCls&lt;/span&gt;&lt;span style="color:blue"&gt;="icon-add"&amp;gt;&lt;/span&gt;创建客户&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;a&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;table &lt;/span&gt;&lt;span style="color:red"&gt;class&lt;/span&gt;&lt;span style="color:blue"&gt;="GridView" &lt;/span&gt;&lt;span style="color:red"&gt;cellspacing&lt;/span&gt;&lt;span style="color:blue"&gt;="0" &lt;/span&gt;&lt;span style="color:red"&gt;cellpadding&lt;/span&gt;&lt;span style="color:blue"&gt;="4" &lt;/span&gt;&lt;span style="color:red"&gt;border&lt;/span&gt;&lt;span style="color:blue"&gt;="0" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;border-collapse&lt;/span&gt;:&lt;span style="color:blue"&gt;collapse&lt;/span&gt;;&lt;span style="color:blue"&gt;"&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr &lt;/span&gt;&lt;span style="color:red"&gt;align&lt;/span&gt;&lt;span style="color:blue"&gt;="left"&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;th &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;:&lt;span style="color:blue"&gt;20px&lt;/span&gt;;&lt;span style="color:blue"&gt;"&amp;gt;&lt;/span&gt;&lt;span style="color:red"&gt;&amp;amp;nbsp;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;th&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;th &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;:&lt;span style="color:blue"&gt;260px&lt;/span&gt;;&lt;span style="color:blue"&gt;"&amp;gt;&lt;/span&gt;客户名称&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;th&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;th &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;:&lt;span style="color:blue"&gt;80px&lt;/span&gt;;&lt;span style="color:blue"&gt;"&amp;gt;&lt;/span&gt;联系人&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;th&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;th&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;地址&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;th&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;th &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;:&lt;span style="color:blue"&gt;80px&lt;/span&gt;;&lt;span style="color:blue"&gt;"&amp;gt;&lt;/span&gt;邮编&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;th&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;th &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;:&lt;span style="color:blue"&gt;160px&lt;/span&gt;;&lt;span style="color:blue"&gt;"&amp;gt;&lt;/span&gt;电话&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;th&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;Customer &lt;/span&gt;customer &lt;span style="color:blue"&gt;in &lt;/span&gt;Model&lt;span style="color:red"&gt;.&lt;/span&gt;List ) { &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;    &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;a &lt;/span&gt;&lt;span style="color:red"&gt;href&lt;/span&gt;&lt;span style="color:blue"&gt;="/AjaxCustomer/Delete.cspx?id=&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;= customer.CustomerID &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;amp;returnUrl=&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;= RequestUrlEncodeRawUrl &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;" &lt;br/&gt;                    &lt;/span&gt;&lt;span style="color:red"&gt;title&lt;/span&gt;&lt;span style="color:blue"&gt;="删除" &lt;/span&gt;&lt;span style="color:red"&gt;class&lt;/span&gt;&lt;span style="color:blue"&gt;="easyui-linkbutton" &lt;/span&gt;&lt;span style="color:red"&gt;plain&lt;/span&gt;&lt;span style="color:blue"&gt;="true"&amp;gt;&lt;br/&gt;            &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;img &lt;/span&gt;&lt;span style="color:red"&gt;src&lt;/span&gt;&lt;span style="color:blue"&gt;="/Images/delete.gif" &lt;/span&gt;&lt;span style="color:red"&gt;alt&lt;/span&gt;&lt;span style="color:blue"&gt;="删除" /&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;a&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;                &lt;br/&gt;        &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;a &lt;/span&gt;&lt;span style="color:red"&gt;href&lt;/span&gt;&lt;span style="color:blue"&gt;="#" &lt;/span&gt;&lt;span style="color:red"&gt;class&lt;/span&gt;&lt;span style="color:blue"&gt;="easyui-linkbutton" &lt;/span&gt;&lt;span style="color:red"&gt;rowId&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;= customer.CustomerID &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;" &lt;/span&gt;&lt;span style="color:red"&gt;plain&lt;/span&gt;&lt;span style="color:blue"&gt;="true" &lt;/span&gt;&lt;span style="color:red"&gt;iconCls&lt;/span&gt;&lt;span style="color:blue"&gt;="icon-open"&amp;gt;&lt;br/&gt;                &lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;customer&lt;span style="color:red"&gt;.&lt;/span&gt;CustomerName&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode()&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;a&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;span &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="ContactName"&amp;gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;customer&lt;span style="color:red"&gt;.&lt;/span&gt;ContactName&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;span&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;span &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="Address"&amp;gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;customer&lt;span style="color:red"&gt;.&lt;/span&gt;Address&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;span&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;span &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="PostalCode"&amp;gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;customer&lt;span style="color:red"&gt;.&lt;/span&gt;PostalCode&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;span&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;span &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="Tel"&amp;gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;customer&lt;span style="color:red"&gt;.&lt;/span&gt;Tel&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;span&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;Model&lt;span style="color:red"&gt;.&lt;/span&gt;PagingInfo&lt;span style="color:red"&gt;.&lt;/span&gt;PaginationBar(&lt;span style="color:purple"&gt;6&lt;/span&gt;)&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;table&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;div &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="divCustomerInfo" &lt;/span&gt;&lt;span style="color:red"&gt;title&lt;/span&gt;&lt;span style="color:blue"&gt;="客户" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;padding&lt;/span&gt;: &lt;span style="color:blue"&gt;8px&lt;/span&gt;; &lt;span style="color:red"&gt;display&lt;/span&gt;: &lt;span style="color:blue"&gt;none"&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;UcExecutor&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Render(&lt;span style="color:#a31515"&gt;"/Controls/Style1/CustomerInfo.ascx"&lt;/span&gt;, Model&lt;span style="color:red"&gt;.&lt;/span&gt;Customer)&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;div&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Content&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;风格２&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022121084894.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;View对应的代码如下：&lt;a href="javascript:void(0);" codeId="pre-style2"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;@ &lt;/span&gt;&lt;span style="color:#a31515"&gt;Page &lt;/span&gt;&lt;span style="color:red"&gt;Title&lt;/span&gt;&lt;span style="color:blue"&gt;="客户管理" &lt;/span&gt;&lt;span style="color:red"&gt;Language&lt;/span&gt;&lt;span style="color:blue"&gt;="C#" &lt;/span&gt;&lt;span style="color:red"&gt;MasterPageFile&lt;/span&gt;&lt;span style="color:blue"&gt;="MasterPage.master" &lt;/span&gt;&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Content &lt;/span&gt;&lt;span style="color:red"&gt;ID&lt;/span&gt;&lt;span style="color:blue"&gt;="Content1" &lt;/span&gt;&lt;span style="color:red"&gt;ContentPlaceHolderID&lt;/span&gt;&lt;span style="color:blue"&gt;="head" &lt;/span&gt;&lt;span style="color:red"&gt;Runat&lt;/span&gt;&lt;span style="color:blue"&gt;="Server"&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HtmlExtension&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;RefJsFileHtml(&lt;span style="color:#a31515"&gt;"/js/MyPage2/Customers.js"&lt;/span&gt;)&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Content&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Content &lt;/span&gt;&lt;span style="color:red"&gt;ID&lt;/span&gt;&lt;span style="color:blue"&gt;="Content2" &lt;/span&gt;&lt;span style="color:red"&gt;ContentPlaceHolderID&lt;/span&gt;&lt;span style="color:blue"&gt;="ContentPlaceHolder1" &lt;/span&gt;&lt;span style="color:red"&gt;Runat&lt;/span&gt;&lt;span style="color:blue"&gt;="Server"&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;table &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="grid1"&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;table&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;div &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="divCustomerInfo" &lt;/span&gt;&lt;span style="color:red"&gt;title&lt;/span&gt;&lt;span style="color:blue"&gt;="客户" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;padding&lt;/span&gt;: &lt;span style="color:blue"&gt;8px&lt;/span&gt;; &lt;span style="color:red"&gt;display&lt;/span&gt;: &lt;span style="color:blue"&gt;none"&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;UcExecutor&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Render(&lt;span style="color:#a31515"&gt;"/Controls/Style2/CustomerInfo.ascx"&lt;/span&gt;, &lt;span style="color:blue"&gt;null&lt;/span&gt;)&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;div&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Content&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;风格３&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022121090469.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;View对应的代码如下：&lt;a href="javascript:void(0);" codeId="pre-style3"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;@ &lt;/span&gt;&lt;span style="color:#a31515"&gt;Page &lt;/span&gt;&lt;span style="color:red"&gt;Title&lt;/span&gt;&lt;span style="color:blue"&gt;="客户管理" &lt;/span&gt;&lt;span style="color:red"&gt;Language&lt;/span&gt;&lt;span style="color:blue"&gt;="C#" &lt;/span&gt;&lt;span style="color:red"&gt;MasterPageFile&lt;/span&gt;&lt;span style="color:blue"&gt;="MasterPage.master" &lt;br/&gt;        &lt;/span&gt;&lt;span style="color:red"&gt;Inherits&lt;/span&gt;&lt;span style="color:blue"&gt;="MyPageView&amp;lt;CustomersPageModel&amp;gt;" &lt;/span&gt;&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Content &lt;/span&gt;&lt;span style="color:red"&gt;ID&lt;/span&gt;&lt;span style="color:blue"&gt;="Content1" &lt;/span&gt;&lt;span style="color:red"&gt;ContentPlaceHolderID&lt;/span&gt;&lt;span style="color:blue"&gt;="head" &lt;/span&gt;&lt;span style="color:red"&gt;Runat&lt;/span&gt;&lt;span style="color:blue"&gt;="Server"&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Content&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Content &lt;/span&gt;&lt;span style="color:red"&gt;ID&lt;/span&gt;&lt;span style="color:blue"&gt;="Content2" &lt;/span&gt;&lt;span style="color:red"&gt;ContentPlaceHolderID&lt;/span&gt;&lt;span style="color:blue"&gt;="ContentPlaceHolder1" &lt;/span&gt;&lt;span style="color:red"&gt;Runat&lt;/span&gt;&lt;span style="color:blue"&gt;="Server"&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;ul &lt;/span&gt;&lt;span style="color:red"&gt;class&lt;/span&gt;&lt;span style="color:blue"&gt;="itemList"&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;Customer &lt;/span&gt;customer &lt;span style="color:blue"&gt;in &lt;/span&gt;Model&lt;span style="color:red"&gt;.&lt;/span&gt;List ) { &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;li&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;table &lt;/span&gt;&lt;span style="color:red"&gt;class&lt;/span&gt;&lt;span style="color:blue"&gt;="GridView" &lt;/span&gt;&lt;span style="color:red"&gt;cellspacing&lt;/span&gt;&lt;span style="color:blue"&gt;="0" &lt;/span&gt;&lt;span style="color:red"&gt;cellpadding&lt;/span&gt;&lt;span style="color:blue"&gt;="4" &lt;/span&gt;&lt;span style="color:red"&gt;border&lt;/span&gt;&lt;span style="color:blue"&gt;="0" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;border-collapse&lt;/span&gt;:&lt;span style="color:blue"&gt;collapse&lt;/span&gt;;&lt;span style="color:blue"&gt;"&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;customer&lt;span style="color:red"&gt;.&lt;/span&gt;CustomerName&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode()&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;customer&lt;span style="color:red"&gt;.&lt;/span&gt;ContactName&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;customer&lt;span style="color:red"&gt;.&lt;/span&gt;Address&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;customer&lt;span style="color:red"&gt;.&lt;/span&gt;PostalCode&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;customer&lt;span style="color:red"&gt;.&lt;/span&gt;Tel&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;table&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;li&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;ul&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;Model&lt;span style="color:red"&gt;.&lt;/span&gt;PagingInfo&lt;span style="color:red"&gt;.&lt;/span&gt;PaginationBar()&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Content&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;这是三种截然不同的风格，在服务端的代码也是完全不同的。&lt;/p&gt;&lt;p&gt;其中第二种风格，是采用了我上篇博客中总结的【纯AJAX网站】的风格来开发，因此在服务端页面的开发过程中，最为简单，它需要输出的HTML最少，UI部分由客户端的JS来实现。&lt;/p&gt;&lt;p&gt;对于第一种和第三种风格，它们的HTML结构是不同的，页面所能完成的功能也是不同的，除此之外，它们应该是比较类似的，都是从下面这个泛型类型继承而来：&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:red"&gt;Inherits&lt;/span&gt;&lt;span style="color:blue"&gt;="MyPageView&amp;lt;CustomersPageModel&amp;gt;"&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;从泛型类型继承的好处是：我可以在设计页面时，对于涉及Model的访问，都会有智能提示。比如：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022121092093.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;由于有智能提示的支持，可以提高开发效率，并可以避免一些低级的拼写错误。&lt;/p&gt;&lt;p&gt;虽然前面我们可以从图片中看到访问【同一个URL地址】出现【三个不同的页面】，但它们背后的Controller却是同一个：&lt;a href="javascript:void(0);" codeId="pre-CustomerController1"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CustomerController&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;PageUrl&lt;/span&gt;(Url &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/mvc/Customers"&lt;/span&gt;)]&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;PageUrl&lt;/span&gt;(Url &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/mvc/Customers.html"&lt;/span&gt;)]&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;PageUrl&lt;/span&gt;(Url &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/mvc/CustomerList.aspx"&lt;/span&gt;)]&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;PageUrl&lt;/span&gt;(Url &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/Pages/Customers.aspx"&lt;/span&gt;)]&lt;br/&gt;    &lt;span style="color:blue"&gt;public static object &lt;/span&gt;LoadModel(&lt;span style="color:blue"&gt;int&lt;/span&gt;&lt;span style="color:red"&gt;? &lt;/span&gt;page)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:green"&gt;// 说明：参数page表示分页数，方法名LoadModel其实可以【随便取】。&lt;br/&gt;&lt;br/&gt;        // 根据用户选择的界面风格，计算实现要呈现的页面路径。&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:blue"&gt;string &lt;/span&gt;papeUrl &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;StyleHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetTargetPageUrl(&lt;span style="color:#a31515"&gt;"Customers.aspx"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;StyleHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;PageStyle &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:#2b91af"&gt;StyleHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;StyleArray[&lt;span style="color:purple"&gt;1&lt;/span&gt;] )&lt;br/&gt;            &lt;span style="color:green"&gt;// Style2 风格下，页面不需要绑定数据。数据由JS通过AJAX方式获取&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;PageResult&lt;/span&gt;(papeUrl, &lt;span style="color:blue"&gt;null&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 为Style1 风格获取数据。&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CustomerSearchInfo &lt;/span&gt;info &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CustomerSearchInfo&lt;/span&gt;();&lt;br/&gt;        info&lt;span style="color:red"&gt;.&lt;/span&gt;SearchWord &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Empty;&lt;br/&gt;        info&lt;span style="color:red"&gt;.&lt;/span&gt;PageIndex &lt;span style="color:red"&gt;= &lt;/span&gt;page&lt;span style="color:red"&gt;.&lt;/span&gt;HasValue &lt;span style="color:red"&gt;? &lt;/span&gt;page&lt;span style="color:red"&gt;.&lt;/span&gt;Value &lt;span style="color:red"&gt;- &lt;/span&gt;&lt;span style="color:purple"&gt;1 &lt;/span&gt;: &lt;span style="color:purple"&gt;0&lt;/span&gt;;&lt;br/&gt;        info&lt;span style="color:red"&gt;.&lt;/span&gt;PageSize &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;AppHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;DefaultPageSize;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;CustomersPageModel &lt;/span&gt;result &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CustomersPageModel&lt;/span&gt;();&lt;br/&gt;        result&lt;span style="color:red"&gt;.&lt;/span&gt;PagingInfo &lt;span style="color:red"&gt;= &lt;/span&gt;info;&lt;br/&gt;        result&lt;span style="color:red"&gt;.&lt;/span&gt;List &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BllFactory&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetCustomerBLL()&lt;span style="color:red"&gt;.&lt;/span&gt;GetList(info);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;PageResult&lt;/span&gt;(papeUrl, result);&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;通过上面代码可以看到我用了4个[PageUrl]，这意味着其实我可以使用4种不同的URL都能访问到这三个页面，&lt;b&gt;而且每一个URL都会根据当前用户所选择的风格，呈现对应的页面。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;事实上，我还可以为这个Action指定更多的[PageUrl]，让它可以处理更多的URL。关于[PageUrl]的使用与设计目的，请继续往下阅读。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;关于URL路由&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;随着 .net framewrok 3.5 的问世，微软发布了一个【ASP.NET 路由】组件，它的出现给当时的URL优化方法提供了另外一种选择，不仅如此，它还提供了一些URL重写组件没有的功能：生成URL 。&lt;/p&gt;&lt;p&gt;随着AP.NET MVC的出现，【ASP.NET 路由】成为此框架的直接依赖组件，我们很难有其它的选择，而且，想不用都不行。&lt;/p&gt;&lt;p&gt;有趣的是：【ASP.NET 路由】这个后生小子的出现，并没有很好地遵守ASP.NET制定的一些规则，其中最为明显的是：它跳过了【处理器的映射】阶段，导致ASP.NET MVC在支持Session时，很为难。直到最后ASP.NET 4.0，微软修改了Session的部分实现方式，这样ASP.NET MVC才能最终借此机会解决Session的完整支持问题。&lt;/p&gt;&lt;p&gt;ASP.NET 路由虽然可以生成URL，但它引入了RouteData的概念，要想支持它，需要在框架层面上做许多基础工作。&lt;/p&gt;&lt;p&gt;而且，我认为：&lt;br /&gt;1. 并不是每个网站都需要这种技术，对于不需要URL优化的网站来说，URL路由的使用只是白白地浪费性能。&lt;br /&gt;2. 另一方面，即使需要URL优化，我们还有众多的URL重写组件可供选择，这样可以不用改变现在构架。&lt;/p&gt;&lt;p&gt;因此，&lt;b&gt;MyMVC虽然不支持URL路由，但并不表示不能实现URL优化。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;在MVC思想中，Controller应该是处理请求的地方，也是最先运行的部分。然而在传统的WebForm编程模型中，aspx页面负责处理请求。因此，必须采取一种方式让最先处理请求的地方从aspx页面中转移，并能提前执行。&lt;/p&gt;&lt;p&gt;而且，将代码从页面移出还有另外二个好处：&lt;br /&gt;1. 被移出的代码肯定是与UI部分无关的，因此，会比较容易测试。&lt;br /&gt;2. 代码与UI的分享也意味着：可以根据运行条件，有选择地将结果交给不同的View来呈现。&lt;/p&gt;&lt;p&gt;考虑到Action可以选择将结果交给不同的View来呈现，而Session也需要支持的问题，最终我决定，在框架内部使用一个专门的HttpHandler来执行用户的Action，根据Action所要求的Session支持模式，HttpHandlerFactory创建不同的HttpHandler来支持。由于需要使用HttpHandlerFactory，所以必须在web.config中注册。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;配置MyMVC框架&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;MyMVC在使用时，需要在web.config中简单的配置：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;add &lt;/span&gt;&lt;span style="color:red"&gt;path&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*.aspx&lt;/span&gt;" &lt;span style="color:red"&gt;verb&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*&lt;/span&gt;" &lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;MyMVC.MvcPageHandlerFactory, MyMVC&lt;/span&gt;" &lt;span style="color:red"&gt;validate&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;true&lt;/span&gt;"&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;如果使用IIS7，则参考以下配置：&lt;a href="javascript:void(0);" codeId="pre-MvcPageHandlerFactory-iis7""&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;system.webServer&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;handlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;add &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;MvcPageHandlerFactory&lt;/span&gt;" &lt;span style="color:red"&gt;verb&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*&lt;/span&gt;" &lt;span style="color:red"&gt;path&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*.aspx&lt;/span&gt;" &lt;br/&gt;                &lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;MyMVC.MvcPageHandlerFactory, MyMVC&lt;/span&gt;" &lt;span style="color:red"&gt;preCondition&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;integratedMode&lt;/span&gt;"&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;handlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;system.webServer&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;我们可以把MvcPageHandlerFactory理解成MyMVC在ASP.NET管线的入口。&lt;/p&gt;&lt;p&gt;&lt;b&gt;注意：&lt;br /&gt;1. 上面的配置代码中，选择aspx这个扩展名并不是必须的，您也可以选择喜欢的扩展名。&lt;br /&gt;2. 如果不喜欢扩展名的映射，可以使用HttpModule，MyMVC中提供的方法也能替代这个过程。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;映射处理器（入口）&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在web.config中注册MvcPageHandlerFactory后，所有符合条件的请求将会进入MvcPageHandlerFactory。&lt;br /&gt;我们来看一下MvcPageHandlerFactory的实现代码：&lt;a href="javascript:void(0);" codeId="pre-MvcPageHandlerFactory"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal sealed class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;AspnetPageHandlerFactory &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;PageHandlerFactory &lt;/span&gt;{ }&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public sealed class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MvcPageHandlerFactory &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IHttpHandlerFactory&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;尝试根据当前请求，获取一个有效的Action，并返回ActionHandler&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;此方法可以在HttpModule中使用，用于替代httpHandler的映射配置&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    /// &amp;lt;param name="context"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;public static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;TryGetHandler(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;InvokeInfo &lt;/span&gt;vkInfo &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ReflectionHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetPageActionInvokeInfo(context&lt;span style="color:red"&gt;.&lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;FilePath);&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( vkInfo &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) &lt;br/&gt;            &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ActionHandler&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;CreateHandler(vkInfo);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;AspnetPageHandlerFactory &lt;/span&gt;_msPageHandlerFactory;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;IHttpHandler IHttpHandlerFactory&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetHandler(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context, &lt;br/&gt;                        &lt;span style="color:blue"&gt;string &lt;/span&gt;requestType, &lt;span style="color:blue"&gt;string &lt;/span&gt;virtualPath, &lt;span style="color:blue"&gt;string &lt;/span&gt;physicalPath)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:green"&gt;// 尝试根据请求路径获取Action&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:#2b91af"&gt;InvokeInfo &lt;/span&gt;vkInfo &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ReflectionHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetPageActionInvokeInfo(virtualPath);&lt;br/&gt;        &lt;br/&gt;        &lt;span style="color:green"&gt;// 如果没有找到合适的Action，并且请求的是一个ASPX页面，则按ASP.NET默认的方式来继续处理&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( vkInfo &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;&lt;span style="color:red"&gt;&amp;amp;&amp;amp; &lt;/span&gt;virtualPath&lt;span style="color:red"&gt;.&lt;/span&gt;EndsWith(&lt;span style="color:#a31515"&gt;".aspx"&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;StringComparison&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;OrdinalIgnoreCase) ) {&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( _msPageHandlerFactory &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;                _msPageHandlerFactory &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;AspnetPageHandlerFactory&lt;/span&gt;();&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:green"&gt;// 调用ASP.NET默认的Page处理器工厂来处理&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:blue"&gt;return &lt;/span&gt;_msPageHandlerFactory&lt;span style="color:red"&gt;.&lt;/span&gt;GetHandler(context, requestType, virtualPath, physicalPath);&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ActionHandler&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;CreateHandler(vkInfo);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;void &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IHttpHandlerFactory&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;ReleaseHandler(&lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;handler)&lt;br/&gt;    {            &lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;从代码中可以看到，MyMVC首先会根据当前的请求地址查找有没有一个Action可以处理它，如果没有，则采用ASP.NET默认的方式来处理。因此，把【*.aspx】交给MvcPageHandlerFactory是不会有问题的。&lt;/p&gt;&lt;p&gt;说明：创建一个空壳类型AspnetPageHandlerFactory的原因是：不能直接调用PageHandlerFactory的构造函数。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;内部初始化&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;MyMVC在第一次处理请求时，要做一个初始化的过程，这个过程是由MvcPageHandlerFactory中的一个调用引发的：&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:green"&gt;// 尝试根据请求路径获取Action&lt;br/&gt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;InvokeInfo &lt;/span&gt;vkInfo &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ReflectionHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetPageActionInvokeInfo(virtualPath);&lt;br/&gt;&lt;br/&gt;&lt;p&gt;ReflectionHelper有个静态构造函数，虽然上次我已贴出它的代码，但那只是部分代码，以下才是完整的初始化代码：&lt;a href="javascript:void(0);" codeId="pre-ReflectionHelper"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal static class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ReflectionHelper&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;// 保存PageAction的字典&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;private static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Dictionary&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;ActionDescription&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;s_PageActionDict;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 保存AjaxController的列表&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;private static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ControllerDescription&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;s_AjaxControllerList;&lt;br/&gt;    &lt;span style="color:green"&gt;// 保存AjaxAction的字典&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;private static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Hashtable &lt;/span&gt;s_AjaxActionTable &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Hashtable&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Synchronized(&lt;br/&gt;                                        &lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Hashtable&lt;/span&gt;(&lt;span style="color:purple"&gt;4096&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;StringComparer&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;OrdinalIgnoreCase));&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 用于从类型查找Action的反射标记&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;private static readonly &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BindingFlags &lt;/span&gt;ActionBindingFlags &lt;span style="color:red"&gt;=&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BindingFlags&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Static &lt;span style="color:red"&gt;| &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BindingFlags&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Instance &lt;span style="color:red"&gt;| &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BindingFlags&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Public &lt;span style="color:red"&gt;| &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BindingFlags&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IgnoreCase;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;static &lt;/span&gt;ReflectionHelper()&lt;br/&gt;    {&lt;br/&gt;        InitControllers();&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;加载所有的Controller&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;private static void &lt;/span&gt;InitControllers()&lt;br/&gt;    {&lt;br/&gt;        s_AjaxControllerList &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ControllerDescription&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt;&lt;/span&gt;(&lt;span style="color:purple"&gt;1024&lt;/span&gt;);&lt;br/&gt;        &lt;span style="color:blue"&gt;var &lt;/span&gt;pageControllerList &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ControllerDescription&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt;&lt;/span&gt;(&lt;span style="color:purple"&gt;1024&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;ICollection &lt;/span&gt;assemblies &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BuildManager&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetReferencedAssemblies();&lt;br/&gt;        &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;Assembly &lt;/span&gt;assembly &lt;span style="color:blue"&gt;in &lt;/span&gt;assemblies ) {&lt;br/&gt;            &lt;span style="color:green"&gt;// 过滤以【System.】开头的程序集，加快速度&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( assembly&lt;span style="color:red"&gt;.&lt;/span&gt;FullName&lt;span style="color:red"&gt;.&lt;/span&gt;StartsWith(&lt;span style="color:#a31515"&gt;"System."&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;StringComparison&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;OrdinalIgnoreCase) )&lt;br/&gt;                &lt;span style="color:blue"&gt;continue&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:blue"&gt;try &lt;/span&gt;{&lt;br/&gt;                &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;Type &lt;/span&gt;t &lt;span style="color:blue"&gt;in &lt;/span&gt;assembly&lt;span style="color:red"&gt;.&lt;/span&gt;GetExportedTypes() ) {&lt;br/&gt;                    &lt;span style="color:blue"&gt;if&lt;/span&gt;( t&lt;span style="color:red"&gt;.&lt;/span&gt;Name&lt;span style="color:red"&gt;.&lt;/span&gt;StartsWith(&lt;span style="color:#a31515"&gt;"Ajax"&lt;/span&gt;) )&lt;br/&gt;                        s_AjaxControllerList&lt;span style="color:red"&gt;.&lt;/span&gt;Add(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ControllerDescription&lt;/span&gt;(t));&lt;br/&gt;&lt;br/&gt;                    &lt;span style="color:blue"&gt;else if&lt;/span&gt;( t&lt;span style="color:red"&gt;.&lt;/span&gt;Name&lt;span style="color:red"&gt;.&lt;/span&gt;EndsWith(&lt;span style="color:#a31515"&gt;"Controller"&lt;/span&gt;) )&lt;br/&gt;                        pageControllerList&lt;span style="color:red"&gt;.&lt;/span&gt;Add(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ControllerDescription&lt;/span&gt;(t));&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;            &lt;span style="color:blue"&gt;catch &lt;/span&gt;{ }&lt;br/&gt;        }&lt;br/&gt;                    &lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 提前加载Page Controller中的所有Action方法&lt;br/&gt;        &lt;/span&gt;s_PageActionDict &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Dictionary&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;ActionDescription&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt;&lt;/span&gt;(&lt;span style="color:purple"&gt;4096&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;StringComparer&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;OrdinalIgnoreCase);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;ControllerDescription &lt;/span&gt;controller &lt;span style="color:blue"&gt;in &lt;/span&gt;pageControllerList ) {&lt;br/&gt;            &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;MethodInfo &lt;/span&gt;m &lt;span style="color:blue"&gt;in &lt;/span&gt;controller&lt;span style="color:red"&gt;.&lt;/span&gt;ControllerType&lt;span style="color:red"&gt;.&lt;/span&gt;GetMethods(ActionBindingFlags) ) {&lt;br/&gt;                &lt;span style="color:#2b91af"&gt;PageUrlAttribute&lt;/span&gt;[] pageUrlAttrs &lt;span style="color:red"&gt;= &lt;/span&gt;m&lt;span style="color:red"&gt;.&lt;/span&gt;GetMyAttributes&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;PageUrlAttribute&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt;&lt;/span&gt;();&lt;br/&gt;                &lt;span style="color:#2b91af"&gt;ActionAttribute &lt;/span&gt;actionAttr &lt;span style="color:red"&gt;= &lt;/span&gt;m&lt;span style="color:red"&gt;.&lt;/span&gt;GetMyAttribute&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ActionAttribute&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt;&lt;/span&gt;();&lt;br/&gt;&lt;br/&gt;                &lt;span style="color:blue"&gt;if&lt;/span&gt;( pageUrlAttrs&lt;span style="color:red"&gt;.&lt;/span&gt;Length &lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;&lt;span style="color:red"&gt;&amp;amp;&amp;amp; &lt;/span&gt;actionAttr &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) {&lt;br/&gt;                    &lt;span style="color:#2b91af"&gt;ActionDescription &lt;/span&gt;actionDescription &lt;span style="color:red"&gt;=&lt;br/&gt;                        &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ActionDescription&lt;/span&gt;(m, actionAttr) { PageController &lt;span style="color:red"&gt;= &lt;/span&gt;controller };&lt;br/&gt;&lt;br/&gt;                    &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;PageUrlAttribute &lt;/span&gt;attr &lt;span style="color:blue"&gt;in &lt;/span&gt;pageUrlAttrs ) {&lt;br/&gt;                        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(attr&lt;span style="color:red"&gt;.&lt;/span&gt;Url) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;)&lt;br/&gt;                            s_PageActionDict&lt;span style="color:red"&gt;.&lt;/span&gt;Add(attr&lt;span style="color:red"&gt;.&lt;/span&gt;Url, actionDescription);&lt;br/&gt;                    }&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 用于Ajax调用的Action信息则采用延迟加载的方式。&lt;br/&gt;    &lt;/span&gt;}&lt;br/&gt;&lt;p&gt;从以上代码可以看出，在初始化时，MyMVC加载了全部的PageAction ，而AjaxAction却没有采用这种方式来实现，为什么呢？请继续阅读。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;从URL到Action的映射过程&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;前面我们看到了MyMVC的初始化过程，其实是在ReflectionHelper的构造函数中完成的。在这个初始化之后，MvcPageHandlerFactory调用ReflectionHelper.GetPageActionInvokeInfo(virtualPath)便可以得到要调用的Action的具体描述。我称这个过程为：&lt;b&gt;从URL到Action的映射&lt;/b&gt;。&lt;/p&gt;&lt;p&gt;GetPageActionInvokeInfo方法的实现代码如下：&lt;a href="javascript:void(0);" codeId="pre-GetPageActionInvokeInfo"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;根据一个页面请求路径，返回内部表示的调用信息。&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;/// &amp;lt;param name="url"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;InvokeInfo &lt;/span&gt;GetPageActionInvokeInfo(&lt;span style="color:blue"&gt;string &lt;/span&gt;url)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(url) )&lt;br/&gt;        &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"url"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;ActionDescription &lt;/span&gt;action &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( s_PageActionDict&lt;span style="color:red"&gt;.&lt;/span&gt;TryGetValue(url, &lt;span style="color:blue"&gt;out &lt;/span&gt;action) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;)&lt;br/&gt;        &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;InvokeInfo &lt;/span&gt;vkInfo &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;InvokeInfo&lt;/span&gt;();&lt;br/&gt;    vkInfo&lt;span style="color:red"&gt;.&lt;/span&gt;Controller &lt;span style="color:red"&gt;= &lt;/span&gt;action&lt;span style="color:red"&gt;.&lt;/span&gt;PageController;&lt;br/&gt;    vkInfo&lt;span style="color:red"&gt;.&lt;/span&gt;Action &lt;span style="color:red"&gt;= &lt;/span&gt;action;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( vkInfo&lt;span style="color:red"&gt;.&lt;/span&gt;Action&lt;span style="color:red"&gt;.&lt;/span&gt;MethodInfo&lt;span style="color:red"&gt;.&lt;/span&gt;IsStatic &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;)&lt;br/&gt;        vkInfo&lt;span style="color:red"&gt;.&lt;/span&gt;Instance &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Activator&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;CreateInstance(vkInfo&lt;span style="color:red"&gt;.&lt;/span&gt;Controller&lt;span style="color:red"&gt;.&lt;/span&gt;ControllerType);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;vkInfo;&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;在介绍这个映射过程之前，让我们再来回顾一下Action的声明代码：&lt;a href="javascript:void(0);" codeId="pre-CustomerController2"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CustomerController&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;PageUrl&lt;/span&gt;(Url &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/mvc/Customers"&lt;/span&gt;)]&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;PageUrl&lt;/span&gt;(Url &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/mvc/Customers.html"&lt;/span&gt;)]&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;PageUrl&lt;/span&gt;(Url &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/mvc/CustomerList.aspx"&lt;/span&gt;)]&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;PageUrl&lt;/span&gt;(Url &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/Pages/Customers.aspx"&lt;/span&gt;)]&lt;br/&gt;    &lt;span style="color:blue"&gt;public static object &lt;/span&gt;LoadModel(&lt;span style="color:blue"&gt;int&lt;/span&gt;&lt;span style="color:red"&gt;? &lt;/span&gt;page)&lt;br/&gt;    {&lt;br/&gt;&lt;p&gt;通过ReflectionHelper构造函数中所完成的初始化过程，每个Action的描述会根据[PageUrl]的数量而生成多个字典条目，因此，在GetPageActionInvokeInfo的实现过程中，也只是简单的查找了这个字典而已，就可以得到所需要的调用信息，从面完成映射的过程。整个过程可以用以下图形来表示：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022121093691.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;在上面的示例中，我使用了"/mvc/Customers"这种URL，显然它并不符合我在web.config中为MvcPageHandlerFactory注册时所指定的URL模式要求。那么，又该如何处理呢？&lt;/p&gt;&lt;p&gt;虽然这种URL虽然没有扩展名，但我仍然可以通过配置httpHandler的方式来解决，下面的配置就是我们需要的：&lt;a href="javascript:void(0);" codeId="pre-mvc-httpHandlers"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;add &lt;/span&gt;&lt;span style="color:red"&gt;path&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;/mvc/*&lt;/span&gt;" &lt;span style="color:red"&gt;verb&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*&lt;/span&gt;" &lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;MyMVC.MvcPageHandlerFactory, MyMVC&lt;/span&gt;" &lt;span style="color:red"&gt;validate&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;true&lt;/span&gt;" &lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;在介绍MvcPageHandlerFactory时，MyMVC提供了另一个方法TryGetHandler供外部使用。因此，在示例网站中，我还可以在Global.asax中调用这个方法来解决前面的那个问题：&lt;a href="javascript:void(0);" codeId="pre-Application_PostResolveRequestCache"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;protected void &lt;/span&gt;Application_PostResolveRequestCache(&lt;span style="color:blue"&gt;object &lt;/span&gt;sender, &lt;span style="color:#2b91af"&gt;EventArgs &lt;/span&gt;e)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;// 这里只是一个演示。&lt;br/&gt;    // 主要是将诸如：/mvc/Customers 这类请求映射到MyMVC框架的处理器&lt;br/&gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpApplication &lt;/span&gt;app &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;HttpApplication&lt;/span&gt;)sender;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( app&lt;span style="color:red"&gt;.&lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;FilePath&lt;span style="color:red"&gt;.&lt;/span&gt;StartsWith(&lt;span style="color:#a31515"&gt;"/mvc/"&lt;/span&gt;) ) {&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;myHandler &lt;span style="color:red"&gt;= &lt;/span&gt;MyMVC&lt;span style="color:red"&gt;.&lt;/span&gt;&lt;span style="color:#2b91af"&gt;MvcPageHandlerFactory&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;TryGetHandler(app&lt;span style="color:red"&gt;.&lt;/span&gt;Context);&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( myHandler &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            app&lt;span style="color:red"&gt;.&lt;/span&gt;Context&lt;span style="color:red"&gt;.&lt;/span&gt;RemapHandler(myHandler);&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;对于切换HttpHandler的操作，我有以下建议：&lt;br /&gt;1. 尽量放在HttpModule中去实现。因为可以通过修改配置来切换规则（启用或者禁止），所以会比较灵活。&lt;br /&gt;2. 如果可以通过HttpHandler映射能实现的，尽量首选HttpHandler映射方式。原因：更快，更标准。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;PageUrl的设计思想&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在前面的示例代码中，我为一个Action添加多个[PageUrl]，来标记这个Action可以处理多个URL，因此，一个Action能处理哪些URL是通过指定[PageUrl]来实现的。&lt;/p&gt;&lt;p&gt;为什么要叫【PageUrl】？&lt;br /&gt;我想或许有些人会有这个疑问。&lt;br /&gt;下面我就来回答这个问题，也可以让大家了解我设计PageUrl的原因：&lt;br /&gt;1. 我们请求一个URL通常是为了得到一个页面显示，因此可以认为一个URL最终可以表示成一个页面。&lt;br /&gt;2. 我也想过使用[Url]这种名称，但感觉太短了，而且Ajax请求也有URL，那么必须显式地加以区分。&lt;br /&gt;所以，我最终决定使用[PageUrl]这个名字。&lt;/p&gt;&lt;p&gt;在Ajax部分，我认为通常只需要完成获取数据以及处理提交数据的功能就可以了。因此，绝大多数情况下是不要需View的，而且，一个功能与一个URL对应，这样还可以简化问题。所以，在Ajax部分，我提倡在URL中直接指出要调用哪个Controller中的哪个Action。&lt;/p&gt;&lt;p&gt;在Page部分，事实上也需要一个Action，本来也是可以继续使用这种做法的，不过，我并没有这种做，理由如下：&lt;br /&gt;1. 我们创建View其实也是创建Page，使用Page的路径不是更好吗？而且WebForm的粉丝或许会更喜欢。&lt;br /&gt;2. 多URL的匹配功能。后面会有详细说明。&lt;/p&gt;&lt;p&gt;由于以上种种原因，我将[PageUrl]设计成与[Action]是独立关系，并且[PageUrl]可以多次指定的。&lt;/p&gt;&lt;p&gt;&lt;b&gt;注意：&lt;/b&gt;&lt;br /&gt;1. Url参数中指定的字符串，可以对应一个aspx页面。&lt;i&gt;也可以不对应aspx页面。&lt;/i&gt;&lt;br /&gt;2. Url参数中，不要包含QueryString，否则根本不能匹配。&lt;br /&gt;3. 如果您使用URL重写组件，那么此处应该是重写后的路径。&lt;/p&gt;&lt;p&gt;由于我在MvcPageHandlerFactory中使用ASP.NET框架传入的virtualPath并不包含查询参数，因此，把它理解成页面路径也是非常合适的。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;多URL的匹配功能&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;或许有些人认为多URL匹配一个Action是没有意义的，比如下面的这个Action会更符合常理：&lt;a href="javascript:void(0);" codeId="pre-CategoryController1"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CategoryController&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;PageUrl&lt;/span&gt;(Url &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/Pages/Categories.aspx"&lt;/span&gt;)]&lt;br/&gt;    &lt;span style="color:blue"&gt;public object &lt;/span&gt;LoadModel()&lt;br/&gt;    {&lt;br/&gt;&lt;p&gt;是的，通常情况下，一个Action处理一个URL也是较为常见。&lt;br /&gt;但仍然有二种情况需要这个功能。首先来看下面的示例：&lt;a href="javascript:void(0);" codeId="pre-TransferRequest"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;PageUrl&lt;/span&gt;(Url &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/Pages/AddOrder.aspx"&lt;/span&gt;)]&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;PageUrl&lt;/span&gt;(Url &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/Pages/CodeExplorer.aspx"&lt;/span&gt;)]&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;PageUrl&lt;/span&gt;(Url &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/Pages/Default.aspx"&lt;/span&gt;)]&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;PageUrl&lt;/span&gt;(Url &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/Pages/Orders.aspx"&lt;/span&gt;)]&lt;br/&gt;&lt;span style="color:blue"&gt;public object &lt;/span&gt;TransferRequest()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;// 这个Action要做的事较为简单，&lt;br/&gt;    // 将请求 "/Pages/Orders.aspx" 用实际的页面 "/Pages/StyleX/Orders.aspx" 来响应。&lt;br/&gt;    // 因为用户选择的风格不同，但URL地址是一样的，所以在这里切换。&lt;br/&gt;&lt;br/&gt;    // 当然这样的处理也只适合页面不需要Model的情况下。&lt;br/&gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;string &lt;/span&gt;filePath &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpContextHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;RequestFilePath;&lt;br/&gt;    &lt;span style="color:blue"&gt;int &lt;/span&gt;p &lt;span style="color:red"&gt;= &lt;/span&gt;filePath&lt;span style="color:red"&gt;.&lt;/span&gt;LastIndexOf(&lt;span style="color:#a31515"&gt;'/'&lt;/span&gt;);&lt;br/&gt;    &lt;span style="color:blue"&gt;string &lt;/span&gt;pageName &lt;span style="color:red"&gt;= &lt;/span&gt;filePath&lt;span style="color:red"&gt;.&lt;/span&gt;Substring(p &lt;span style="color:red"&gt;+ &lt;/span&gt;&lt;span style="color:purple"&gt;1&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;PageResult&lt;/span&gt;(&lt;span style="color:#2b91af"&gt;StyleHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetTargetPageUrl(pageName), &lt;span style="color:blue"&gt;null &lt;/span&gt;&lt;span style="color:green"&gt;/*model*/&lt;/span&gt;);&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;代码所涉及的4个页面在呈现时，由于并不需要数据，但为了能够实现多样式的支持，它们可以共用一个Action，因此这里只是切换一个View的路径而已。&lt;/p&gt;&lt;p&gt;理解上面那句话，可能还需要知道StyleHelper的实现代码：&lt;a href="javascript:void(0);" codeId="pre-StyleHelper"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public static class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;StyleHelper&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;public static readonly string &lt;/span&gt;STR_PageStyle &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"PageStyle"&lt;/span&gt;;&lt;br/&gt;    &lt;span style="color:blue"&gt;public static readonly string&lt;/span&gt;[] StyleArray &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new string&lt;/span&gt;[] { &lt;span style="color:#a31515"&gt;"Style1"&lt;/span&gt;, &lt;span style="color:#a31515"&gt;"Style2"&lt;/span&gt;, &lt;span style="color:#a31515"&gt;"Style3" &lt;/span&gt;};&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public static string &lt;/span&gt;PageStyle&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;get &lt;/span&gt;{ &lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CookieHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetCookieValue(STR_PageStyle) &lt;span style="color:red"&gt;?? &lt;/span&gt;StyleArray[&lt;span style="color:purple"&gt;1&lt;/span&gt;]; }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public static string &lt;/span&gt;GetTargetPageUrl(&lt;span style="color:blue"&gt;string &lt;/span&gt;pageName)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;return string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Format(&lt;span style="color:#a31515"&gt;"/Pages/{0}/" &lt;/span&gt;&lt;span style="color:red"&gt;+ &lt;/span&gt;pageName, PageStyle);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;示例网站的目录结构如下图：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022121095212.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;在示例网站中，由于三种风格的截然不同，尤其是在功能与HTML结构上就完全不同，因此根本不可能通过CSS或者SKIN的方式来解决，所以我为三种风格创建了三个目录，分别存放相应的页面文件。最终根据用户的选择（Cookie）来决定使用哪个目录下的页面来呈现。&lt;/p&gt;&lt;p&gt;用户设置风格的JS代码如下，&lt;a href="javascript:void(0);" codeId="pre-btnSetStyle"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;$(&lt;span style="color:blue"&gt;function&lt;/span&gt;(){&lt;br/&gt;    $(&lt;span style="color:#a31515"&gt;"a.btnSetStyle"&lt;/span&gt;).click(&lt;span style="color:blue"&gt;function&lt;/span&gt;(){&lt;br/&gt;        &lt;span style="color:blue"&gt;var &lt;/span&gt;style &lt;span style="color:red"&gt;= &lt;/span&gt;$(&lt;span style="color:blue"&gt;this&lt;/span&gt;).attr(&lt;span style="color:#a31515"&gt;"ps"&lt;/span&gt;);&lt;br/&gt;        &lt;br/&gt;        &lt;span style="color:green"&gt;// 其实写cookie也可以直接使用JS去写的。&lt;br/&gt;        &lt;/span&gt;$.ajax({&lt;br/&gt;            url&lt;span style="color:red"&gt;: &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/AjaxStyle/SetStyle.cspx"&lt;/span&gt;&lt;span style="color:red"&gt;,&lt;br/&gt;            &lt;/span&gt;data&lt;span style="color:red"&gt;: &lt;/span&gt;{style&lt;span style="color:red"&gt;: &lt;/span&gt;style}&lt;span style="color:red"&gt;,&lt;br/&gt;            &lt;/span&gt;success&lt;span style="color:red"&gt;: &lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt;(){&lt;br/&gt;                window.location &lt;span style="color:red"&gt;= &lt;/span&gt;window.location;&lt;br/&gt;            }&lt;br/&gt;        });&lt;br/&gt;        &lt;span style="color:blue"&gt;return false&lt;/span&gt;;&lt;br/&gt;    });&lt;br/&gt;});&lt;br/&gt;&lt;p&gt;服务端的C#代码如下：&lt;a href="javascript:void(0);" codeId="pre-AjaxStyle"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;AjaxStyle&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;    &lt;span style="color:blue"&gt;public void &lt;/span&gt;SetStyle(&lt;span style="color:blue"&gt;string &lt;/span&gt;style)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;Array&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IndexOf(&lt;span style="color:#2b91af"&gt;StyleHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;StyleArray, style) &lt;span style="color:red"&gt;&amp;gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;) {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;HttpCookie &lt;/span&gt;cookie &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpCookie&lt;/span&gt;(&lt;span style="color:#2b91af"&gt;StyleHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;STR_PageStyle, style);&lt;br/&gt;            cookie&lt;span style="color:red"&gt;.&lt;/span&gt;Expires &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DateTime&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Now&lt;span style="color:red"&gt;.&lt;/span&gt;AddYears(&lt;span style="color:purple"&gt;1&lt;/span&gt;);&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;CookieHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;AddCookie(cookie);&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;说明：CookieHelper是设计成支持单元测试的，所以不要怀疑这里的代码不符合MVC，后面会专门谈它。&lt;/p&gt;&lt;p&gt;所以，在这种情况下，多个URL映射到一个Action是有意义的。这是【多URL的匹配功能】的第一个用途。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;解决老的URL兼容问题&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在一个网站的成长过程中，一般会有重构的过程。在重构过程中，或许会删除以前的某些页面，或许调整URL格式。然而，用户也可能会收藏这个网站的链接，但由于页面重构了，老的链接可能会因此而失效，造成404错误。此时就要解决URL的兼容问题。&lt;/p&gt;&lt;p&gt;在ASP.NET中，我们可以在web.config配置urlMappings节点来做这样的映射转换。还有另一种方法是，创建一个HttpModule专门判断是否在请求一些老的URL，如果是，则重定向到新的页面。总之，不管使用哪种方法，都需要为每个传入请求检查URL是否是老格式的URL，这个过程会根据一个列表来逐一检查，不过，可惜的是：绝大部分请求可能都是新的URL格式，而那些兼容方案无疑会浪费很多的CPU资源。&lt;/p&gt;&lt;p&gt;在MyMVC中，可以简单地处理这个问题，就像下面的这个示例一样：&lt;a href="javascript:void(0);" codeId="pre-CustomerController4"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CustomerController&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;PageUrl&lt;/span&gt;(Url &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/mvc/Customers"&lt;/span&gt;)]&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;PageUrl&lt;/span&gt;(Url &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/mvc/Customers.html"&lt;/span&gt;)]&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;PageUrl&lt;/span&gt;(Url &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/mvc/CustomerList.aspx"&lt;/span&gt;)]&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;PageUrl&lt;/span&gt;(Url &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/Pages/Customers.aspx"&lt;/span&gt;)]&lt;br/&gt;    &lt;span style="color:blue"&gt;public static object &lt;/span&gt;LoadModel(&lt;span style="color:blue"&gt;int&lt;/span&gt;&lt;span style="color:red"&gt;? &lt;/span&gt;page)&lt;br/&gt;    {&lt;br/&gt;&lt;p&gt;这个“客户管理”页面可能经过了多次重构，没关系，只要把各个版本的地址用[PageUrl]标识出来就可以了，完全不用前面所说的兼容方案，因此，在URL的兼容处理上没有任何负担，也不会影响性能。&lt;/p&gt;&lt;p&gt;说明：[PageUrl]的顺序并不重要，可以随意调整。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;对身份认证的支持&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;MyMVC也支持一些基本的身份认证，可以通过在Action方法中添加[Authorize]修饰属性来指示。&lt;br /&gt;AuthorizeAttribute的实现代码如下：&lt;a href="javascript:void(0);" codeId="pre-AuthorizeAttribute"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;用于验证用户身份的修饰属性&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;[&lt;span style="color:#2b91af"&gt;AttributeUsage&lt;/span&gt;(&lt;span style="color:#2b91af"&gt;AttributeTargets&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Class &lt;span style="color:red"&gt;| &lt;/span&gt;&lt;span style="color:#2b91af"&gt;AttributeTargets&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Method, AllowMultiple &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;false&lt;/span&gt;, Inherited &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;false&lt;/span&gt;)]&lt;br/&gt;    &lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;AuthorizeAttribute &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;Attribute&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color:blue"&gt;private string &lt;/span&gt;_user;&lt;br/&gt;        &lt;span style="color:blue"&gt;private string&lt;/span&gt;[] _users;&lt;br/&gt;        &lt;span style="color:blue"&gt;private string &lt;/span&gt;_role;&lt;br/&gt;        &lt;span style="color:blue"&gt;private string&lt;/span&gt;[] _roles;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;private string&lt;/span&gt;[] SplitString(&lt;span style="color:blue"&gt;string &lt;/span&gt;value)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(value) )&lt;br/&gt;                &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color:blue"&gt;else&lt;br/&gt;                return &lt;/span&gt;(&lt;span style="color:blue"&gt;from &lt;/span&gt;s &lt;span style="color:blue"&gt;in &lt;/span&gt;value&lt;span style="color:red"&gt;.&lt;/span&gt;Split(&lt;span style="color:#a31515"&gt;','&lt;/span&gt;)&lt;br/&gt;                        &lt;span style="color:blue"&gt;let &lt;/span&gt;u &lt;span style="color:red"&gt;= &lt;/span&gt;s&lt;span style="color:red"&gt;.&lt;/span&gt;Trim()&lt;br/&gt;                        &lt;span style="color:blue"&gt;where &lt;/span&gt;u&lt;span style="color:red"&gt;.&lt;/span&gt;Length &lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;br/&gt;                        &lt;/span&gt;&lt;span style="color:blue"&gt;select &lt;/span&gt;u)&lt;span style="color:red"&gt;.&lt;/span&gt;ToArray();&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// &lt;/span&gt;&lt;span style="color:green"&gt;允许访问的用户列表，用逗号分隔。&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:blue"&gt;public string &lt;/span&gt;Users&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;get &lt;/span&gt;{ &lt;span style="color:blue"&gt;return &lt;/span&gt;_user; }&lt;br/&gt;            &lt;span style="color:blue"&gt;set &lt;/span&gt;{ _user &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;value&lt;/span&gt;; _users &lt;span style="color:red"&gt;= &lt;/span&gt;SplitString(&lt;span style="color:blue"&gt;value&lt;/span&gt;); }&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// &lt;/span&gt;&lt;span style="color:green"&gt;允许访问的角色列表，用逗号分隔。&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:blue"&gt;public string &lt;/span&gt;Roles&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;get &lt;/span&gt;{ &lt;span style="color:blue"&gt;return &lt;/span&gt;_role; }&lt;br/&gt;            &lt;span style="color:blue"&gt;set &lt;/span&gt;{ _role &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;value&lt;/span&gt;; _roles &lt;span style="color:red"&gt;= &lt;/span&gt;SplitString(&lt;span style="color:blue"&gt;value&lt;/span&gt;); }&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;internal bool &lt;/span&gt;AuthenticateRequest(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( context&lt;span style="color:red"&gt;.&lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;IsAuthenticated &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;)&lt;br/&gt;                &lt;span style="color:blue"&gt;return false&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( _users &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;&lt;span style="color:red"&gt;&amp;amp;&amp;amp; &lt;br/&gt;                &lt;/span&gt;_users&lt;span style="color:red"&gt;.&lt;/span&gt;Contains(context&lt;span style="color:red"&gt;.&lt;/span&gt;User&lt;span style="color:red"&gt;.&lt;/span&gt;Identity&lt;span style="color:red"&gt;.&lt;/span&gt;Name, &lt;span style="color:#2b91af"&gt;StringComparer&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;OrdinalIgnoreCase) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;)&lt;br/&gt;                &lt;span style="color:blue"&gt;return false&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( _roles &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;&lt;span style="color:red"&gt;&amp;amp;&amp;amp; &lt;/span&gt;_roles&lt;span style="color:red"&gt;.&lt;/span&gt;Any(context&lt;span style="color:red"&gt;.&lt;/span&gt;User&lt;span style="color:red"&gt;.&lt;/span&gt;IsInRole) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;)&lt;br/&gt;                &lt;span style="color:blue"&gt;return false&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:blue"&gt;return true&lt;/span&gt;;&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;p&gt;认证检查发生在调用Action之前，代码如下：&lt;a href="javascript:void(0);" codeId="pre-ExecuteAction"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal static void &lt;/span&gt;ExecuteAction(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context, &lt;span style="color:#2b91af"&gt;InvokeInfo &lt;/span&gt;vkInfo)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( context &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;        &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"context"&lt;/span&gt;);&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( vkInfo &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;        &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"vkInfo"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 验证请求是否允许访问（身份验证）&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#2b91af"&gt;AuthorizeAttribute &lt;/span&gt;authorize &lt;span style="color:red"&gt;= &lt;/span&gt;vkInfo&lt;span style="color:red"&gt;.&lt;/span&gt;GetAuthorize();&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( authorize &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( authorize&lt;span style="color:red"&gt;.&lt;/span&gt;AuthenticateRequest(context) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;ExceptionHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Throw403Exception(context);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 调用方法&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;object &lt;/span&gt;result &lt;span style="color:red"&gt;= &lt;/span&gt;ExecuteActionInternal(context, vkInfo);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 设置OutputCache&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#2b91af"&gt;OutputCacheAttribute &lt;/span&gt;outputCache &lt;span style="color:red"&gt;= &lt;/span&gt;vkInfo&lt;span style="color:red"&gt;.&lt;/span&gt;GetOutputCacheSetting();&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( outputCache &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;        outputCache&lt;span style="color:red"&gt;.&lt;/span&gt;SetResponseCache(context);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 处理方法的返回结果&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IActionResult &lt;/span&gt;executeResult &lt;span style="color:red"&gt;= &lt;/span&gt;result &lt;span style="color:blue"&gt;as &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IActionResult&lt;/span&gt;;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( executeResult &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) {&lt;br/&gt;        executeResult&lt;span style="color:red"&gt;.&lt;/span&gt;Ouput(context);&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;else &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( result &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) {&lt;br/&gt;            &lt;span style="color:green"&gt;// 普通类型结果&lt;br/&gt;            &lt;/span&gt;context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;ContentType &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"text/plain"&lt;/span&gt;;&lt;br/&gt;            context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Write(result&lt;span style="color:red"&gt;.&lt;/span&gt;ToString());&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;下面的示例代码演示了它的用法：&lt;a href="javascript:void(0);" codeId="pre-Authorize-demo"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Authorize&lt;/span&gt;(Users&lt;span style="color:red"&gt;=&lt;/span&gt;&lt;span style="color:#a31515"&gt;"fish"&lt;/span&gt;)]&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;PageUrl&lt;/span&gt;(Url &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/Pages/Demo/TestAuthorize/Fish.aspx"&lt;/span&gt;)]&lt;br/&gt;&lt;span style="color:blue"&gt;public object &lt;/span&gt;ShowFishPage()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;// 仅当当前用户是 fish 时，才允许访问这个PageAction&lt;br/&gt;&lt;br/&gt;    // 注意：第一参数为null，表示使用当前地址。&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;PageResult&lt;/span&gt;(&lt;span style="color:blue"&gt;null&lt;/span&gt;, &lt;span style="color:blue"&gt;null&lt;/span&gt;);&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Authorize&lt;/span&gt;]&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;PageUrl&lt;/span&gt;(Url &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/Pages/Demo/TestAuthorize/LoginUser.aspx"&lt;/span&gt;)]&lt;br/&gt;&lt;span style="color:blue"&gt;public object &lt;/span&gt;ShowLoginUserPage()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;// 仅当当前用户是已登录用户时，才允许访问这个PageAction&lt;br/&gt;&lt;br/&gt;    // 注意：第一参数为null，表示使用当前地址。&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;PageResult&lt;/span&gt;(&lt;span style="color:blue"&gt;null&lt;/span&gt;, &lt;span style="color:blue"&gt;null&lt;/span&gt;);&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&lt;b&gt;注意：&lt;/b&gt;&lt;br /&gt;1. 如果一个Action没有使用[Authorize]，则表示允许任意用户访问（包括未登录用户）。&lt;br /&gt;2. [Authorize]对于AjaxAction仍然有效。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;View的设计方式&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在MyMVC中，View采用了ASP.NET Page，不过，我并不建议使用CodeFile文件。不使用CodeFile文件，我想这是很多喜欢WebForm的人不能接受的。他们更愿意在CodeFile文件中获取数据，绑定数据，响应事件，处理用户的提交数据。也正是由于这个原因，才会让其它人认为WebForm是一种对单元测试极差的编程模型。&lt;/p&gt;&lt;p&gt;这里我要表达一下我的观点：代码是否可支持单元测试，&lt;b&gt;这其中最主要的原因还是开发人员自身造成的，框架的选择只是起到促进或是部分限制的作用。&lt;/b&gt;就算让一些人使用ASP.NET MVC，他们所编写的代码未必就能支持单元测试，有些人实在太依赖于HttpContext.Current，甚至在ASP.NET MVC中还在写这种代码。&lt;/p&gt;&lt;p&gt;好吧，还是回到Page的设计这个话题上来。MyMVC所提倡的做法与ASP.NET MVC的做法类似，那就是直接在Page中采用内联的方式显示数据，而不是在CodeFile中绑定数据。许多人一看到ASP.NET MVC的这种内联写法，感觉又回到了ASP时代，认为是在倒退，其实这只是表面现象。表面的背后是：&lt;b&gt;代码远离了UI。&lt;/b&gt;，也可以理解成：&lt;b&gt;逻辑远离了UI。&lt;/b&gt;这也是正是ASP.NET MVC一直所提倡的：&lt;b&gt;分离关注点。&lt;/b&gt;在新的开发理念中，原来的Page分解成View和Controller，在实现它们时，只关注自身那一部分就可以了，因此，如果单看Page时，可能是会有前面所说的那种感觉。另一方面，由于代码远离了UI，或许可以有更多的机会重构它们，使它们的重用性更高。&lt;/p&gt;&lt;p&gt;下面还是来回顾一下MyMVC中Page的代码：&lt;a href="javascript:void(0);" codeId="pre-view-page"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;@ &lt;/span&gt;&lt;span style="color:#a31515"&gt;Page &lt;/span&gt;&lt;span style="color:red"&gt;Title&lt;/span&gt;&lt;span style="color:blue"&gt;="客户管理" &lt;/span&gt;&lt;span style="color:red"&gt;Language&lt;/span&gt;&lt;span style="color:blue"&gt;="C#" &lt;/span&gt;&lt;span style="color:red"&gt;MasterPageFile&lt;/span&gt;&lt;span style="color:blue"&gt;="MasterPage.master" &lt;br/&gt;        &lt;/span&gt;&lt;span style="color:red"&gt;Inherits&lt;/span&gt;&lt;span style="color:blue"&gt;="MyPageView&amp;lt;CustomersPageModel&amp;gt;" &lt;/span&gt;&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Content &lt;/span&gt;&lt;span style="color:red"&gt;ID&lt;/span&gt;&lt;span style="color:blue"&gt;="Content1" &lt;/span&gt;&lt;span style="color:red"&gt;ContentPlaceHolderID&lt;/span&gt;&lt;span style="color:blue"&gt;="head" &lt;/span&gt;&lt;span style="color:red"&gt;Runat&lt;/span&gt;&lt;span style="color:blue"&gt;="Server"&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Content&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Content &lt;/span&gt;&lt;span style="color:red"&gt;ID&lt;/span&gt;&lt;span style="color:blue"&gt;="Content2" &lt;/span&gt;&lt;span style="color:red"&gt;ContentPlaceHolderID&lt;/span&gt;&lt;span style="color:blue"&gt;="ContentPlaceHolder1" &lt;/span&gt;&lt;span style="color:red"&gt;Runat&lt;/span&gt;&lt;span style="color:blue"&gt;="Server"&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;ul &lt;/span&gt;&lt;span style="color:red"&gt;class&lt;/span&gt;&lt;span style="color:blue"&gt;="itemList"&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;Customer &lt;/span&gt;customer &lt;span style="color:blue"&gt;in &lt;/span&gt;Model&lt;span style="color:red"&gt;.&lt;/span&gt;List ) { &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;li&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;table &lt;/span&gt;&lt;span style="color:red"&gt;class&lt;/span&gt;&lt;span style="color:blue"&gt;="GridView" &lt;/span&gt;&lt;span style="color:red"&gt;cellspacing&lt;/span&gt;&lt;span style="color:blue"&gt;="0" &lt;/span&gt;&lt;span style="color:red"&gt;cellpadding&lt;/span&gt;&lt;span style="color:blue"&gt;="4" &lt;/span&gt;&lt;span style="color:red"&gt;border&lt;/span&gt;&lt;span style="color:blue"&gt;="0" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;border-collapse&lt;/span&gt;:&lt;span style="color:blue"&gt;collapse&lt;/span&gt;;&lt;span style="color:blue"&gt;"&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;customer&lt;span style="color:red"&gt;.&lt;/span&gt;CustomerName&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode()&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;customer&lt;span style="color:red"&gt;.&lt;/span&gt;ContactName&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;customer&lt;span style="color:red"&gt;.&lt;/span&gt;Address&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;customer&lt;span style="color:red"&gt;.&lt;/span&gt;PostalCode&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;customer&lt;span style="color:red"&gt;.&lt;/span&gt;Tel&lt;span style="color:red"&gt;.&lt;/span&gt;HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;table&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;li&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;ul&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;Model&lt;span style="color:red"&gt;.&lt;/span&gt;PagingInfo&lt;span style="color:red"&gt;.&lt;/span&gt;PaginationBar()&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;asp&lt;/span&gt;&lt;span style="color:blue"&gt;:&lt;/span&gt;&lt;span style="color:#a31515"&gt;Content&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;此时，对于呈现所需的数据可以直接从Model对象中获取，但要求在Page指令中指出Model的类型，这样还可以有智能提示的优点。如果页面需要显示数据，请务必从MyPageView&amp;lt;&amp;gt;继承，它的实现代码如下：&lt;a href="javascript:void(0);" codeId="pre-MyPageView"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;页面视图的基类&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;/// &amp;lt;typeparam name="TModel"&amp;gt;&lt;/span&gt;&lt;span style="color:green"&gt;传递给页面呈现时所需的数据实体对象类型&lt;/span&gt;&lt;span style="color:gray"&gt;&amp;lt;/typeparam&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyPageView&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;TModel&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;MyBasePage&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;用于页面呈现时所需的数据实体对象&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;public &lt;/span&gt;TModel Model { &lt;span style="color:blue"&gt;get&lt;/span&gt;; &lt;span style="color:blue"&gt;set&lt;/span&gt;; }&lt;br/&gt;    &lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;其实也就是一个简单的类型，包含了Model这个属性而已。至于MyBasePage的实现代码，我们可以忽略它，它是直接从System.Web.UI.Page继承的。&lt;/p&gt;&lt;p&gt;再来一段用户控件的代码：&lt;a href="javascript:void(0);" codeId="pre-uc-demo"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;@ &lt;/span&gt;&lt;span style="color:#a31515"&gt;Control &lt;/span&gt;&lt;span style="color:red"&gt;Language&lt;/span&gt;&lt;span style="color:blue"&gt;="C#" &lt;/span&gt;&lt;span style="color:red"&gt;Inherits&lt;/span&gt;&lt;span style="color:blue"&gt;="MyUserControlView&amp;lt;Customer&amp;gt;" &lt;/span&gt;&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;table &lt;/span&gt;&lt;span style="color:red"&gt;cellpadding&lt;/span&gt;&lt;span style="color:blue"&gt;="4" &lt;/span&gt;&lt;span style="color:red"&gt;border&lt;/span&gt;&lt;span style="color:blue"&gt;="0px"&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;: &lt;span style="color:blue"&gt;80px"&amp;gt;&lt;/span&gt;客户名称&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="CustomerName" &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text" &lt;/span&gt;&lt;span style="color:red"&gt;maxlength&lt;/span&gt;&lt;span style="color:blue"&gt;="50" &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="txtCustomerName" &lt;br/&gt;        &lt;/span&gt;&lt;span style="color:red"&gt;class&lt;/span&gt;&lt;span style="color:blue"&gt;="myTextbox w400" &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;= Model.CustomerName.HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;" /&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;联系人&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="ContactName" &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text" &lt;/span&gt;&lt;span style="color:red"&gt;maxlength&lt;/span&gt;&lt;span style="color:blue"&gt;="50" &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="txtContactName" &lt;br/&gt;        &lt;/span&gt;&lt;span style="color:red"&gt;class&lt;/span&gt;&lt;span style="color:blue"&gt;="myTextbox w400"    &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;= Model.ContactName.HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;" /&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;地址&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="Address" &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text" &lt;/span&gt;&lt;span style="color:red"&gt;maxlength&lt;/span&gt;&lt;span style="color:blue"&gt;="50" &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="txtAddress" &lt;br/&gt;        &lt;/span&gt;&lt;span style="color:red"&gt;class&lt;/span&gt;&lt;span style="color:blue"&gt;="myTextbox w400"    &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;= Model.Address.HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;" /&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;邮编&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="PostalCode" &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text" &lt;/span&gt;&lt;span style="color:red"&gt;maxlength&lt;/span&gt;&lt;span style="color:blue"&gt;="10" &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="txtPostalCode" &lt;br/&gt;        &lt;/span&gt;&lt;span style="color:red"&gt;class&lt;/span&gt;&lt;span style="color:blue"&gt;="myTextbox w400" &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;= Model.PostalCode.HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;" /&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;电话&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="Tel" &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text" &lt;/span&gt;&lt;span style="color:red"&gt;maxlength&lt;/span&gt;&lt;span style="color:blue"&gt;="50" &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="txtTel" &lt;br/&gt;        &lt;/span&gt;&lt;span style="color:red"&gt;class&lt;/span&gt;&lt;span style="color:blue"&gt;="myTextbox w400"    &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;= Model.Tel.HtmlEncode() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;" /&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;td&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;tr&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;table&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;基本上，与Page的开发方式差不多，只是基类换成了MyUserControlView&amp;lt;&amp;gt;而已。&lt;/p&gt;&lt;p&gt;在这里我认为要补充一点的是：&lt;br /&gt;与ASP.NET MVC不同，MyMVC不提供任何HtmlHelper。&lt;br /&gt;我认为HtmlHelper与MVC思想完全没有关系，因此不提供这些方法。&lt;br /&gt;另一方面，很多人希望更好地控制HTML代码，因此就更没必要提供这些方法了。&lt;br /&gt;如果您认为需要一些必要的HtmlHelper方法，那么可以实现自己喜欢的HtmlHelper类库。&lt;/p&gt;&lt;p&gt;最后我想说的是：页面继承泛型类，还需要一些额外的处理。比如下面的代码：&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:red"&gt;Inherits&lt;/span&gt;&lt;span style="color:blue"&gt;="MyPageView&amp;lt;CustomersPageModel&amp;gt;"&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;要让这种设置能够通过编译，需要在web.config中做如下配置：&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;pages  &lt;/span&gt;&lt;span style="color:red"&gt;pageParserFilterType&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;MyMVC.ViewTypeParserFilter, MyMVC&lt;/span&gt;"  &lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;ViewTypeParserFilter的实现代码较长，我就不在此贴出了，可以从本文结尾处下载。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Controller,Action的设计方式&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在MyMVC中，Action分为二种：AjaxAction和PageAction。&lt;br /&gt;PageAction与AjaxActioin在方法的定义上并没有什么差异，只要是个public方法就可以了。&lt;br /&gt;不过，PageAction与AjaxAction不同点在于：&lt;br /&gt;1. Controller的容器名称不同，PageAction要求Controller的名字必须以Controller结尾。&lt;br /&gt;2. 必须有一个有效的[PageUrl]的修饰属性指出可以处理的URL&lt;br /&gt;3. Action的名字与URL无关，可以随意取名。&lt;/p&gt;&lt;p&gt;在MyMVC中，2种Action还有另一特点是：不区分GET,POST 。&lt;br /&gt;原因是：我喜欢用JQuery，用它实现客户端的Ajax时，GET, POST，只是一个参数的差别而已。另一方面，对于HTML表单来说，GET, POST也只是一个参数的差别，&lt;b&gt;大部分&lt;/b&gt;表单也可以通过GET方式来提交，只要您愿意。所以，我想，既然客户端可以这样灵活地切换，服务端也就没有必要再去做那样限制。或许有些人认为区分二者会更安全，但我认为它们对安全性基本上不构成影响。反而，如果服务端忽略它们，只会让客户端更容易调用。&lt;/p&gt;&lt;p&gt;还有一种情况下可能需要区分二者：请求与提交是同一个地址。&lt;br /&gt;这应该可以算得上是我在上篇总结的【以服务端为中心的网站】的开发方式。&lt;br /&gt;事实上，在使用MyMVC的项目中，&amp;lt;form&amp;gt;标签应该需要手写，可能更多的时候会提交到另一个地址，&lt;br /&gt;因为，我更建议使用Ajax方式提交数据。&lt;br /&gt;所以，最终我决定：&lt;b&gt;MyMVC的Action不区分GET, POST.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;在设计MyMVC时，我一直没有忘记将View和Controller的分离，而且对于Controller，只有名字上的约束，Action的约束也较少，因此，我们在实现Action时，完全可以把它们独立到【类库项目】中，&lt;br /&gt;就像示例项目这样：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012022121100742.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;这样做的好处是：测试Actioin会更容易。&lt;br /&gt;此时网站可能只是一堆aspx，js, css文件。我一直期待能将aspx也交给美工去维护，这样设计但愿能让可能性更大一些。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;输出HTML的方式&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;MyMVC提供二种方式在Action中返回HTML，分别是返回PageResult或者UcResult，表示需要呈现一个页面或者一个用户控件。当在Action返回这二种结果时，Action的部分就执行完毕了。剩下的处理是在MyMVC框架中进行的，MyMVC框架会对这二种结果，以IActionResult接口的方式调用Ouput方法输出结果给客户端。&lt;br /&gt;PageResult和UcResult的实现代码如下：&lt;a href="javascript:void(0);" codeId="pre-IActionResult"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public interface &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IActionResult&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;void &lt;/span&gt;Ouput(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context);&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;表示一个用户控件结果（用户控件将由框架执行）&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public sealed class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;UcResult &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IActionResult&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;VirtualPath { &lt;span style="color:blue"&gt;get&lt;/span&gt;; &lt;span style="color:blue"&gt;private set&lt;/span&gt;; }&lt;br/&gt;    &lt;span style="color:blue"&gt;public object &lt;/span&gt;Model { &lt;span style="color:blue"&gt;get&lt;/span&gt;; &lt;span style="color:blue"&gt;private set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public &lt;/span&gt;UcResult(&lt;span style="color:blue"&gt;string &lt;/span&gt;virtualPath, &lt;span style="color:blue"&gt;object &lt;/span&gt;model)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(virtualPath) )&lt;br/&gt;            &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"virtualPath"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;VirtualPath &lt;span style="color:red"&gt;= &lt;/span&gt;virtualPath;&lt;br/&gt;        &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Model &lt;span style="color:red"&gt;= &lt;/span&gt;model;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;void &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IActionResult&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Ouput(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context)&lt;br/&gt;    {&lt;br/&gt;        context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;ContentType &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"text/html"&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color:blue"&gt;string &lt;/span&gt;html &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;UcExecutor&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Render(VirtualPath, Model);&lt;br/&gt;        context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Write(html);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;表示一个页面结果（页面将由框架执行）&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public sealed class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;PageResult &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IActionResult&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;VirtualPath { &lt;span style="color:blue"&gt;get&lt;/span&gt;; &lt;span style="color:blue"&gt;private set&lt;/span&gt;; }&lt;br/&gt;    &lt;span style="color:blue"&gt;public object &lt;/span&gt;Model { &lt;span style="color:blue"&gt;get&lt;/span&gt;; &lt;span style="color:blue"&gt;private set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public &lt;/span&gt;PageResult(&lt;span style="color:blue"&gt;string &lt;/span&gt;virtualPath, &lt;span style="color:blue"&gt;object &lt;/span&gt;model)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;VirtualPath &lt;span style="color:red"&gt;= &lt;/span&gt;virtualPath;&lt;br/&gt;        &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Model &lt;span style="color:red"&gt;= &lt;/span&gt;model;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;void &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IActionResult&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Ouput(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;VirtualPath) )&lt;br/&gt;            &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;VirtualPath &lt;span style="color:red"&gt;= &lt;/span&gt;context&lt;span style="color:red"&gt;.&lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;FilePath;&lt;br/&gt;&lt;br/&gt;        context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;ContentType &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"text/html"&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color:blue"&gt;string &lt;/span&gt;html &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;PageExecutor&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Render(context, VirtualPath, Model);&lt;br/&gt;        context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Write(html);&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;这二个类型的使用方式是一样的，都需要提供二个参数，第一个参数表示页面或者用户控件的存放路径，第二个参数表示给页面或者用户控件所需的显示数据。比如下面这个示例：&lt;a href="javascript:void(0);" codeId="pre-ShowCustomerPicker"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public object &lt;/span&gt;ShowCustomerPicker(&lt;span style="color:blue"&gt;string &lt;/span&gt;searchWord, &lt;span style="color:blue"&gt;int&lt;/span&gt;&lt;span style="color:red"&gt;? &lt;/span&gt;page)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;CustomerSearchInfo &lt;/span&gt;info &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CustomerSearchInfo&lt;/span&gt;();&lt;br/&gt;    info&lt;span style="color:red"&gt;.&lt;/span&gt;SearchWord &lt;span style="color:red"&gt;= &lt;/span&gt;searchWord &lt;span style="color:red"&gt;?? &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Empty;&lt;br/&gt;    info&lt;span style="color:red"&gt;.&lt;/span&gt;PageIndex &lt;span style="color:red"&gt;= &lt;/span&gt;page&lt;span style="color:red"&gt;.&lt;/span&gt;HasValue &lt;span style="color:red"&gt;? &lt;/span&gt;page&lt;span style="color:red"&gt;.&lt;/span&gt;Value &lt;span style="color:red"&gt;- &lt;/span&gt;&lt;span style="color:purple"&gt;1 &lt;/span&gt;: &lt;span style="color:purple"&gt;0&lt;/span&gt;;&lt;br/&gt;    info&lt;span style="color:red"&gt;.&lt;/span&gt;PageSize &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;AppHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;DefaultPageSize;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;CustomerPickerModel &lt;/span&gt;data &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CustomerPickerModel&lt;/span&gt;();&lt;br/&gt;    data&lt;span style="color:red"&gt;.&lt;/span&gt;SearchInfo &lt;span style="color:red"&gt;= &lt;/span&gt;info;&lt;br/&gt;    data&lt;span style="color:red"&gt;.&lt;/span&gt;List &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BllFactory&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetCustomerBLL()&lt;span style="color:red"&gt;.&lt;/span&gt;GetList(info);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;UcResult&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"/Controls/Style1/CustomerPicker.ascx"&lt;/span&gt;, data);&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;设计这二类结果，我的本意是：&lt;br /&gt;1. UcResult给Ajax请求使用，因为有可能会要求服务端输出一段HTML&lt;br /&gt;2. PageResult用于整页面的响应。&lt;/p&gt;&lt;p&gt;在MyMVC中，&lt;b&gt;执行页面或者用户控件，需要指出页面或者用户控件的路径，而不是采用什么约定关系。&lt;/b&gt;&lt;br /&gt;我认为约定会造成名字耦合，约定也会影响限制灵活，因此，必须明确指定（允许为null）。&lt;/p&gt;&lt;p&gt;PageResult多用于PageAction，而PageAction又有[PageUrl]来指示可以处理哪些URL，虽然一个PageAction可以处理多个URL，但通常情况下，还是以一个PageAction处理一个URL的情况居多。此时，MyMVC允许在返回PageResult时，&lt;b&gt;第一个参数可以设置为null，表示使用当前请求地址。&lt;/b&gt;如果此时当前请求地址有一个aspx页面与之对应，自然就会方便很多。可以参考下面的示例：&lt;a href="javascript:void(0);" codeId="pre-Authorize-demo2"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Authorize&lt;/span&gt;(Users&lt;span style="color:red"&gt;=&lt;/span&gt;&lt;span style="color:#a31515"&gt;"fish"&lt;/span&gt;)]&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;PageUrl&lt;/span&gt;(Url &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/Pages/Demo/TestAuthorize/Fish.aspx"&lt;/span&gt;)]&lt;br/&gt;&lt;span style="color:blue"&gt;public object &lt;/span&gt;ShowFishPage()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;// 仅当当前用户是 fish 时，才允许访问这个PageAction&lt;br/&gt;&lt;br/&gt;    // 注意：第一参数为null，表示使用当前地址。&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;PageResult&lt;/span&gt;(&lt;span style="color:blue"&gt;null&lt;/span&gt;, &lt;span style="color:blue"&gt;null&lt;/span&gt;);&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;在MyMVC框架中，PageResult最终会调用PageExecutor.Render()来获取页面的生成代码，具体过程如下：&lt;a href="javascript:void(0);" codeId="pre-PageExecutor"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public static class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;PageExecutor&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;internal static readonly &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Type &lt;/span&gt;MyPageViewOpenType &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;typeof&lt;/span&gt;(&lt;span style="color:#2b91af"&gt;MyPageView&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&amp;gt;&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;private static void &lt;/span&gt;SetPageModel(&lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;handler, &lt;span style="color:blue"&gt;object &lt;/span&gt;model)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( handler &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;return&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( model &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) {&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;Type &lt;/span&gt;handlerType &lt;span style="color:red"&gt;= &lt;/span&gt;handler&lt;span style="color:red"&gt;.&lt;/span&gt;GetType()&lt;span style="color:red"&gt;.&lt;/span&gt;BaseType;&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;Type &lt;/span&gt;viewType &lt;span style="color:red"&gt;= &lt;/span&gt;MyPageViewOpenType&lt;span style="color:red"&gt;.&lt;/span&gt;MakeGenericType(model&lt;span style="color:red"&gt;.&lt;/span&gt;GetType());&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:green"&gt;// 检查类型是否匹配&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( handlerType &lt;span style="color:red"&gt;== &lt;/span&gt;viewType &lt;span style="color:red"&gt;|| &lt;/span&gt;handlerType&lt;span style="color:red"&gt;.&lt;/span&gt;IsSubclassOf(viewType) ) {&lt;br/&gt;                &lt;span style="color:#2b91af"&gt;DataMember &lt;/span&gt;member &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ReflectionHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetMemberByName(viewType, &lt;span style="color:#a31515"&gt;"Model"&lt;/span&gt;, &lt;span style="color:blue"&gt;true&lt;/span&gt;);&lt;br/&gt;                member&lt;span style="color:red"&gt;.&lt;/span&gt;SetValue(handler, model);&lt;br/&gt;            }&lt;br/&gt;            &lt;span style="color:blue"&gt;else&lt;br/&gt;                throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"参数model的类型与页面的参数类型不一致。"&lt;/span&gt;);&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;用指定的页面路径以及视图数据呈现结果，最后返回生成的HTML代码。&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;页面应从MyPageView&amp;amp;lt;T&amp;amp;gt;继承&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    /// &amp;lt;param name="context"&amp;gt;&lt;/span&gt;&lt;span style="color:green"&gt;HttpContext对象&lt;/span&gt;&lt;span style="color:gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;    /// &amp;lt;param name="pageVirtualPath"&amp;gt;&lt;/span&gt;&lt;span style="color:green"&gt;Page的虚拟路径&lt;/span&gt;&lt;span style="color:gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;    /// &amp;lt;param name="model"&amp;gt;&lt;/span&gt;&lt;span style="color:green"&gt;视图数据&lt;/span&gt;&lt;span style="color:gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;    /// &amp;lt;returns&amp;gt;&lt;/span&gt;&lt;span style="color:green"&gt;生成的HTML代码&lt;/span&gt;&lt;span style="color:gray"&gt;&amp;lt;/returns&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;public static string &lt;/span&gt;Render(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context, &lt;span style="color:blue"&gt;string &lt;/span&gt;pageVirtualPath, &lt;span style="color:blue"&gt;object &lt;/span&gt;model)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( context &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"context"&lt;/span&gt;);&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(pageVirtualPath) )&lt;br/&gt;            &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"pageVirtualPath"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;Page &lt;/span&gt;handler &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BuildManager&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;CreateInstanceFromVirtualPath(&lt;br/&gt;                                        pageVirtualPath, &lt;span style="color:blue"&gt;typeof&lt;/span&gt;(&lt;span style="color:blue"&gt;object&lt;/span&gt;)) &lt;span style="color:blue"&gt;as &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Page&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( handler &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;InvalidOperationException&lt;/span&gt;(&lt;br/&gt;                &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Format(&lt;span style="color:#a31515"&gt;"指定的路径 {0} 不是一个有效的页面。"&lt;/span&gt;, pageVirtualPath));&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;        SetPageModel(handler, model);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;StringWriter &lt;/span&gt;output &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;StringWriter&lt;/span&gt;();&lt;br/&gt;        context&lt;span style="color:red"&gt;.&lt;/span&gt;Server&lt;span style="color:red"&gt;.&lt;/span&gt;Execute(handler, output, &lt;span style="color:blue"&gt;false&lt;/span&gt;);&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;output&lt;span style="color:red"&gt;.&lt;/span&gt;ToString();&lt;br/&gt;    }&lt;br/&gt;&lt;p&gt;UcResult则会调用UcExecutor.Render()生成用户控件的输出代码，具体过程如下：&lt;a href="javascript:void(0);" codeId="pre-UcExecutor"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public static class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;UcExecutor&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;internal static readonly &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Type &lt;/span&gt;MyUserControlViewOpenType &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;typeof&lt;/span&gt;(&lt;span style="color:#2b91af"&gt;MyUserControlView&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&amp;gt;&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;用指定的用户控件以及视图数据呈现结果，最后返回生成的HTML代码。&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;用户控件应从MyUserControlView&amp;amp;lt;T&amp;amp;gt;继承&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    /// &amp;lt;param name="ucVirtualPath"&amp;gt;&lt;/span&gt;&lt;span style="color:green"&gt;用户控件的虚拟路径&lt;/span&gt;&lt;span style="color:gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;    /// &amp;lt;param name="model"&amp;gt;&lt;/span&gt;&lt;span style="color:green"&gt;视图数据&lt;/span&gt;&lt;span style="color:gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;    /// &amp;lt;returns&amp;gt;&lt;/span&gt;&lt;span style="color:green"&gt;生成的HTML代码&lt;/span&gt;&lt;span style="color:gray"&gt;&amp;lt;/returns&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;public static string &lt;/span&gt;Render(&lt;span style="color:blue"&gt;string &lt;/span&gt;ucVirtualPath, &lt;span style="color:blue"&gt;object &lt;/span&gt;model)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(ucVirtualPath) )&lt;br/&gt;            &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"ucVirtualPath"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;Page &lt;/span&gt;page &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Page&lt;/span&gt;();&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;Control &lt;/span&gt;ctl &lt;span style="color:red"&gt;= &lt;/span&gt;page&lt;span style="color:red"&gt;.&lt;/span&gt;LoadControl(ucVirtualPath);&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( ctl &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;InvalidOperationException&lt;/span&gt;(&lt;br/&gt;                &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Format(&lt;span style="color:#a31515"&gt;"指定的用户控件 {0} 没有找到。"&lt;/span&gt;, ucVirtualPath));&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;MyBaseUserControl &lt;/span&gt;myctl &lt;span style="color:red"&gt;= &lt;/span&gt;ctl &lt;span style="color:blue"&gt;as &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyBaseUserControl&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( myctl &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) {&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( model &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) {&lt;br/&gt;                &lt;span style="color:#2b91af"&gt;Type &lt;/span&gt;viewType &lt;span style="color:red"&gt;= &lt;/span&gt;MyUserControlViewOpenType&lt;span style="color:red"&gt;.&lt;/span&gt;MakeGenericType(model&lt;span style="color:red"&gt;.&lt;/span&gt;GetType());&lt;br/&gt;                &lt;span style="color:#2b91af"&gt;Type &lt;/span&gt;ctrlType &lt;span style="color:red"&gt;= &lt;/span&gt;myctl&lt;span style="color:red"&gt;.&lt;/span&gt;GetType();&lt;br/&gt;&lt;br/&gt;                &lt;span style="color:green"&gt;// 检查用户控件的类型是否匹配&lt;br/&gt;                &lt;/span&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( ctrlType &lt;span style="color:red"&gt;== &lt;/span&gt;viewType &lt;span style="color:red"&gt;|| &lt;/span&gt;ctrlType&lt;span style="color:red"&gt;.&lt;/span&gt;IsSubclassOf(viewType) ) {&lt;br/&gt;                    &lt;span style="color:green"&gt;// 给用户控件的视图数据赋值。&lt;br/&gt;                    &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DataMember &lt;/span&gt;member &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ReflectionHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetMemberByName(viewType, &lt;span style="color:#a31515"&gt;"Model"&lt;/span&gt;, &lt;span style="color:blue"&gt;true&lt;/span&gt;);&lt;br/&gt;                    member&lt;span style="color:red"&gt;.&lt;/span&gt;SetValue(myctl, model);&lt;br/&gt;                }&lt;br/&gt;                &lt;span style="color:blue"&gt;else&lt;br/&gt;                    throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"参数model的类型与用户控件的参数类型不一致。"&lt;/span&gt;);&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 将用户控件放在Page容器中。&lt;br/&gt;        &lt;/span&gt;page&lt;span style="color:red"&gt;.&lt;/span&gt;Controls&lt;span style="color:red"&gt;.&lt;/span&gt;Add(ctl);&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;StringWriter &lt;/span&gt;output &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;StringWriter&lt;/span&gt;();&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;HtmlTextWriter &lt;/span&gt;write &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HtmlTextWriter&lt;/span&gt;(output, &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Empty);&lt;br/&gt;        page&lt;span style="color:red"&gt;.&lt;/span&gt;RenderControl(write);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 用下面的方法也可以的。&lt;br/&gt;        //HttpContext.Current.Server.Execute(page, output, false);&lt;br/&gt;&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:blue"&gt;return &lt;/span&gt;output&lt;span style="color:red"&gt;.&lt;/span&gt;ToString();&lt;br/&gt;    }&lt;br/&gt;&lt;p&gt;&lt;strong&gt;HTML分块输出&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;注意哦，前面介绍的2个Render方法的可见性都是public，这样设计的想法是让框架提供对外生成HTML的能力，或许有些用户有这样的需求。另一方面，或许还有些用户打算在Action的执行过程中，将原来较大的HTML页面分块输出给客户端。BigPipe就使用了这种想法：整个请求不用等到全部数据获取成功后一次性输出，而是将页面按业务逻辑拆分，并在获取到相应的数据后，立即向客户端输出部分片段。&lt;/p&gt;&lt;p&gt;其实HTML分块输出在ASP.NET中并不是什么新的技术，而是在ASP.NET一出现时就已经存在了，那就是在输出的过程中不断调用Response.Flush();&lt;/p&gt;&lt;p&gt;由于MyMVC将生成HTML做为一种基础功能，因此在MyMVC中，只要您调用Response.Flush();便可以方便地实现分块输出。不过，为了让调用更简单，我提供了二个辅助方法来简化这个过程。&lt;/p&gt;&lt;p&gt;在PageExecutor类型中的ResponseWrite方法：&lt;a href="javascript:void(0);" codeId="pre-PageExecutor-ResponseWrite"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;用指定的Page以及视图数据呈现结果，&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;然后将产生的HTML代码写入HttpContext.Current.Response&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;用户控件应从MyPageView&amp;amp;lt;T&amp;amp;gt;继承&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;/// &amp;lt;param name="pageVirtualPath"&amp;gt;&lt;/span&gt;&lt;span style="color:green"&gt;Page的虚拟路径&lt;/span&gt;&lt;span style="color:gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;/// &amp;lt;param name="model"&amp;gt;&lt;/span&gt;&lt;span style="color:green"&gt;视图数据&lt;/span&gt;&lt;span style="color:gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;/// &amp;lt;param name="flush"&amp;gt;&lt;/span&gt;&lt;span style="color:green"&gt;是否需要在输出html后调用Response.Flush()&lt;/span&gt;&lt;span style="color:gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public static void &lt;/span&gt;ResponseWrite(&lt;span style="color:blue"&gt;string &lt;/span&gt;pageVirtualPath, &lt;span style="color:blue"&gt;object &lt;/span&gt;model, &lt;span style="color:blue"&gt;bool &lt;/span&gt;flush)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpContext&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Current;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( context &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;        &lt;span style="color:blue"&gt;return&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;ContentType) )&lt;br/&gt;        context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;ContentType &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"text/html"&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;string &lt;/span&gt;html &lt;span style="color:red"&gt;= &lt;/span&gt;Render(context, pageVirtualPath, model);&lt;br/&gt;    context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Write(html);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( flush )&lt;br/&gt;        context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Flush();&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;在UcExecutor类型中的ResponseWrite方法：&lt;a href="javascript:void(0);" codeId="pre-UcExecutor-ResponseWrite"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;用指定的用户控件以及视图数据呈现结果，&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;然后将产生的HTML代码写入HttpContext.Current.Response&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;用户控件应从MyUserControlView&amp;amp;lt;T&amp;amp;gt;继承&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;/// &amp;lt;param name="ucVirtualPath"&amp;gt;&lt;/span&gt;&lt;span style="color:green"&gt;用户控件的虚拟路径&lt;/span&gt;&lt;span style="color:gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;/// &amp;lt;param name="model"&amp;gt;&lt;/span&gt;&lt;span style="color:green"&gt;视图数据&lt;/span&gt;&lt;span style="color:gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;/// &amp;lt;param name="flush"&amp;gt;&lt;/span&gt;&lt;span style="color:green"&gt;是否需要在输出html后调用Response.Flush()&lt;/span&gt;&lt;span style="color:gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public static void &lt;/span&gt;ResponseWrite(&lt;span style="color:blue"&gt;string &lt;/span&gt;ucVirtualPath, &lt;span style="color:blue"&gt;object &lt;/span&gt;model, &lt;span style="color:blue"&gt;bool &lt;/span&gt;flush)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpContext&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Current;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( context &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;        &lt;span style="color:blue"&gt;return&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;ContentType) )&lt;br/&gt;        context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;ContentType &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"text/html"&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;string &lt;/span&gt;html &lt;span style="color:red"&gt;= &lt;/span&gt;Render(ucVirtualPath, model);&lt;br/&gt;    context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Write(html);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( flush )&lt;br/&gt;        context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Flush();&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&lt;b&gt;注意：&lt;/b&gt;由于这二个方法在内部使用了HttpContext.Current，因此如果在Action中调用它们，会造成Action不能支持单元测试。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;关于单元测试的支持&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;提到MVC思想，我想就不得不谈单元测试了。&lt;br /&gt;因为MVC的主要思想还是想把这三个字目对应的事物分开，以方便开发与测试。这里面，我认为尤其是View与Controller的分离最为重要，因为有UI的地方比较难测试，反过来，如果没有UI的东西就比较容易测试了。&lt;/p&gt;&lt;p&gt;不过，在ASP.NET中，影响单元测试的不仅仅只是UI元素，还有HttpContxt, HttpRequest, HttpResponse这之类的&lt;b&gt;&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/08/21/2148640.html" target="_blank"&gt;核心对象&lt;/a&gt;&lt;/b&gt;。比如：即使我们将Controller放在类库项目中实现，但在Action中还在访问QueryString，Form，甚至发起重定向的请求，你说这样的代码如何测试。&lt;/p&gt;&lt;p&gt;我认为判断一个方法是否可支持单元测试有一个简单的办法：&lt;b&gt;写个控制台的程序去调用它，看它能否正常运行。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;通常，用户的输入数据主要有三个来源：QueryString, Form, Cookie。而且前二者居多，Cookie则多用于保存用户偏好设置。因此，在MyMVC中，可以让Action不再去直接访问QueryString, Form，替代的方式是：将要读取的名字做为C#方法的参数名明确指出。这样，Actioin中的代码就远离了QueryString, Form。至于Cookie的访问，MyMVC则提供一个辅助类来支持访问：&lt;a href="javascript:void(0);" codeId="pre-CookieHelper"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;读写Cookie的辅助工具类。这个类对测试环境仍然有效。&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public static class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CookieHelper&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;ThreadStatic&lt;/span&gt;]&lt;br/&gt;    &lt;span style="color:blue"&gt;private static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpCookieCollection &lt;/span&gt;s_cookies;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;private static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpCookieCollection &lt;/span&gt;TestCookies&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;get&lt;br/&gt;        &lt;/span&gt;{&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;TestEnvironment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsTestEnvironment &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;)&lt;br/&gt;                &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;InvalidOperationException&lt;/span&gt;();&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( s_cookies &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)    &lt;span style="color:green"&gt;// 测试环境不考虑线程安全问题。&lt;br/&gt;                &lt;/span&gt;s_cookies &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpCookieCollection&lt;/span&gt;();&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;s_cookies;&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;从Request中获取一个Cookie对象&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    /// &amp;lt;param name="key"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;public static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpCookie &lt;/span&gt;GetCookie(&lt;span style="color:blue"&gt;string &lt;/span&gt;key)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;TestEnvironment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsTestEnvironment ) &lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;TestCookies[key];&lt;br/&gt;        &lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpContext&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Current&lt;span style="color:red"&gt;.&lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;Cookies[key];&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;从Request中获取一个Cookie对象的值，如果不存在，则返回null&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    /// &amp;lt;param name="key"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;public static string &lt;/span&gt;GetCookieValue(&lt;span style="color:blue"&gt;string &lt;/span&gt;key)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;HttpCookie &lt;/span&gt;cookie &lt;span style="color:red"&gt;= &lt;/span&gt;GetCookie(key);&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( cookie &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color:blue"&gt;else&lt;br/&gt;            return &lt;/span&gt;cookie&lt;span style="color:red"&gt;.&lt;/span&gt;Value;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;将一个Cookie对应写入到Response中&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    /// &amp;lt;param name="cookie"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;public static void &lt;/span&gt;SetCookie(&lt;span style="color:#2b91af"&gt;HttpCookie &lt;/span&gt;cookie)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;TestEnvironment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsTestEnvironment ) &lt;br/&gt;            TestCookies&lt;span style="color:red"&gt;.&lt;/span&gt;Set(cookie);            &lt;br/&gt;        &lt;span style="color:blue"&gt;else&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpContext&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Current&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Cookies&lt;span style="color:red"&gt;.&lt;/span&gt;Set(cookie);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;将一个Cookie对应写入到Response中&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    /// &amp;lt;param name="cookie"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;public static void &lt;/span&gt;AddCookie(&lt;span style="color:#2b91af"&gt;HttpCookie &lt;/span&gt;cookie)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;TestEnvironment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsTestEnvironment ) &lt;br/&gt;            TestCookies&lt;span style="color:red"&gt;.&lt;/span&gt;Add(cookie);&lt;br/&gt;        &lt;span style="color:blue"&gt;else&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpContext&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Current&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Cookies&lt;span style="color:red"&gt;.&lt;/span&gt;Add(cookie);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;清除所有写入的Cookie &lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;public static void &lt;/span&gt;ClearCookie()&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;TestEnvironment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsTestEnvironment )&lt;br/&gt;            TestCookies&lt;span style="color:red"&gt;.&lt;/span&gt;Clear();&lt;br/&gt;        &lt;span style="color:blue"&gt;else&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpContext&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Current&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Cookies&lt;span style="color:red"&gt;.&lt;/span&gt;Clear();&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;删除指定名称的Cookie&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    /// &amp;lt;param name="key"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;public static void &lt;/span&gt;RemoveCookie(&lt;span style="color:blue"&gt;string &lt;/span&gt;key)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;TestEnvironment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsTestEnvironment ) &lt;br/&gt;            TestCookies&lt;span style="color:red"&gt;.&lt;/span&gt;Remove(key);&lt;br/&gt;        &lt;span style="color:blue"&gt;else&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpContext&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Current&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Cookies&lt;span style="color:red"&gt;.&lt;/span&gt;Remove(key);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&lt;b&gt;重定向也是常见的需求。&lt;/b&gt;MyMVC则是通过提供RedirectResult来支持的：&lt;a href="javascript:void(0);" codeId="pre-RedirectResult"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;表示一个重定向的结果&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public sealed class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;RedirectResult &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IActionResult&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;Url { &lt;span style="color:blue"&gt;get&lt;/span&gt;; &lt;span style="color:blue"&gt;private set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public &lt;/span&gt;RedirectResult(&lt;span style="color:blue"&gt;string &lt;/span&gt;url)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(url) )&lt;br/&gt;            &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"url"&lt;/span&gt;);&lt;br/&gt;        Url &lt;span style="color:red"&gt;= &lt;/span&gt;url;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;void &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IActionResult&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Ouput(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context)&lt;br/&gt;    {&lt;br/&gt;        context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Redirect(Url, &lt;span style="color:blue"&gt;true&lt;/span&gt;);&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;说明：Ouput方法由框架调用，不影响Action的单元测试。&lt;br /&gt;示例代码：&lt;a href="javascript:void(0);" codeId="pre-RedirectResult-demo"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public object &lt;/span&gt;Delete(&lt;span style="color:blue"&gt;int &lt;/span&gt;id)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;BllFactory&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetCategoryBLL()&lt;span style="color:red"&gt;.&lt;/span&gt;Delete(id);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;RedirectResult&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"/Pages/Categories.aspx"&lt;/span&gt;);&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;在ASP.NET项目开发过程中，还有一类需求较为常见，那就是：&lt;b&gt;访问一些当前环境变量。&lt;/b&gt;&lt;br /&gt;MyMVC则是通过以下二个类型来处理的。&lt;a href="javascript:void(0);" codeId="pre-TestEnvironment"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public static class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;TestEnvironment&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;当前运行环境是否为测试环境（非ASP.NET环境）&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;internal static readonly bool &lt;/span&gt;IsTestEnvironment &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;HttpRuntime&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;AppDomainAppId &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;ThreadStatic&lt;/span&gt;]&lt;br/&gt;    &lt;span style="color:blue"&gt;private static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Hashtable &lt;/span&gt;s_ContextInfo;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;private static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Hashtable &lt;/span&gt;ContextInfo&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;get&lt;br/&gt;        &lt;/span&gt;{&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;TestEnvironment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsTestEnvironment &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;)&lt;br/&gt;                &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;InvalidOperationException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"只有测试代码才允许执行这个调用。"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( s_ContextInfo &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)    &lt;span style="color:green"&gt;// 测试环境不考虑线程安全问题。&lt;br/&gt;                &lt;/span&gt;s_ContextInfo &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Hashtable&lt;/span&gt;(&lt;span style="color:purple"&gt;100&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;StringComparer&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Ordinal);&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;s_ContextInfo;&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public static object &lt;/span&gt;GetValue(&lt;span style="color:blue"&gt;string &lt;/span&gt;key)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;object &lt;/span&gt;val &lt;span style="color:red"&gt;= &lt;/span&gt;ContextInfo[key];&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( val &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;InvalidOperationException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"您忘记了给测试环境赋值了。参数名：" &lt;/span&gt;&lt;span style="color:red"&gt;+ &lt;/span&gt;key);&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;val;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public static void &lt;/span&gt;SetValue(&lt;span style="color:blue"&gt;string &lt;/span&gt;key, &lt;span style="color:blue"&gt;object &lt;/span&gt;val)&lt;br/&gt;    {&lt;br/&gt;        ContextInfo[key] &lt;span style="color:red"&gt;= &lt;/span&gt;val;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public static void &lt;/span&gt;ClearTestEnvironmentInfo()&lt;br/&gt;    {&lt;br/&gt;        ContextInfo&lt;span style="color:red"&gt;.&lt;/span&gt;Clear();&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;CookieHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;ClearCookie();&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;用于访问当前请求上下文的工具类。这个类对测试环境仍然有效。&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public static class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpContextHelper&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;// 为了能让代码支持测试环境&lt;br/&gt;    // 会判断 TestEnvironment.IsTestEnvironment&lt;br/&gt;    // 如果在ASP.NET环境中运行，则直接返回HttpRuntime或者HttpContext.Current中的参数值&lt;br/&gt;    // 如果是在测试环境中运行，则使用另一个静态变量来维护所有需要访问的状态。&lt;br/&gt;    &lt;br/&gt;    // 在测试前，需要先给相应的参数赋值。&lt;br/&gt;    // 测试完成后可调用TestEnvironment.ClearTestEnvironmentInfo()清除临时环境。&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;return HttpRuntime.AppDomainAppPath;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;public static string &lt;/span&gt;AppRootPath&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;get&lt;br/&gt;        &lt;/span&gt;{&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;TestEnvironment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsTestEnvironment )&lt;br/&gt;                &lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:#2b91af"&gt;TestEnvironment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetValue(&lt;span style="color:#a31515"&gt;"AppDomainAppPath"&lt;/span&gt;) &lt;span style="color:blue"&gt;as string&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpRuntime&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;AppDomainAppPath;&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color:blue"&gt;set&lt;br/&gt;        &lt;/span&gt;{&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;TestEnvironment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;SetValue(&lt;span style="color:#a31515"&gt;"AppDomainAppPath"&lt;/span&gt;, &lt;span style="color:blue"&gt;value&lt;/span&gt;);&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;return HttpContext.Current.Request.FilePath;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;public static string &lt;/span&gt;RequestFilePath&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;get&lt;br/&gt;        &lt;/span&gt;{&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;TestEnvironment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsTestEnvironment )&lt;br/&gt;                &lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:#2b91af"&gt;TestEnvironment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetValue(&lt;span style="color:#a31515"&gt;"RequestFilePath"&lt;/span&gt;) &lt;span style="color:blue"&gt;as string&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpContext&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Current&lt;span style="color:red"&gt;.&lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;FilePath;&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color:blue"&gt;set&lt;br/&gt;        &lt;/span&gt;{&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;TestEnvironment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;SetValue(&lt;span style="color:#a31515"&gt;"RequestFilePath"&lt;/span&gt;, &lt;span style="color:blue"&gt;value&lt;/span&gt;);&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;return HttpContext.Current.Request.RawUrl;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;public static string &lt;/span&gt;RequestRawUrl&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;get&lt;br/&gt;        &lt;/span&gt;{&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;TestEnvironment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsTestEnvironment )&lt;br/&gt;                &lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:#2b91af"&gt;TestEnvironment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetValue(&lt;span style="color:#a31515"&gt;"RequestRawUrl"&lt;/span&gt;) &lt;span style="color:blue"&gt;as string&lt;/span&gt;;&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpContext&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Current&lt;span style="color:red"&gt;.&lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;RawUrl;&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color:blue"&gt;set&lt;br/&gt;        &lt;/span&gt;{&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;TestEnvironment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;SetValue(&lt;span style="color:#a31515"&gt;"RequestRawUrl"&lt;/span&gt;, &lt;span style="color:blue"&gt;value&lt;/span&gt;);&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;return HttpContext.Current.User.Identity.Name;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;public static string &lt;/span&gt;UserIdentityName&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;get&lt;br/&gt;        &lt;/span&gt;{&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;TestEnvironment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsTestEnvironment )&lt;br/&gt;                &lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:#2b91af"&gt;TestEnvironment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetValue(&lt;span style="color:#a31515"&gt;"UserIdentityName"&lt;/span&gt;) &lt;span style="color:blue"&gt;as string&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;HttpContext&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Current&lt;span style="color:red"&gt;.&lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;IsAuthenticated &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;)&lt;br/&gt;                &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpContext&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Current&lt;span style="color:red"&gt;.&lt;/span&gt;User&lt;span style="color:red"&gt;.&lt;/span&gt;Identity&lt;span style="color:red"&gt;.&lt;/span&gt;Name;&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color:blue"&gt;set&lt;br/&gt;        &lt;/span&gt;{&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;TestEnvironment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;SetValue(&lt;span style="color:#a31515"&gt;"UserIdentityName"&lt;/span&gt;, &lt;span style="color:blue"&gt;value&lt;/span&gt;);&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 如果还需要访问更多的HttpContext信息，也可以采用下面的方法。请自行完成。&lt;br/&gt;&lt;br/&gt;    //public static HttpContextBase Current&lt;br/&gt;    //{&lt;br/&gt;    //    get { }&lt;br/&gt;    //    set { }&lt;br/&gt;    //}&lt;br/&gt;&lt;/span&gt;}&lt;br/&gt;&lt;p&gt;注意HttpContextHelper这个类，我将平时访问的一些与请求或者与ASP.NET运行环境相关的属性全部封装在这里了。如果不够，还可以继续添加。有了这些代码，我就可以简单在控制台程序中调用它们（您也可以移到单元测试项目中）：&lt;a href="javascript:void(0);" codeId="pre-Test_TestEnvironment"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Program&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;static void &lt;/span&gt;Main(&lt;span style="color:blue"&gt;string&lt;/span&gt;[] args)&lt;br/&gt;    {&lt;br/&gt;        InitDB();&lt;br/&gt;&lt;br/&gt;        Test_AjaxStyle_SetStyle();&lt;br/&gt;        Test_AjaxCustomer_GetById();&lt;br/&gt;        Test_TestEnvironment();&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;Console&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;ReadLine();&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;static void &lt;/span&gt;InitDB()&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;string &lt;/span&gt;xmlPath &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"..\\..\\DemoWebSite1\\App_Data\\MyNorthwindDataBase.xml"&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;WebSiteDB&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;LoadDbFromXml(xmlPath);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;static void &lt;/span&gt;Test_AjaxStyle_SetStyle()&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;AjaxStyle &lt;/span&gt;ajax &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;AjaxStyle&lt;/span&gt;();&lt;br/&gt;        ajax&lt;span style="color:red"&gt;.&lt;/span&gt;SetStyle(&lt;span style="color:#2b91af"&gt;StyleHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;StyleArray[&lt;span style="color:purple"&gt;0&lt;/span&gt;]);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;CookieHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetCookieValue(&lt;span style="color:#2b91af"&gt;StyleHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;STR_PageStyle) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:#2b91af"&gt;StyleHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;StyleArray[&lt;span style="color:purple"&gt;0&lt;/span&gt;] )&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;Console&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="color:#a31515"&gt;"AjaxStyle.SetStyle(\"{0}\") OK"&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;StyleHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;StyleArray[&lt;span style="color:purple"&gt;0&lt;/span&gt;]);&lt;br/&gt;        &lt;span style="color:blue"&gt;else&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Console&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="color:#a31515"&gt;"AjaxStyle.SetStyle(\"{0}\") faild."&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;StyleHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;StyleArray[&lt;span style="color:purple"&gt;0&lt;/span&gt;]);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;CookieHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;ClearCookie();&lt;br/&gt;&lt;br/&gt;        ajax&lt;span style="color:red"&gt;.&lt;/span&gt;SetStyle(&lt;span style="color:#a31515"&gt;"abc"&lt;/span&gt;);        &lt;span style="color:green"&gt;// 一个无效的值。&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;CookieHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetCookieValue(&lt;span style="color:#2b91af"&gt;StyleHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;STR_PageStyle) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null  &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;Console&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="color:#a31515"&gt;"AjaxStyle.SetStyle(\"abc\") OK"&lt;/span&gt;);&lt;br/&gt;        &lt;span style="color:blue"&gt;else&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Console&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="color:#a31515"&gt;"AjaxStyle.SetStyle(\"abc\") faild."&lt;/span&gt;);&lt;br/&gt;    }&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color:blue"&gt;static void &lt;/span&gt;Test_AjaxCustomer_GetById()&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;AjaxCustomer &lt;/span&gt;ajax &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;AjaxCustomer&lt;/span&gt;();&lt;br/&gt;        &lt;span style="color:blue"&gt;object &lt;/span&gt;result &lt;span style="color:red"&gt;= &lt;/span&gt;ajax&lt;span style="color:red"&gt;.&lt;/span&gt;GetById(&lt;span style="color:purple"&gt;1&lt;/span&gt;);&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( result &lt;span style="color:blue"&gt;is &lt;/span&gt;&lt;span style="color:#2b91af"&gt;JsonResult &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;Console&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="color:#a31515"&gt;"AjaxCustomer.GetById(1) OK"&lt;/span&gt;);&lt;br/&gt;        &lt;span style="color:blue"&gt;else&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Console&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="color:#a31515"&gt;"AjaxCustomer.GetById(1) faild"&lt;/span&gt;);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;static void &lt;/span&gt;Test_TestEnvironment()&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;TestEnvironment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;SetValue(&lt;span style="color:#a31515"&gt;"key1"&lt;/span&gt;, &lt;span style="color:purple"&gt;123&lt;/span&gt;);&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;TestEnvironment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;SetValue(&lt;span style="color:#a31515"&gt;"key2"&lt;/span&gt;, &lt;span style="color:#a31515"&gt;"abc"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( (&lt;span style="color:blue"&gt;int&lt;/span&gt;)&lt;span style="color:#2b91af"&gt;TestEnvironment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetValue(&lt;span style="color:#a31515"&gt;"key1"&lt;/span&gt;) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:purple"&gt;123 &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;Console&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="color:#a31515"&gt;"TestEnvironment.SetValue(123) OK."&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( (&lt;span style="color:blue"&gt;string&lt;/span&gt;)&lt;span style="color:#2b91af"&gt;TestEnvironment&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetValue(&lt;span style="color:#a31515"&gt;"key2"&lt;/span&gt;) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:#a31515"&gt;"abc" &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;Console&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="color:#a31515"&gt;"TestEnvironment.SetValue(\"abc\") OK."&lt;/span&gt;);&lt;br/&gt;    }&lt;br/&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;用过ASP.NET MVC的人可能会问我：&lt;br /&gt;为什么不使用System.Web.Abstractions定义的那些类型，那样不是更容易支持单元测试吗？&lt;br /&gt;是啊，我也知道那种做法的好处。但那样做的工作量也会更大。&lt;br /&gt;根据目前的MyMVC设计方式，如果要引入HttpContextBase, HttpRequestBase, HttpResponseBase这类对象，就需要设计Controller基类，并且创建Controller的过程也会比目前复杂，或者要把ASP.NET MVC那套创建Controller的过程搬过来，否则仍然会不完整。然而，&lt;b&gt;我还是打算自己再设计另一种简单的方法 尽可能 地去解决这个问题。&lt;/b&gt;上面的方法就是我的设计，虽然不够完整，却是简单有效的，而且测试代码也会简单很多。另一方面，我不提供Controller基类，但可以设计诸如HttpContextHelper.Current这样的访问方式，最终的结果仍然是可以支持单元测试的，况且HttpContextHelper.Current这种用法也不会让人难以适应。不提供还有另外的好处：允许设计自己的基类。&lt;/p&gt;&lt;p&gt;还有一点要补充的是：MyMVC框架内部也没有使用System.Web.Abstractions，是的，我知道。&lt;br /&gt;这也只能说：框架的代码不能进行单元测试而已。   &lt;b&gt;但不影响用户的Action代码的单元测试。&lt;/b&gt;&lt;br /&gt;再说框架中的代码有些也很难做单元测试，毕竟太依赖于ASP.NET，而且我没那么多的空闲时间以及驱动力。&lt;/p&gt;&lt;p&gt;MyMVC还有一个没有支持的是文件的上传与下载。&lt;br /&gt;这里我来说说对于这块功能访如何去实现：&lt;br /&gt;1. 可以直接访问HttpContext.Current ，并忽略这些代码的单元测试能力。&lt;br /&gt;2. 自行实现我前面没有实现的HttpContextHelper.Current 。&lt;br /&gt;是的，我的确没有完成这个功能，而把它留给了用户，抱歉。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;关于框架代码与示例代码&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在本文的未尾，我提供了MyMVC框架的代码，以及全部示例代码。&lt;/p&gt;&lt;p&gt;以前我也提供过我的&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/05/02/2034010.html" target="_blank"&gt;老版本框架的演示示例&lt;/a&gt;，我认为我已经考虑地相当周到了：&lt;br /&gt;1. 没有IIS，没有VS，一样可以运行我的DEMO，因为我把&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/10/26/2225848.html" target="_blank"&gt;FishAspnetLoader&lt;/a&gt;放进去了，调用的BAT文件也准备好了。&lt;br /&gt;2. SQL SERVER如果支持【用户实例】模式，部署会容易。&lt;br /&gt;3. 在数据方面，我不但提供了mdf文件，还提供了sql脚本。&lt;br /&gt;4. 还准备了一些说明文件。&lt;br /&gt;&lt;br /&gt;然而，事实却没有我想像那么好，还是有很多人给我发邮件，问我示例为什么不能运行。&lt;br /&gt;不能运行的环境也是让我完全没有想到的：&lt;br /&gt;1. 有人把它部署到了IIS6，扩展名的映射遇到问题。&lt;br /&gt;2. 有人把它部署到了IIS7，可我没有提供对IIS7的配置！&lt;br /&gt;3. 有人没有安装SQL SERVER。这个只能是没有办法了！&lt;br /&gt;4. 有人不能完成示例程序所需的SQL SERVER配置。&lt;br /&gt;5. 有人用VS2010打开项目并升级了.net版本，遇到一些说不清楚的问题。&lt;/p&gt;&lt;p&gt;吸取前面的教训后，这次我的示例采用XML文件做为数据源，而且增加了IIS7的配置。&lt;br /&gt;不过，有一点我不能替您设置的是XML文件的写入权限。&lt;br /&gt;如果数据不能保存，请检查目录的写入权限，此时程序没有任何提示。&lt;/p&gt;&lt;p&gt;再补充二点：&lt;br /&gt;1. 如果您使用VS2010打开示例项目，请不要选择升级.net版本，不要盲目点击确定。&lt;br /&gt;2. 如果在IIS中部署示例网站遇到问题，那么建议使用VS运行示例网站。&lt;/p&gt;&lt;p&gt;如果您还有配置ASP.NET应用程序的问题，那么请关注我的后续博客。&lt;br /&gt;下篇博客我打算谈一下在部署ASP.NET网站时，IIS6/7 以及SQL SERVER中必须知道的一些设置。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://files.cnblogs.com/fish-li/MyMVC.cab.7z"&gt;点击此处下载示例代码&lt;/a&gt;&lt;/p&gt;&lt;div class="articleFooter"&gt;&lt;p&gt;&lt;b class="redText"&gt;注意：本文所介绍的框架还提供另外一个工具做为演示示例，&lt;/b&gt;&lt;br /&gt;点击后面链接即可阅读。&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/03/04/2379612.html" target="_blank"&gt;【用ASP.NET写个SQLSERVER的小工具】&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class="articleFooter"&gt;&lt;p&gt;如果，您认为阅读这篇博客让您有些收获，不妨点击一下右下角的&lt;a id="btnRecommendMyBlog" href="javascript:void(0);"&gt;【&lt;b&gt;推荐&lt;/b&gt;】&lt;/a&gt;按钮。&lt;br /&gt;如果，您希望更容易地发现我的新博客，不妨点击一下右下角的&lt;a id="btnFollowFishLi" href="javascript:void(0);"&gt;【&lt;b&gt;关注 Fish Li&lt;/b&gt;】&lt;/a&gt;。&lt;br /&gt;因为，我的写作热情也离不开您的肯定支持。&lt;/p&gt;&lt;p&gt;感谢您的阅读，如果您对我的博客所讲述的内容有兴趣，请继续关注我的后续博客，我是Fish Li 。&lt;span class="icon_smile"&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/fish-li/aggbug/2361982.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/21/2361982.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/fish-li/archive/2012/02/12/2348395.html</id><title type="text">写自己的ASP.NET MVC框架（上）</title><summary type="text">写了几篇细说之后，今天打算换换口味，还是来写代码吧。所以，这次博客将以实际的代码来展示在ASP.NET平台上开发自己的框架，我希望也能让您发现这并不是件难事。我在前面的博客【用Asp.net写自己的服务框架】中，发布了一个用ASP.NET写的服务框架，那个框架我目前仍在使用中。近来，由于时常也会有人问我一些关于ASP.NET MVC的话题，因此，就想再写个自己的MVC框架出来，一方面可以留给自己使用，另外也可以谈谈MVC，尤其可以展示一下在ASP.NET下写框架的乐趣。我之所以将写框架看成是件有乐趣的事，是因为：在写框架的过程中会接触许多的技术细节。比如：1. 为了支持Session需要了解管</summary><published>2012-02-12T14:13:00Z</published><updated>2012-02-12T14:13:00Z</updated><author><name>Fish Li</name><uri>http://www.cnblogs.com/fish-li/</uri></author><link rel="alternate" href="http://www.cnblogs.com/fish-li/archive/2012/02/12/2348395.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/fish-li/archive/2012/02/12/2348395.html"/><content type="html">&lt;p&gt;写了几篇细说之后，今天打算换换口味，还是来写代码吧。所以，这次博客将以实际的代码来展示在ASP.NET平台上开发自己的框架，我希望也能让您发现这并不是件难事。&lt;/p&gt;&lt;p&gt;我在前面的博客&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/09/05/2168073.html" target="_blank"&gt;【用Asp.net写自己的服务框架】&lt;/a&gt;中，发布了一个用ASP.NET写的服务框架，那个框架我目前仍在使用中。近来，由于时常也会有人问我一些关于ASP.NET MVC的话题，因此，就想再写个自己的MVC框架出来，一方面可以留给自己使用，另外也可以谈谈MVC，尤其可以展示一下在ASP.NET下写框架的乐趣。&lt;/p&gt;&lt;p&gt;我之所以将写框架看成是件有乐趣的事，是因为：在写框架的过程中会接触许多的技术细节。&lt;br /&gt;比如：&lt;br /&gt;1. 为了支持Session需要了解管线过程以及支持Session工作的原理。&lt;br /&gt;2. 在HttpHandler的映射过程中，HttpHandlerFactory的使用会让设计很灵活。&lt;br /&gt;3. 反射可以让我们轻松地根据一个URL去寻找匹配的Action以及为Action准备传入参数。&lt;br /&gt;4. 为了便于测试Action，如何有效的封装框架的功能（这里有许多ASP.NET的技术细节）。&lt;br /&gt;5. 如何设计让框架更灵活更强大。&lt;/p&gt;&lt;p&gt;在开始今天的博客之前，我想有必要说说我的框架的规模：&lt;br /&gt;如果说ASP.NET WebForm是个复杂框架，ASP.NET MVC是个轻量级框架的话，那么，我的MVC框架将只是个微量级的框架。&lt;br /&gt;但这个微量级的框架却可以提供许多实用的功能（因为我没有引入一些与MVC无关的东西），而且完全遵守MVC的思想而设计。&lt;br /&gt;由于我的框架规模实在太小，因此，有些地方的确是不够完善，但我认为在大多数情况下是够用的。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;ASP.NET程序的几种开发方式&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;时常见到有人在问：到底选择WebForm还是MVC ？&lt;br /&gt;其实我认为最好是二个都选吧。然后，你去发现它们的优点与缺点，最后，当你觉得它们都不爽时，还是写自己的框架吧。&lt;/p&gt;&lt;p&gt;我来说说我这样选择的理由：任何东西都有它们的优点，这很正常，所以二个都选就能发现更多的优点，发现优点的过程其实也是自己进步的过程。当然它们也有缺点，发现那些缺点，你自然会想办法去避开，其实这也是个进步的过程。因此，在你吸收优点以及避开缺点的过程中，会感觉它们不再完美（因为自己在进步），再到后来，你会怎么选择，我就不知道了，那就是你自己的事了。而我选择了另一条路：写自己的ASP.NET MVC框架。&lt;/p&gt;&lt;p&gt;在比较各类框架之前，我想有必要先来总结一下：现在能用ASP.NET开发哪些类型的网站？由于ASP.NET与WCF这类纯服务性质的框架不同，我们主要还是用它来开发一些可与用户交互的界面程序。因此，今天的分类将重要讨论这些界面（UI）的开发方式。&lt;/p&gt;&lt;p&gt;我认为目前的ASP.NET能支持开发三种类型的网站：&lt;br /&gt;1. &lt;b&gt;以服务端为中心的网站&lt;/b&gt;：所有页面的生成以及交互的逻辑全部服务端来完成，服务端甚至能生成必要的JS代码。&lt;br /&gt;2. &lt;b&gt;门户类网站&lt;/b&gt;：服务端只负责页面的第一次呈现，用户的交互以及表单的提交全部采用AJAX的方式完成。&lt;br /&gt;3. &lt;b&gt;纯AJAX网站&lt;/b&gt;：服务端基本上不参与UI的处理，只负责处理数据，UI在客户端由JavaScript来生成并控制提交。&lt;/p&gt;&lt;p&gt;【以服务端为中心的网站】，这类网站有个非常明显的特点，至少在开发上表现地非常明显：服务端要做的事情很多，HTML的生成, 简单的JS交互，客户端验证，等等，全由服务端来处理。在开发这类网站时，由于工作全在服务端，因此如果我们使用ASP.NET开发，自然地，所有的任务都将由aspx, C#这类技术来实现，采用这种方式开发出来的网站，页面与用户的交互性通常不会很友好，比如：提交数据时经常需要整页刷新。&lt;/p&gt;&lt;p&gt;【门户类网站】，这类网站与之前的【以服务端为中心的网站】有个重要的差别：页面只是呈现数据，表单的提交全采用AJAX方式了。这样做的好处能将显示逻辑与数据更新逻辑有效的分离，不必纠缠在一起（可认为是二个通道），在这种开发模式下，由于页面只负责数据的显示，因此，只要能将业务逻辑尽可能地与UI分离，项目在维护上会容易很多，采用这种方式开发的网站，页面与用户交互的友好性会好很多，而且也不会影响SEO，因此被较多的门户网站采用。&lt;/p&gt;&lt;p&gt;【纯AJAX网站】，在这类网站中，服务端由于不参与UI处理，网站可以只是些静态的HTML文件，而且在设计页面时，只要留下一些占位符就可以了，UI元素全部由JS来生成。这类网站的客户端通常会选择一个JS的UI框架来支持。这类界面相对于前二种来说，会更漂亮，用户的操作体验也会更友好。但由于页面主要由JS来生成，对SEO的支持较差，因此，特别适合一些后台类的网站项目。&lt;/p&gt;&lt;p&gt;在前面所列出的三种开发方式中，前二种由于界面部分由服务端来实现，因此选择一个合适的框架，会对开发工作有着非常重要的影响（尤其是第一种）。但是，如果选择第三种方式，那么选择 WebForm 还是 MVC 真的都是浮云了，甚至还可以使用其它的服务框架来支持AJAX的调用。&lt;/p&gt;&lt;p&gt;喜欢微软的MVC框架的一些人，通常会列举一些WebForm中较为低级的缺点，从而把ASP.NET MVC框架说的很完美，而且是非它不可。这里，我不想谈论它们的优点与缺点，因为我前面已经说过了，在我看来，它们都有优点也同时有各自的缺点。今天，我只想先暂且忘记它们，来实现自己的框架。&lt;/p&gt;&lt;p&gt;开始吧，看看我的作品。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;介绍我的MVC框架&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;我比较喜欢ASP.NET这个平台，因为它们扩展性实在太好了，在它上面，我可以容易地实现自己所需的东西，包括开发自己所需要的WEB框架。通过微软的ASP.NET MVC框架，也让我认识到MVC思想的优点，因此，我的WEB框架也将采用MVC思想来开发，因此，我把自己的这个框架称为【我的MVC框架：MyMVC】。今天的博客也将向您展示这个框架，同时我也会与大家一起分享我在开发框架过程中所使用到的一些技术（或者称为实现方式）。&lt;/p&gt;&lt;p&gt;为了让大家对我的MVC框架有个感性的认识，我准备了一个示例网站，网站提供二种完全不同的风格，分别采用【门户类网站】和【纯AJAX网站】的方式来开发。在示例网站的首页，程序会让您选择喜欢的界面风格来继续后面的操作，当然，您也可以随时在右上角切换风格。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012021222053972.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;我的MVC框架设计架构&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在我的框架中，【页面请求】与【AJAX请求】是分开来实现的。&lt;/p&gt;&lt;p&gt;因为我前面以对开发方式做过分类，在开发【纯AJAX网站】时，那么就几乎没有页面请求了（或许有，但可以忽略），此时在服务端全是AJAX服务（我喜欢将AJAX的服务端实现称为服务）。&lt;br /&gt;我将AJAX请求分开来处理是因为：我做的网站中，AJAX的使用非常多，数量都会超过页面请求，而且有时甚至没有ASPX页面，全是AJAX调用，所以我更看重AJAX。&lt;/p&gt;&lt;p&gt;二种请求（我称为通道）大致是这样的处理过程：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012021222060452.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;说明：示意图中并没有直观地反映出【页面请求】与【AJAX请求】在处理过程中的差别，但这个差别是存在的，差别主要在于从URL到Action的映射过程，后面会有详细地介绍。&lt;/p&gt;&lt;p&gt;以下示意图表示了【我的MVC框架】在处理一个请求时的具体过程：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012021222062872.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;b class="redText"&gt;今天的博客内容将主要介绍这个框架如何实现AJAX请求处理，页面请求的实现过程将在后续的博客中介绍。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;回忆以往AJAX的实现方式&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;我的MVC框架对AJAX的支持来源于我对代码不断重构的过程，为了更好地了解我的MVC框架，我认为有必要先来回忆一下以往是如何（在服务端）实现AJAX的。&lt;/p&gt;&lt;p&gt;在ASP.NET中有一种比较原始的实现Ajax的方式，那就是创建一个ashx，就像下面的代码：&lt;a href="javascript:void(0);" codeId="pre-simple-ashx"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;@ &lt;/span&gt;&lt;span style="color:#a31515"&gt;WebHandler &lt;/span&gt;&lt;span style="color:red"&gt;Language&lt;/span&gt;&lt;span style="color:blue"&gt;="C#" &lt;/span&gt;&lt;span style="color:red"&gt;Class&lt;/span&gt;&lt;span style="color:blue"&gt;="Handler1" &lt;/span&gt;&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;using &lt;/span&gt;System;&lt;br/&gt;&lt;span style="color:blue"&gt;using &lt;/span&gt;System&lt;span style="color:red"&gt;.&lt;/span&gt;Web;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Handler1 &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;{&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color:blue"&gt;public void &lt;/span&gt;ProcssRequest (&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context) {&lt;br/&gt;        &lt;span style="color:green"&gt;// 【1】. 从context.Request中读取输入参数&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:blue"&gt;string &lt;/span&gt;param1 &lt;span style="color:red"&gt;= &lt;/span&gt;context&lt;span style="color:red"&gt;.&lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;QueryString[&lt;span style="color:#a31515"&gt;"param1"&lt;/span&gt;];&lt;br/&gt;        &lt;span style="color:blue"&gt;string &lt;/span&gt;param2 &lt;span style="color:red"&gt;= &lt;/span&gt;context&lt;span style="color:red"&gt;.&lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;QueryString[&lt;span style="color:#a31515"&gt;"param2"&lt;/span&gt;];&lt;br/&gt;        &lt;br/&gt;        &lt;span style="color:green"&gt;// 【2】. 根据上面所获取的参数，调用服务层或者BLL层获取结果&lt;br/&gt;        // var result = CallXxxxMethod(param1, param2);&lt;br/&gt;&lt;br/&gt;        // 【3】. 将结果写入context.Response&lt;br/&gt;        &lt;/span&gt;context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;ContentType &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"text/plain"&lt;/span&gt;;&lt;br/&gt;        context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;" result ...... "&lt;/span&gt;);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public bool &lt;/span&gt;IsReusable { &lt;span style="color:blue"&gt;get &lt;/span&gt;{ &lt;span style="color:blue"&gt;return false&lt;/span&gt;; } }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;当然了，也有人会选择创建一个空的aspx去代替ashx，而且使用aspx还可以只输出一个HTML片段。&lt;/p&gt;&lt;p&gt;在这种原始的方式下，整个处理过程可以大致分为注释中所标注的三个阶段。如果使用这种方式去做服务端的AJAX开发，当AJAX的数量到达一定规模后，可以发现：&lt;b&gt;大量的代码是类似。&lt;/b&gt;我之所以称为【类似】，是因为它们却实有差别，差别在于：参数的名字不同，参数的类型不同，参数的个数不同，要调用的方法以及返回值不同。&lt;/p&gt;&lt;p&gt;说实话，这种机械代码我也写过。&lt;br /&gt;不过，当我发现时这个现象时，我就开始想办法去解决这个问题，因为我非常不喜欢写这类重复性质的代码。&lt;br /&gt;在重构过程中，也逐渐形成了我自己的AJAX服务端框架。&lt;br /&gt;后来我把它写到我的第一篇博客中了：&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/03/12/1982434.html" target="_blank"&gt;【晒晒我的Ajax服务端框架】&lt;/a&gt;&lt;/p&gt;&lt;p&gt;在AJAX的发展过程中，微软曾经推出过ASP.NET AJAX框架，它可以在服务端生成一些JS的代理类，让客户端的JS方便地调用服务端的方法。虽然那个框架设计地很巧妙，并且与WebForm配合地很完美，只可惜那个框架不够流行。后来的WCF通过一些配置也可以让JS去调用，不过，喜欢的人也不多，可能还是因为配置麻烦的缘故吧。当后来微软推出了ASP.NET MVC框架时，一些人开始惊呼：AJAX非ASP.NET MVC框架不可。因为ASP.NET MVC框架可以很容易让JS去调用一个C#方法，从此以后，再也不用去【读参数，调用方法，写输出】这些繁琐的事情了，而且没有WCF那么复杂的配置。的确，他们没有解决的问题，ASP.NET MVC框架很好地解决了。&lt;/p&gt;&lt;p&gt;今天的博客，我将向大家介绍我的AJAX解决方案，它同样可以很好的解决上面的那些繁琐的过程。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;MyMVC中实现AJAX的方式&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在我的框架中，服务端可以很容易地将一个C#方法公开给客户端的JavaScript来访问，比如下面这个C#方法：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;AjaxOrder&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;    &lt;span style="color:blue"&gt;public void &lt;/span&gt;AddOrder(&lt;span style="color:#2b91af"&gt;OrderSubmitForm &lt;/span&gt;form)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;Order &lt;/span&gt;order &lt;span style="color:red"&gt;= &lt;/span&gt;form&lt;span style="color:red"&gt;.&lt;/span&gt;ConvertToOrderItem();&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;BllFactory&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetOrderBLL()&lt;span style="color:red"&gt;.&lt;/span&gt;AddOrder(order);&lt;br/&gt;    }&lt;br/&gt;&lt;p&gt;那么客户端就可以通过这个URL地址来调用那个方法："/AjaxOrder/AddOrder.cspx" ，&lt;br /&gt;URL中的一些名称与C#类名以及方法的名称的对应关系，请参考下图。&lt;br /&gt;至于C#方法所需的参数，你就不用担心了，框架会替您准备好，你只要访问就可以了。&lt;br /&gt;说明：这个Action太简单了，连返回值也没有。后面会有返回值的示例代码，请继续阅读。&lt;/p&gt;&lt;p&gt;前面的示例可以用下面的图形来表示C#代码与URL的映射关系：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012021222064878.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;补充说明一下：按照MVC的标准术语，下文将这类用于处理请求的方法将称为【Action】，Action所在的类型称为Controller。不过，在我的MVC框架中，Action又分【PageAction】和【AjaxAction】。而且，在我的MVC框架中，&lt;b&gt;对Controller限制极少，不会要求您继承什么类型或者实现什么接口，Controller甚至可以是个静态类。&lt;/b&gt;&lt;br /&gt;唯独只要求：1. &lt;b&gt;包含AjaxAction的Controller必须以&lt;/b&gt;&lt;b class="redText"&gt;Ajax开头&lt;/b&gt;，&lt;b&gt;包含PageAction的Controller必须以&lt;/b&gt;&lt;b class="redText"&gt;Controller结尾&lt;/b&gt;（照顾喜欢微软MVC框架的用户）。加这个限制仅仅是为了快速定位Action，并没有其它原因。2. 类型与方法的可见性为 public （同样仅仅只是为了快速定位） 。&lt;br /&gt;所以，在我的框架中，&lt;b&gt;Controller的意义将只是一个Action的容器。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;如何使用MyMVC框架中的AJAX功能&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在我的MVC框架中，JS几乎可以透明地直接调用C#方法。比如我有这样一个C#方法：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;AjaxDemo&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;GetMd5(&lt;span style="color:blue"&gt;string &lt;/span&gt;input)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( input &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            input &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Empty;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;byte&lt;/span&gt;[] bb &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MD5CryptoServiceProvider&lt;/span&gt;())&lt;span style="color:red"&gt;.&lt;/span&gt;ComputeHash(&lt;span style="color:#2b91af"&gt;Encoding&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Default&lt;span style="color:red"&gt;.&lt;/span&gt;GetBytes(input));&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BitConverter&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;ToString(bb)&lt;span style="color:red"&gt;.&lt;/span&gt;Replace(&lt;span style="color:#a31515"&gt;"-"&lt;/span&gt;, &lt;span style="color:#a31515"&gt;""&lt;/span&gt;)&lt;span style="color:red"&gt;.&lt;/span&gt;ToLower();&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;方法很简单，可以计算一个字符串的MD5值。下面再来看一下如何在JS中调用：&lt;/p&gt;&lt;br/&gt;$(&lt;span style="color:#a31515"&gt;"#btnGetMd5"&lt;/span&gt;).click(&lt;span style="color:blue"&gt;function&lt;/span&gt;(){&lt;br/&gt;    $.ajax({&lt;br/&gt;        &lt;span style="color:green"&gt;// 以下二个URL地址都是有效的。&lt;br/&gt;        //url: "/AjaxDemo/GetMd5.cspx",&lt;br/&gt;        &lt;/span&gt;url&lt;span style="color:red"&gt;: &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/AjaxDemo.GetMd5.cspx"&lt;/span&gt;&lt;span style="color:red"&gt;,&lt;br/&gt;        &lt;/span&gt;data&lt;span style="color:red"&gt;: &lt;/span&gt;{input&lt;span style="color:red"&gt;: &lt;/span&gt;$(&lt;span style="color:#a31515"&gt;"#txtInput"&lt;/span&gt;).val()}&lt;span style="color:red"&gt;,&lt;br/&gt;        &lt;/span&gt;success&lt;span style="color:red"&gt;: &lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt;(responseText){&lt;br/&gt;            $(&lt;span style="color:#a31515"&gt;"#spanReslt"&lt;/span&gt;).text(responseText);&lt;br/&gt;        }&lt;br/&gt;    });&lt;br/&gt;});&lt;br/&gt;&lt;p&gt;说明一下：这里我使用JQuery这个JavaScript类库来完成客户端的部分。&lt;br /&gt;在JS代码中，我通过一个URL地址就可以直接访问到前面所定义的C#方法，C#方法所面的参数由$.ajax()的data参数指定。由于实在过于简单，我感觉不需要再对这个示例做更多的解释。&lt;/p&gt;&lt;p&gt;唯独我要提醒的是：为了安全，JS并不能调用任何一个C#方法（虽然在技术上没有任何难度）。所以，如果您允许一个C#方法公开给JS调用，那么方法必须加[Action]这个Attribute 。&lt;/p&gt;&lt;p&gt;在前面的示例中，方法的传入参数以及返回值的类型都比较简单，事实上，MyMVC也可以支持复杂的数据类型。例如，以下方法的签名都是有效的：&lt;a href="javascript:void(0);" codeId="pre-parameters"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public void &lt;/span&gt;Insert(&lt;span style="color:#2b91af"&gt;Customer &lt;/span&gt;customer)&lt;br/&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public object &lt;/span&gt;Delete(&lt;span style="color:blue"&gt;int &lt;/span&gt;id, &lt;span style="color:blue"&gt;string &lt;/span&gt;returnUrl)&lt;br/&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public object &lt;/span&gt;ShowCustomerPicker(&lt;span style="color:blue"&gt;string &lt;/span&gt;searchWord, &lt;span style="color:blue"&gt;int&lt;/span&gt;&lt;span style="color:red"&gt;? &lt;/span&gt;page)&lt;br/&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public object &lt;/span&gt;Search(&lt;span style="color:#2b91af"&gt;OrderSearchInfo &lt;/span&gt;info, &lt;span style="color:blue"&gt;int&lt;/span&gt;&lt;span style="color:red"&gt;? &lt;/span&gt;page)&lt;br/&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public object &lt;/span&gt;ShowProductPicker(&lt;span style="color:blue"&gt;int&lt;/span&gt;&lt;span style="color:red"&gt;? &lt;/span&gt;categoryId, &lt;span style="color:blue"&gt;string &lt;/span&gt;searchWord, &lt;span style="color:blue"&gt;int&lt;/span&gt;&lt;span style="color:red"&gt;? &lt;/span&gt;page)&lt;br/&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public object &lt;/span&gt;LoadModel()&lt;br/&gt;&lt;p&gt;有了MyMVC，就几乎上不需要再去访问QueryString，Form这些对象了。&lt;b&gt;你需要什么参数，只要写在方法的签名中就可以了。&lt;/b&gt;参数可以是简单的数据类型，也可以是自定义的数据类型，参数的个数也没有限制。&lt;/p&gt;&lt;p&gt;不过，有一点我要提醒您：所有的数据来源只有二个地方：QueryString和Form，框架只读取这二个地方，而且直接访问它们的索引器。由于QueryString，Form这二个类型都是NameValueCollection，而NameValueCollection的索引器在实现上有点独特，因此请大家注意它们的返回值。关于NameValueCollection的细节描述，可以参考我的博客&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/12/06/2278463.html" target="_blank"&gt;【细说 Request[]与Request.Params[]】&lt;/a&gt;，今天我就不再重谈这个细节话题了。&lt;/p&gt;&lt;p&gt;在读取参数时，万一出现key重复了怎么办？&lt;br /&gt;框架还提供另一种解决方案，那就是您可以在C#的方法的签名中，声明NameValueCollection类型的变量，变量名可以从【Form，QueryString，Headers，ServerVariables】中选择。注意：对于后二者，框架本身也是不读取的，如果需要读取，只能使用这个方法来获取。示例代码如下：&lt;a href="javascript:void(0);" codeId="pre-TestNameValueCollection"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public string &lt;/span&gt;TestNameValueCollection(&lt;span style="color:#2b91af"&gt;NameValueCollection &lt;/span&gt;queryString, &lt;span style="color:#2b91af"&gt;NameValueCollection &lt;/span&gt;form, &lt;br/&gt;    &lt;span style="color:#2b91af"&gt;NameValueCollection &lt;/span&gt;headers, &lt;span style="color:#2b91af"&gt;NameValueCollection &lt;/span&gt;serverVariables)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;StringBuilder &lt;/span&gt;sb &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;StringBuilder&lt;/span&gt;();&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:blue"&gt;string &lt;/span&gt;key &lt;span style="color:blue"&gt;in &lt;/span&gt;queryString&lt;span style="color:red"&gt;.&lt;/span&gt;AllKeys )&lt;br/&gt;        sb&lt;span style="color:red"&gt;.&lt;/span&gt;AppendFormat(&lt;span style="color:#a31515"&gt;"queryString, {0} = {1}\r\n"&lt;/span&gt;, key, queryString[key]);&lt;br/&gt;    &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:blue"&gt;string &lt;/span&gt;key &lt;span style="color:blue"&gt;in &lt;/span&gt;form&lt;span style="color:red"&gt;.&lt;/span&gt;AllKeys )&lt;br/&gt;        sb&lt;span style="color:red"&gt;.&lt;/span&gt;AppendFormat(&lt;span style="color:#a31515"&gt;"form, {0} = {1}\r\n"&lt;/span&gt;, key, form[key]);&lt;br/&gt;    &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:blue"&gt;string &lt;/span&gt;key &lt;span style="color:blue"&gt;in &lt;/span&gt;headers&lt;span style="color:red"&gt;.&lt;/span&gt;AllKeys )&lt;br/&gt;        sb&lt;span style="color:red"&gt;.&lt;/span&gt;AppendFormat(&lt;span style="color:#a31515"&gt;"headers, {0} = {1}\r\n"&lt;/span&gt;, key, headers[key]);&lt;br/&gt;    &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:blue"&gt;string &lt;/span&gt;key &lt;span style="color:blue"&gt;in &lt;/span&gt;serverVariables&lt;span style="color:red"&gt;.&lt;/span&gt;AllKeys )&lt;br/&gt;        sb&lt;span style="color:red"&gt;.&lt;/span&gt;AppendFormat(&lt;span style="color:#a31515"&gt;"serverVariables, {0} = {1}\r\n"&lt;/span&gt;, key, serverVariables[key]);&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;sb&lt;span style="color:red"&gt;.&lt;/span&gt;ToString();&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;代码中，我同时要求框架给出这四个集合，事实上，您可以根据实际情况来决定需要多少个参数。&lt;/p&gt;&lt;p&gt;注意：&lt;br /&gt;1. 参数名称是大小写【不敏感】的。&lt;br /&gt;2. 类型一定要求是NameValueCollection 。&lt;br /&gt;3. 框架会优先读取QueryString，如果没有则会查看Form&lt;br /&gt;4. 千万不要在Action中使用HttpContext.Current.Request.QueryString[]的方式读取来自客户端的参数。&lt;/p&gt;&lt;p&gt;关于参数，还有一种特殊的情况：我在博客&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/07/17/2108884.html" target="_blank"&gt;【细说 Form (表单)】&lt;/a&gt;中曾提到过，例如，我有这样二个类型，它们的结构一样：&lt;a href="javascript:void(0);" codeId="pre-Customer-Salesman-1"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Customer&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;Name;&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;Tel;&lt;br/&gt;}&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Salesman&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;Name { &lt;span style="color:blue"&gt;get&lt;/span&gt;; &lt;span style="color:blue"&gt;set&lt;/span&gt;; }&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;Tel { &lt;span style="color:blue"&gt;get&lt;/span&gt;; &lt;span style="color:blue"&gt;set&lt;/span&gt;; }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;如果此时我有这样一个C#方法，又该如何处理呢？&lt;a href="javascript:void(0);" codeId="pre-TestCustomerType"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public string &lt;/span&gt;TestCustomerType(&lt;span style="color:#2b91af"&gt;Customer &lt;/span&gt;customer, &lt;span style="color:#2b91af"&gt;Salesman &lt;/span&gt;salesman)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:#a31515"&gt;"customer.Name = " &lt;/span&gt;&lt;span style="color:red"&gt;+ &lt;/span&gt;customer&lt;span style="color:red"&gt;.&lt;/span&gt;Name &lt;span style="color:red"&gt;+ &lt;/span&gt;&lt;span style="color:#a31515"&gt;"\r\n" &lt;/span&gt;&lt;span style="color:red"&gt;+&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:#a31515"&gt;"customer.Tel = " &lt;/span&gt;&lt;span style="color:red"&gt;+ &lt;/span&gt;customer&lt;span style="color:red"&gt;.&lt;/span&gt;Tel &lt;span style="color:red"&gt;+ &lt;/span&gt;&lt;span style="color:#a31515"&gt;"\r\n" &lt;/span&gt;&lt;span style="color:red"&gt;+&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:#a31515"&gt;"salesman.Name = " &lt;/span&gt;&lt;span style="color:red"&gt;+ &lt;/span&gt;salesman&lt;span style="color:red"&gt;.&lt;/span&gt;Name &lt;span style="color:red"&gt;+ &lt;/span&gt;&lt;span style="color:#a31515"&gt;"\r\n" &lt;/span&gt;&lt;span style="color:red"&gt;+&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:#a31515"&gt;"salesman.Name = " &lt;/span&gt;&lt;span style="color:red"&gt;+ &lt;/span&gt;salesman&lt;span style="color:red"&gt;.&lt;/span&gt;Tel;&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;上面的示例也可以理解成：一模一样的参数类型，就是要出现多次，再或者，多个不同的自定义类型中，有些成员的名称是相同的。&lt;br /&gt;此时我的框架在设计时与微软的MVC框架一样，要求在HTML中对name做特殊的设置，示例代码如下：&lt;a href="javascript:void(0);" codeId="pre-TestCustomerType-html"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;form &lt;/span&gt;&lt;span style="color:red"&gt;action&lt;/span&gt;&lt;span style="color:blue"&gt;="/AjaxDemo2/TestCustomerType.cspx" &lt;/span&gt;&lt;span style="color:red"&gt;method&lt;/span&gt;&lt;span style="color:blue"&gt;="post"&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;客户名称: &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text" &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="customer.Name" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;: &lt;span style="color:blue"&gt;300px" /&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;客户电话: &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text" &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="customer.Tel" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;: &lt;span style="color:blue"&gt;300px" /&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;销售员名称: &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text" &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="salesman.Name" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;: &lt;span style="color:blue"&gt;300px" /&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;销售员电话: &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text" &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;="salesman.Tel" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;: &lt;span style="color:blue"&gt;300px" /&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="submit" &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="提交" /&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;form&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;此时要求：input标签中的name必须能够反映C#方法的参数名以及类型中所包含的数据成员名称。&lt;/p&gt;&lt;p&gt;&lt;b class="redText"&gt;注意：在MyMVC框架中，自定义的数据类型所包含的数据成员不要求是属性，字段(Field)也是完全受支持的。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;配置MyMVC框架&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;MyMVC框架在使用前，必须配置。&lt;br /&gt;在前面的示例中，"/AjaxDemo2/TestCustomerType.cspx" 这样的URL地址，按照ASP.NET的默认设置，它是不能被映射到一个有效的处理器的，那时，将出现一个404异常。因此，为了使用MyMVC中对AJAX的支持，必须做以下配置：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;add &lt;/span&gt;&lt;span style="color:red"&gt;path&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*Ajax*/*.cspx,*Ajax*.*.cspx&lt;/span&gt;" &lt;span style="color:red"&gt;verb&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*&lt;/span&gt;" &lt;br/&gt;                                &lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;MyMVC.AjaxHandlerFactory, MyMVC&lt;/span&gt;" &lt;span style="color:red"&gt;validate&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;true&lt;/span&gt;"&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;如果在IIS7的环境中运行，还需要以下配置：&lt;a href="javascript:void(0);" codeId="pre-AjaxHandlerFactory-iis7"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;system.webServer&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;validation &lt;/span&gt;&lt;span style="color:red"&gt;validateIntegratedModeConfiguration&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;false&lt;/span&gt;"&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;security&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;requestFiltering&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;            &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;fileExtensions&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;                &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;remove &lt;/span&gt;&lt;span style="color:red"&gt;fileExtension&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;.cspx&lt;/span&gt;"&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;                &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;add &lt;/span&gt;&lt;span style="color:red"&gt;fileExtension&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;.cspx&lt;/span&gt;" &lt;span style="color:red"&gt;allowed&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;true&lt;/span&gt;"&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;            &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;fileExtensions&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;requestFiltering&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;security&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;handlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;add &lt;/span&gt;&lt;span style="color:red"&gt;name&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;AjaxHandlerFactory&lt;/span&gt;" &lt;span style="color:red"&gt;verb&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*&lt;/span&gt;" &lt;span style="color:red"&gt;path&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*Ajax*/*.cspx&lt;/span&gt;" &lt;br/&gt;                        &lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;MyMVC.AjaxHandlerFactory, MyMVC&lt;/span&gt;" &lt;span style="color:red"&gt;preCondition&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;integratedMode&lt;/span&gt;"&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;handlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;system.webServer&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;在示例代码中，我使用了【cspx】这个扩展名，如果您不喜欢，也可以选择您所喜欢的扩展名，这个不是问题。&lt;/p&gt;&lt;p&gt;关于配置参数中的【path】属性，请参考我的上篇博客&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/01/29/2331477.html" target="_blank"&gt;【细说 HttpHandler 的映射过程】&lt;/a&gt;，这里也不再重新解释。如果没有看过的，建议还是去看一下，下面将会用到那些知识，因为它非常重要。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;MyMVC框架的实现原理 - 映射处理器（入口）&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;前面谈到了MyMVC框架的配置，通过那个配置，相当于在ASP.NET中为MyMVC注册了一个入口点。&lt;/p&gt;&lt;p&gt;根据上面的配置，符合条件的请求将会被映射给AjaxHandlerFactory。既然是这样，我们来看一下这个入口点的实现代码：&lt;a href="javascript:void(0);" codeId="pre-AjaxHandlerFactory"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal sealed class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;AjaxHandlerFactory &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IHttpHandlerFactory&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;GetHandler(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context,&lt;br/&gt;                        &lt;span style="color:blue"&gt;string &lt;/span&gt;requestType, &lt;span style="color:blue"&gt;string &lt;/span&gt;virtualPath, &lt;span style="color:blue"&gt;string &lt;/span&gt;physicalPath)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:green"&gt;// 根据请求路径，定位到要执行的Action&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ControllerActionPair &lt;/span&gt;pair &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;UrlParser&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;ParseAjaxUrl(virtualPath);&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( pair &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;ExceptionHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Throw404Exception(context);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 获取内部表示的调用信息&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:#2b91af"&gt;InvokeInfo &lt;/span&gt;vkInfo &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ReflectionHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetAjaxInvokeInfo(pair);&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( vkInfo &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;ExceptionHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Throw404Exception(context);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 创建能够调用Action的HttpHandler&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ActionHandler&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;CreateHandler(vkInfo);&lt;br/&gt;    }&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color:blue"&gt;public void &lt;/span&gt;ReleaseHandler(&lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;handler)&lt;br/&gt;    {&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;代码中，每个步骤做了什么事情，注释中有说明，不需要再重复说明。最后创建的ActionHandler的实现代码如下：&lt;a href="javascript:void(0);" codeId="pre-ActionHandler"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ActionHandler &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IHttpHandler&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;internal &lt;/span&gt;&lt;span style="color:#2b91af"&gt;InvokeInfo &lt;/span&gt;InvokeInfo;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public void &lt;/span&gt;ProcessRequest(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:green"&gt;// 调用核心的工具类，执行Action&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ActionExecutor&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;ExecuteAction(context, &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;InvokeInfo);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public bool &lt;/span&gt;IsReusable&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;get &lt;/span&gt;{ &lt;span style="color:blue"&gt;return false&lt;/span&gt;; }&lt;br/&gt;    }&lt;br/&gt;&lt;p&gt;整个入口点就是这样的。&lt;br /&gt;有没人想过：为什么不直接在web.config中映射到这个ActionHandler呢？&lt;br /&gt;答案在后面，请继续阅读。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;MyMVC框架的实现原理 - 对Session的支持&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;前面有一个方法的实现我故意没有贴出，那么是ActionHandler.CreateHandler()这个静态方法。现在是时候来贴它了：&lt;a href="javascript:void(0);" codeId="pre-CreateHandler"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ActionHandler &lt;/span&gt;CreateHandler(&lt;span style="color:#2b91af"&gt;InvokeInfo &lt;/span&gt;vkInfo)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;SessionMode &lt;/span&gt;mode &lt;span style="color:red"&gt;= &lt;/span&gt;vkInfo&lt;span style="color:red"&gt;.&lt;/span&gt;GetSessionMode();&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( mode &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:#2b91af"&gt;SessionMode&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;NotSupport )&lt;br/&gt;        &lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ActionHandler &lt;/span&gt;{ InvokeInfo &lt;span style="color:red"&gt;= &lt;/span&gt;vkInfo };&lt;br/&gt;    &lt;span style="color:blue"&gt;else if&lt;/span&gt;( mode &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:#2b91af"&gt;SessionMode&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;ReadOnly )&lt;br/&gt;        &lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ReadOnlySessionActionHandler &lt;/span&gt;{ InvokeInfo &lt;span style="color:red"&gt;= &lt;/span&gt;vkInfo };&lt;br/&gt;    &lt;span style="color:blue"&gt;else&lt;br/&gt;        return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;RequiresSessionActionHandler &lt;/span&gt;{ InvokeInfo &lt;span style="color:red"&gt;= &lt;/span&gt;vkInfo };&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;这段代码又涉及另外二个类型，它们的实现代码如下：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;RequiresSessionActionHandler &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;ActionHandler&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;IRequiresSessionState&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ReadOnlySessionActionHandler &lt;/span&gt;: &lt;br/&gt;                        &lt;span style="color:#2b91af"&gt;ActionHandler&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;IRequiresSessionState&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;IReadOnlySessionState&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;不要感到奇怪，这二个类型的确没有任何代码。&lt;/p&gt;&lt;p&gt;它们除了从ActionHandler继承而来，还实现了另外二个接口，那二个接口我在博客&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/07/31/2123191.html" target="_blank"&gt;【Session，有没有必要使用它？】&lt;/a&gt;中已有详细的解释，不明白的朋友，可以去阅读那篇博客。&lt;/p&gt;&lt;p&gt;再来回答前面那个问题：&lt;b&gt;为什么不直接在web.config中映射到这个ActionHandler呢？&lt;/b&gt;&lt;br /&gt;答：如果这样配置，那么对Session的支持将只有一种模式！&lt;br /&gt;在这个框架中，我采用HttpHandlerFactory就可以轻松地实现对多种Session模式的支持。&lt;br /&gt;说到这里，我真的感觉上篇博客&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/01/29/2331477.html" target="_blank"&gt;【细说 HttpHandler 的映射过程】&lt;/a&gt;的研究成果太有意义了，是它给【MyMVC对Session完美的支持】提供了灵感。&lt;/p&gt;&lt;p&gt;老实说：我是不使用Session的。&lt;br /&gt;但看到以前的博客中有些人还是坚持使用Session，所以就决定在MyMVC中支持这个功能，毕竟支持Session不是件难事。&lt;/p&gt;&lt;p&gt;下面再来说说如何支持Session 。&lt;a href="javascript:void(0);" codeId="pre-TestSessionMode"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;SessionMode&lt;/span&gt;(&lt;span style="color:#2b91af"&gt;SessionMode&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Support)]&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public int &lt;/span&gt;TestSessionMode(&lt;span style="color:blue"&gt;int &lt;/span&gt;a)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;// 一个累加的方法，检验是否可以访问Session&lt;br/&gt;    // 警告：示例代码的这样做法会影响Action的单元测试。&lt;br/&gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( System&lt;span style="color:red"&gt;.&lt;/span&gt;Web&lt;span style="color:red"&gt;.&lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpContext&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Current&lt;span style="color:red"&gt;.&lt;/span&gt;Session &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;        &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;InvalidOperationException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"Session没有开启。"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;object &lt;/span&gt;obj &lt;span style="color:red"&gt;= &lt;/span&gt;System&lt;span style="color:red"&gt;.&lt;/span&gt;Web&lt;span style="color:red"&gt;.&lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpContext&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Current&lt;span style="color:red"&gt;.&lt;/span&gt;Session[&lt;span style="color:#a31515"&gt;"counter"&lt;/span&gt;];&lt;br/&gt;    &lt;span style="color:blue"&gt;int &lt;/span&gt;counter &lt;span style="color:red"&gt;= &lt;/span&gt;(obj &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;&lt;span style="color:red"&gt;? &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;: (&lt;span style="color:blue"&gt;int&lt;/span&gt;)obj);&lt;br/&gt;    counter &lt;span style="color:red"&gt;+= &lt;/span&gt;a;&lt;br/&gt;    System&lt;span style="color:red"&gt;.&lt;/span&gt;Web&lt;span style="color:red"&gt;.&lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpContext&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Current&lt;span style="color:red"&gt;.&lt;/span&gt;Session[&lt;span style="color:#a31515"&gt;"counter"&lt;/span&gt;] &lt;span style="color:red"&gt;= &lt;/span&gt;counter;&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;counter;&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;p&gt;在上面这段代码中，我加了一个[SessionMode]的Attribute，用它可以指定Action的Session支持模式，SessionMode是个枚举值，定义如下：&lt;a href="javascript:void(0);" codeId="pre-SessionMode-enum"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;Action所支持的Session模式&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public enum &lt;/span&gt;&lt;span style="color:#2b91af"&gt;SessionMode&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;不支持&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;NotSupport,&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;全支持&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;Support,&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;仅支持读取&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;ReadOnly&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;MyMVC框架支持以上三种不同的Session模式，默认是关闭的，如果需要使用，请显式指定。[SessionMode]既可以用于Controller类型，也可以用于Action 。&lt;/p&gt;&lt;p&gt;&lt;b&gt;注意：&lt;/b&gt;Session的使用将会给Action的单元测试带来麻烦。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;MyMVC框架的实现原理 - 对OutputCache的支持&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;MyMVC框架对OutputCache也有着很好的支持。下面的代码演示了如何使用OutputCache：&lt;/p&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;OutputCache&lt;/span&gt;(Duration&lt;span style="color:red"&gt;=&lt;/span&gt;&lt;span style="color:purple"&gt;10&lt;/span&gt;, VaryByParam&lt;span style="color:red"&gt;=&lt;/span&gt;&lt;span style="color:#a31515"&gt;"none"&lt;/span&gt;)]&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public string &lt;/span&gt;TestOutputCache()&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DateTime&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Now&lt;span style="color:red"&gt;.&lt;/span&gt;ToString();&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;如果在浏览器中访问这个地址：http://localhost:34743/AjaxDemo/TestOutputCache.cspx&lt;br /&gt;会发现结果在10秒钟内不会有改变（F5刷新），如果打开Fiddler2，会看到304的响应。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012021222071544.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;[OutputCache]所支持的属性较多，这里就不一一列出了，下面再来说说它的实现原理。&lt;/p&gt;&lt;p&gt;我在博客&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/01/11/2320027.html" target="_blank"&gt;【细说 ASP.NET控制HTTP缓存】&lt;/a&gt;曾分析过ASP.NET Page的缓存页实现原理，其中有个小节【缓存页的服务端编程】专门分析了Page对OutputCache的实现过程，在MyMVC中，就是使用的这种方法，具体过程可以参考那篇博客。补充一句：微软的ASP.NET MVC也是这样做的，它也是借助了Page的强大功能。&lt;/p&gt;&lt;p&gt;MyMVC中的代码：&lt;a href="javascript:void(0);" codeId="pre-OutputCacheAttribute"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;AttributeUsage&lt;/span&gt;(&lt;span style="color:#2b91af"&gt;AttributeTargets&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Class &lt;span style="color:red"&gt;| &lt;/span&gt;&lt;span style="color:#2b91af"&gt;AttributeTargets&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Method, AllowMultiple &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;false&lt;/span&gt;)]&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;OutputCacheAttribute &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;Attribute&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;OutputCacheParameters &lt;/span&gt;_cacheSettings &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;OutputCacheParameters&lt;/span&gt;();&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 略过一些属性。&lt;br/&gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;internal void &lt;/span&gt;SetResponseCache(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( context &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"context"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;OutputCachedPage &lt;/span&gt;page &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;OutputCachedPage&lt;/span&gt;(_cacheSettings);&lt;br/&gt;        page&lt;span style="color:red"&gt;.&lt;/span&gt;ProcessRequest(context);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;private sealed class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;OutputCachedPage &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;Page&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;OutputCacheParameters &lt;/span&gt;_cacheSettings;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;public &lt;/span&gt;OutputCachedPage(&lt;span style="color:#2b91af"&gt;OutputCacheParameters &lt;/span&gt;cacheSettings)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;ID &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Guid&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;NewGuid()&lt;span style="color:red"&gt;.&lt;/span&gt;ToString();&lt;br/&gt;            _cacheSettings &lt;span style="color:red"&gt;= &lt;/span&gt;cacheSettings;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;protected override void &lt;/span&gt;FrameworkInitialize()&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;base&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;FrameworkInitialize();&lt;br/&gt;            InitOutputCache(_cacheSettings);&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;在OutputCacheAttribute类的用法中，清楚地指出适用于类型与方法，因此，这个Attribute可以用于Controller和Action 。&lt;/p&gt;&lt;p&gt;说明：OutputCacheAttribute与SessionModeAttribute类似，都可以用于Controller和Action，同时使用时，Action优先匹配，代码如下：&lt;a href="javascript:void(0);" codeId="pre-GetOutputCacheSetting"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal sealed class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;InvokeInfo&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ControllerDescription &lt;/span&gt;Controller;&lt;br/&gt;    &lt;span style="color:blue"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ActionDescription &lt;/span&gt;Action;&lt;br/&gt;    &lt;span style="color:blue"&gt;public object &lt;/span&gt;Instance;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af"&gt;OutputCacheAttribute &lt;/span&gt;GetOutputCacheSetting()&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Action &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;&lt;span style="color:red"&gt;&amp;amp;&amp;amp; &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Action&lt;span style="color:red"&gt;.&lt;/span&gt;OutputCache &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;return this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Action&lt;span style="color:red"&gt;.&lt;/span&gt;OutputCache;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Controller &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;&lt;span style="color:red"&gt;&amp;amp;&amp;amp; &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Controller&lt;span style="color:red"&gt;.&lt;/span&gt;OutputCache &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;return this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Controller&lt;span style="color:red"&gt;.&lt;/span&gt;OutputCache;            &lt;br/&gt;        &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af"&gt;SessionMode &lt;/span&gt;GetSessionMode()&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Action &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;&lt;span style="color:red"&gt;&amp;amp;&amp;amp; &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Action&lt;span style="color:red"&gt;.&lt;/span&gt;SessionMode &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;return this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Action&lt;span style="color:red"&gt;.&lt;/span&gt;SessionMode&lt;span style="color:red"&gt;.&lt;/span&gt;SessionMode;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Controller &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;&lt;span style="color:red"&gt;&amp;amp;&amp;amp; &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Controller&lt;span style="color:red"&gt;.&lt;/span&gt;SessionMode &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;return this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Controller&lt;span style="color:red"&gt;.&lt;/span&gt;SessionMode&lt;span style="color:red"&gt;.&lt;/span&gt;SessionMode;            &lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:#2b91af"&gt;SessionMode&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;NotSupport;&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;因此，框架只要选择一个时机调用SetResponseCache()方法就可以了，至于这个调用时机出现在哪里，请继续阅读。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;MyMVC框架的实现原理 - 查找Action的过程&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;前面有张图片反映了从URL地址到Action的映射过程：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012021222064878.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;下面再来谈谈这个过程的实现。&lt;br /&gt;首先，我们要先在web.config中注册MyMVC的HttpHandlerFactory，它是整个框架的入口。&lt;br /&gt;在ASP.NET的管线过程中，会调用GetHandler()方法，终于我的代码有机会运行了！&lt;br /&gt;框架执行的第一行代码是：&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:green"&gt;// 根据请求路径，定位到要执行的Action&lt;br/&gt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ControllerActionPair &lt;/span&gt;pair &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;UrlParser&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;ParseAjaxUrl(virtualPath);&lt;br/&gt;&lt;br/&gt;&lt;p&gt;ControllerActionPair是我定义的一个表示Controller以及Action名字的值对类型：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public sealed class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ControllerActionPair&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;Controller;&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;Action;&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;静态方法UrlParser.ParseAjaxUrl()就是专门用来解析URL并返回ControllerActionPair的：&lt;a href="javascript:void(0);" codeId="pre-UrlParser"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal static class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;UrlParser&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;// 用于匹配Ajax请求的正则表达式，&lt;br/&gt;    // 可以匹配的URL：/AjaxClass/method.cspx?id=2&lt;br/&gt;    // 注意：类名必须Ajax做为前缀&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;internal static readonly string &lt;/span&gt;AjaxUrlPattern&lt;br/&gt;        &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;@"/(?&amp;lt;name&amp;gt;(\w[\./\w]*)?(?=Ajax)\w+)[/\.](?&amp;lt;method&amp;gt;\w+)\.[a-zA-Z]+"&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ControllerActionPair &lt;/span&gt;ParseAjaxUrl(&lt;span style="color:blue"&gt;string &lt;/span&gt;path)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(path) )&lt;br/&gt;            &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"path"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;Match &lt;/span&gt;match &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Regex&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Match(path, AjaxUrlPattern);&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( match&lt;span style="color:red"&gt;.&lt;/span&gt;Success &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ControllerActionPair &lt;/span&gt;{&lt;br/&gt;            Controller &lt;span style="color:red"&gt;= &lt;/span&gt;match&lt;span style="color:red"&gt;.&lt;/span&gt;Groups[&lt;span style="color:#a31515"&gt;"name"&lt;/span&gt;]&lt;span style="color:red"&gt;.&lt;/span&gt;Value&lt;span style="color:red"&gt;.&lt;/span&gt;Replace(&lt;span style="color:#a31515"&gt;"/"&lt;/span&gt;, &lt;span style="color:#a31515"&gt;"."&lt;/span&gt;),&lt;br/&gt;            Action &lt;span style="color:red"&gt;= &lt;/span&gt;match&lt;span style="color:red"&gt;.&lt;/span&gt;Groups[&lt;span style="color:#a31515"&gt;"method"&lt;/span&gt;]&lt;span style="color:red"&gt;.&lt;/span&gt;Value&lt;br/&gt;        };&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;代码很简单，核心其实就是那个正则表达式，从URL中提取Controller，Action的名字全靠它。&lt;br /&gt;至于正则表达式的使用，我想这是个基本功，这里就略过了。&lt;/p&gt;&lt;p&gt;再来看AjaxHandlerFactory的第二个调用：&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:green"&gt;// 获取内部表示的调用信息&lt;br/&gt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;InvokeInfo &lt;/span&gt;vkInfo &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ReflectionHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetAjaxInvokeInfo(pair);&lt;br/&gt;&lt;br/&gt;&lt;p&gt;ReflectionHelper类是一个内部使用的工具类，专门用于反射处理，AjaxAction查找过程的相关代码如下（注意代码中的注释）：&lt;a href="javascript:void(0);" codeId="pre-ReflectionHelper"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal static class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ReflectionHelper&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 保存AjaxController的列表&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;private static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ControllerDescription&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;s_AjaxControllerList;&lt;br/&gt;    &lt;span style="color:green"&gt;// 保存AjaxAction的字典&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;private static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Hashtable &lt;/span&gt;s_AjaxActionTable &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Hashtable&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Synchronized(&lt;br/&gt;                                        &lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Hashtable&lt;/span&gt;(&lt;span style="color:purple"&gt;4096&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;StringComparer&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;OrdinalIgnoreCase));&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 用于从类型查找Action的反射标记&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;private static readonly &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BindingFlags &lt;/span&gt;ActionBindingFlags &lt;span style="color:red"&gt;=&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BindingFlags&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Static &lt;span style="color:red"&gt;| &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BindingFlags&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Instance &lt;span style="color:red"&gt;| &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BindingFlags&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Public &lt;span style="color:red"&gt;| &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BindingFlags&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IgnoreCase;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;static &lt;/span&gt;ReflectionHelper()&lt;br/&gt;    {&lt;br/&gt;        InitControllers();&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;加载所有的Controller&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;private static void &lt;/span&gt;InitControllers()&lt;br/&gt;    {&lt;br/&gt;        s_AjaxControllerList &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;ControllerDescription&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt;&lt;/span&gt;(&lt;span style="color:purple"&gt;1024&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;ICollection &lt;/span&gt;assemblies &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BuildManager&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetReferencedAssemblies();&lt;br/&gt;        &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;Assembly &lt;/span&gt;assembly &lt;span style="color:blue"&gt;in &lt;/span&gt;assemblies ) {&lt;br/&gt;            &lt;span style="color:green"&gt;// 过滤以【System.】开头的程序集，加快速度&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( assembly&lt;span style="color:red"&gt;.&lt;/span&gt;FullName&lt;span style="color:red"&gt;.&lt;/span&gt;StartsWith(&lt;span style="color:#a31515"&gt;"System."&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;StringComparison&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;OrdinalIgnoreCase) )&lt;br/&gt;                &lt;span style="color:blue"&gt;continue&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:blue"&gt;try &lt;/span&gt;{&lt;br/&gt;                &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;Type &lt;/span&gt;t &lt;span style="color:blue"&gt;in &lt;/span&gt;assembly&lt;span style="color:red"&gt;.&lt;/span&gt;GetExportedTypes() ) {&lt;br/&gt;                    &lt;span style="color:blue"&gt;if&lt;/span&gt;( t&lt;span style="color:red"&gt;.&lt;/span&gt;Name&lt;span style="color:red"&gt;.&lt;/span&gt;StartsWith(&lt;span style="color:#a31515"&gt;"Ajax"&lt;/span&gt;) )&lt;br/&gt;                        s_AjaxControllerList&lt;span style="color:red"&gt;.&lt;/span&gt;Add(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ControllerDescription&lt;/span&gt;(t));&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;            &lt;span style="color:blue"&gt;catch &lt;/span&gt;{ }&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 用于Ajax调用的Action信息则采用延迟加载的方式。&lt;br/&gt;    &lt;/span&gt;}&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;根据要调用的controller名返回对应的Controller （适用于Ajax调用）&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    /// &amp;lt;param name="controller"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;private static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ControllerDescription &lt;/span&gt;GetAjaxController(&lt;span style="color:blue"&gt;string &lt;/span&gt;controller)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(controller) )&lt;br/&gt;            &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"controller"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 查找类型的方式：如果有点号，则按全名来查找(包含命名空间)，否则只看名字。&lt;br/&gt;        // 本框架对于多个匹配条件的类型，将返回第一个匹配项。&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( controller&lt;span style="color:red"&gt;.&lt;/span&gt;IndexOf(&lt;span style="color:#a31515"&gt;'.'&lt;/span&gt;) &lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;s_AjaxControllerList&lt;span style="color:red"&gt;.&lt;/span&gt;FirstOrDefault(&lt;br/&gt;                t &lt;span style="color:red"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Compare(t&lt;span style="color:red"&gt;.&lt;/span&gt;ControllerType&lt;span style="color:red"&gt;.&lt;/span&gt;FullName, controller, &lt;span style="color:blue"&gt;true&lt;/span&gt;) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;);&lt;br/&gt;        &lt;span style="color:blue"&gt;else&lt;br/&gt;            return &lt;/span&gt;s_AjaxControllerList&lt;span style="color:red"&gt;.&lt;/span&gt;FirstOrDefault(&lt;br/&gt;                t &lt;span style="color:red"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Compare(t&lt;span style="color:red"&gt;.&lt;/span&gt;ControllerType&lt;span style="color:red"&gt;.&lt;/span&gt;Name, controller, &lt;span style="color:blue"&gt;true&lt;/span&gt;) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;根据要调用的方法名返回对应的 Action （适用于Ajax调用）&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    /// &amp;lt;param name="controller"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;    /// &amp;lt;param name="action"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;private static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ActionDescription &lt;/span&gt;GetAjaxAction(&lt;span style="color:#2b91af"&gt;Type &lt;/span&gt;controller, &lt;span style="color:blue"&gt;string &lt;/span&gt;action)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( controller &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"controller"&lt;/span&gt;);&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(action) )&lt;br/&gt;            &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"action"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 首先尝试从缓存中读取&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:blue"&gt;string &lt;/span&gt;key &lt;span style="color:red"&gt;= &lt;/span&gt;action &lt;span style="color:red"&gt;+ &lt;/span&gt;&lt;span style="color:#a31515"&gt;"@" &lt;/span&gt;&lt;span style="color:red"&gt;+ &lt;/span&gt;controller&lt;span style="color:red"&gt;.&lt;/span&gt;FullName;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;ActionDescription &lt;/span&gt;mi &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;ActionDescription&lt;/span&gt;)s_AjaxActionTable[key];&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( mi &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) {&lt;br/&gt;            &lt;span style="color:green"&gt;// 注意：这里不考虑方法的重载。&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MethodInfo &lt;/span&gt;method &lt;span style="color:red"&gt;= &lt;/span&gt;controller&lt;span style="color:red"&gt;.&lt;/span&gt;GetMethod(action, ActionBindingFlags);&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( method &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;                &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:blue"&gt;var &lt;/span&gt;attrs &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;ActionAttribute&lt;/span&gt;[])method&lt;span style="color:red"&gt;.&lt;/span&gt;GetCustomAttributes(&lt;span style="color:blue"&gt;typeof&lt;/span&gt;(&lt;span style="color:#2b91af"&gt;ActionAttribute&lt;/span&gt;), &lt;span style="color:blue"&gt;false&lt;/span&gt;);&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( attrs&lt;span style="color:red"&gt;.&lt;/span&gt;Length &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:purple"&gt;1 &lt;/span&gt;)&lt;br/&gt;                &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;            &lt;br/&gt;            mi &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ActionDescription&lt;/span&gt;(method, attrs[&lt;span style="color:purple"&gt;0&lt;/span&gt;]);&lt;br/&gt;            s_AjaxActionTable[key] &lt;span style="color:red"&gt;= &lt;/span&gt;mi;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;mi;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;根据一个AJAX的调用信息（类名与方法名），返回内部表示的调用信息。&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    /// &amp;lt;param name="pair"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;public static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;InvokeInfo &lt;/span&gt;GetAjaxInvokeInfo(&lt;span style="color:#2b91af"&gt;ControllerActionPair &lt;/span&gt;pair)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( pair &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"pair"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;InvokeInfo &lt;/span&gt;vkInfo &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;InvokeInfo&lt;/span&gt;();&lt;br/&gt;&lt;br/&gt;        vkInfo&lt;span style="color:red"&gt;.&lt;/span&gt;Controller &lt;span style="color:red"&gt;= &lt;/span&gt;GetAjaxController(pair&lt;span style="color:red"&gt;.&lt;/span&gt;Controller);&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( vkInfo&lt;span style="color:red"&gt;.&lt;/span&gt;Controller &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        vkInfo&lt;span style="color:red"&gt;.&lt;/span&gt;Action &lt;span style="color:red"&gt;= &lt;/span&gt;GetAjaxAction(vkInfo&lt;span style="color:red"&gt;.&lt;/span&gt;Controller&lt;span style="color:red"&gt;.&lt;/span&gt;ControllerType, pair&lt;span style="color:red"&gt;.&lt;/span&gt;Action);&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( vkInfo&lt;span style="color:red"&gt;.&lt;/span&gt;Action &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;        &lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( vkInfo&lt;span style="color:red"&gt;.&lt;/span&gt;Action&lt;span style="color:red"&gt;.&lt;/span&gt;MethodInfo&lt;span style="color:red"&gt;.&lt;/span&gt;IsStatic &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;)&lt;br/&gt;            vkInfo&lt;span style="color:red"&gt;.&lt;/span&gt;Instance &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Activator&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;CreateInstance(vkInfo&lt;span style="color:red"&gt;.&lt;/span&gt;Controller&lt;span style="color:red"&gt;.&lt;/span&gt;ControllerType);&lt;br/&gt;        &lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;vkInfo;&lt;br/&gt;    }&lt;br/&gt;&lt;p&gt;上面就是AjaxAction查找相关的4段代码：&lt;br /&gt;1. 在ReflectionHelper的静态构造函数中，我加载了所有AjaxController。&lt;br /&gt;2. GetAjaxController方法用于根据一个Controller的名字返回Controller的类型描述。&lt;br /&gt;3. GetAjaxAction方法用于根据Controller的类型以及要调用的Action的名字返回Action的描述信息。&lt;br /&gt;4. GetAjaxInvokeInfo方法用于根据从AjaxHandlerFactory得到的ControllerActionPair描述转成更具体的描述信息。&lt;/p&gt;&lt;p&gt;代码中，Action的查找过程采用了延迟的加载模式，保存Action描述信息的集合我采用了线程安全的Hashtable&lt;/p&gt;&lt;p&gt;好了，上面那段代码我想说的就这些，剩下的就只些反射的使用，这也算是个基本功，而且也不是三言二语能说清楚的。因此，我打算继续谈其它的内容了。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;MyMVC框架的实现原理 - 执行Action的过程&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在AjaxHandlerFactory的GetHandler方法中，最后将创建一个ActionHandler，这是一个HttpHandler，它将在管线的第15个步骤中被调用（引用博客&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/09/05/2168073.html" target="_blank"&gt;【用Asp.net写自己的服务框架】&lt;/a&gt;中的顺序）。&lt;/p&gt;&lt;p&gt;注意：AjaxHandlerFactory的GetHandler方法是在第10步中调用的，第12步就是在准备Session（非进程内模式），因此，必须在第12步前决定Session的使用方式。&lt;/p&gt;&lt;p&gt;所有的Action代码都是在ActionHandler中执行的：&lt;a href="javascript:void(0);" codeId="pre-ActionHandler-ProcessRequest"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ActionHandler &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IHttpHandler&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;internal &lt;/span&gt;&lt;span style="color:#2b91af"&gt;InvokeInfo &lt;/span&gt;InvokeInfo;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public void &lt;/span&gt;ProcessRequest(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:green"&gt;// 调用核心的工具类，执行Action&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ActionExecutor&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;ExecuteAction(context, &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;InvokeInfo);&lt;br/&gt;    }&lt;br/&gt;&lt;p&gt;ExecuteAction的实现过程如下：&lt;a href="javascript:void(0);" codeId="pre-ExecuteAction"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal static void &lt;/span&gt;ExecuteAction(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context, &lt;span style="color:#2b91af"&gt;InvokeInfo &lt;/span&gt;vkInfo)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( context &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;        &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"context"&lt;/span&gt;);&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( vkInfo &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;        &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"vkInfo"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 调用方法&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;object &lt;/span&gt;result &lt;span style="color:red"&gt;= &lt;/span&gt;ExecuteActionInternal(context, vkInfo);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 设置OutputCache&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#2b91af"&gt;OutputCacheAttribute &lt;/span&gt;outputCache &lt;span style="color:red"&gt;= &lt;/span&gt;vkInfo&lt;span style="color:red"&gt;.&lt;/span&gt;GetOutputCacheSetting();&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( outputCache &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;        outputCache&lt;span style="color:red"&gt;.&lt;/span&gt;SetResponseCache(context);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 处理方法的返回结果&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IActionResult &lt;/span&gt;executeResult &lt;span style="color:red"&gt;= &lt;/span&gt;result &lt;span style="color:blue"&gt;as &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IActionResult&lt;/span&gt;;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( executeResult &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) {&lt;br/&gt;        executeResult&lt;span style="color:red"&gt;.&lt;/span&gt;Ouput(context);&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;else &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( result &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) {&lt;br/&gt;            &lt;span style="color:green"&gt;// 普通类型结果&lt;br/&gt;            &lt;/span&gt;context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;ContentType &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"text/plain"&lt;/span&gt;;&lt;br/&gt;            context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Write(result&lt;span style="color:red"&gt;.&lt;/span&gt;ToString());&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal static object &lt;/span&gt;ExecuteActionInternal(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context, &lt;span style="color:#2b91af"&gt;InvokeInfo &lt;/span&gt;info)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;// 准备要传给调用方法的参数&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;object&lt;/span&gt;[] parameters &lt;span style="color:red"&gt;= &lt;/span&gt;GetActionCallParameters(context, info&lt;span style="color:red"&gt;.&lt;/span&gt;Action);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 调用方法&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( info&lt;span style="color:red"&gt;.&lt;/span&gt;Action&lt;span style="color:red"&gt;.&lt;/span&gt;HasReturn )&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;info&lt;span style="color:red"&gt;.&lt;/span&gt;Action&lt;span style="color:red"&gt;.&lt;/span&gt;MethodInfo&lt;span style="color:red"&gt;.&lt;/span&gt;Invoke(info&lt;span style="color:red"&gt;.&lt;/span&gt;Instance, parameters);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;else &lt;/span&gt;{&lt;br/&gt;        info&lt;span style="color:red"&gt;.&lt;/span&gt;Action&lt;span style="color:red"&gt;.&lt;/span&gt;MethodInfo&lt;span style="color:red"&gt;.&lt;/span&gt;Invoke(info&lt;span style="color:red"&gt;.&lt;/span&gt;Instance, parameters);&lt;br/&gt;        &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;前面我不是没有说调用SetResponseCache()的时机嘛，这个时机就是在这里：执行完Action后。&lt;br /&gt;设置过OutputCache后，就是处理返回值了。&lt;/p&gt;&lt;p&gt;前面那段代码中，还有一句重要的调用：&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:green"&gt;// 准备要传给调用方法的参数&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;object&lt;/span&gt;[] parameters &lt;span style="color:red"&gt;= &lt;/span&gt;GetActionCallParameters(context, info&lt;span style="color:red"&gt;.&lt;/span&gt;Action);&lt;br/&gt;&lt;br/&gt;&lt;p&gt;这个调用的意义在注释中有解释，关于这个过程的实现方式还请继续阅读。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;MyMVC框架的实现原理 - 如何给方法赋值&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;用过反射的人都知道，调用一个方法很简单，但如何给一个【不知签名】的方法准备传入参数呢？&lt;br /&gt;下面就来回答这个问题，请接着看GetActionCallParameters的实现过程：&lt;a href="javascript:void(0);" codeId="pre-GetActionCallParameters"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;private static object&lt;/span&gt;[] GetActionCallParameters(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context, &lt;span style="color:#2b91af"&gt;ActionDescription &lt;/span&gt;action)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( action&lt;span style="color:red"&gt;.&lt;/span&gt;Parameters &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;&lt;span style="color:red"&gt;|| &lt;/span&gt;action&lt;span style="color:red"&gt;.&lt;/span&gt;Parameters&lt;span style="color:red"&gt;.&lt;/span&gt;Length &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;)&lt;br/&gt;        &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;object&lt;/span&gt;[] parameters &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new object&lt;/span&gt;[action&lt;span style="color:red"&gt;.&lt;/span&gt;Parameters&lt;span style="color:red"&gt;.&lt;/span&gt;Length];&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;for&lt;/span&gt;( &lt;span style="color:blue"&gt;int &lt;/span&gt;i &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;; i &lt;span style="color:red"&gt;&amp;lt; &lt;/span&gt;action&lt;span style="color:red"&gt;.&lt;/span&gt;Parameters&lt;span style="color:red"&gt;.&lt;/span&gt;Length; i&lt;span style="color:red"&gt;++ &lt;/span&gt;) {&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;ParameterInfo &lt;/span&gt;p &lt;span style="color:red"&gt;= &lt;/span&gt;action&lt;span style="color:red"&gt;.&lt;/span&gt;Parameters[i];&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( p&lt;span style="color:red"&gt;.&lt;/span&gt;IsOut )&lt;br/&gt;            &lt;span style="color:blue"&gt;continue&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( p&lt;span style="color:red"&gt;.&lt;/span&gt;ParameterType &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;typeof&lt;/span&gt;(&lt;span style="color:#2b91af"&gt;NameValueCollection&lt;/span&gt;) ) {&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Compare(p&lt;span style="color:red"&gt;.&lt;/span&gt;Name, &lt;span style="color:#a31515"&gt;"Form"&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;StringComparison&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;OrdinalIgnoreCase) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;)&lt;br/&gt;                parameters[i] &lt;span style="color:red"&gt;= &lt;/span&gt;context&lt;span style="color:red"&gt;.&lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;Form;&lt;br/&gt;            &lt;span style="color:blue"&gt;else if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Compare(p&lt;span style="color:red"&gt;.&lt;/span&gt;Name, &lt;span style="color:#a31515"&gt;"QueryString"&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;StringComparison&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;OrdinalIgnoreCase) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;)&lt;br/&gt;                parameters[i] &lt;span style="color:red"&gt;= &lt;/span&gt;context&lt;span style="color:red"&gt;.&lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;QueryString;&lt;br/&gt;            &lt;span style="color:blue"&gt;else if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Compare(p&lt;span style="color:red"&gt;.&lt;/span&gt;Name, &lt;span style="color:#a31515"&gt;"Headers"&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;StringComparison&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;OrdinalIgnoreCase) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;)&lt;br/&gt;                parameters[i] &lt;span style="color:red"&gt;= &lt;/span&gt;context&lt;span style="color:red"&gt;.&lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;Headers;&lt;br/&gt;            &lt;span style="color:blue"&gt;else if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Compare(p&lt;span style="color:red"&gt;.&lt;/span&gt;Name, &lt;span style="color:#a31515"&gt;"ServerVariables"&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;StringComparison&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;OrdinalIgnoreCase) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;)&lt;br/&gt;                parameters[i] &lt;span style="color:red"&gt;= &lt;/span&gt;context&lt;span style="color:red"&gt;.&lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;ServerVariables;&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color:blue"&gt;else&lt;/span&gt;{&lt;br/&gt;            &lt;span style="color:#2b91af"&gt;Type &lt;/span&gt;paramterType &lt;span style="color:red"&gt;= &lt;/span&gt;p&lt;span style="color:red"&gt;.&lt;/span&gt;ParameterType&lt;span style="color:red"&gt;.&lt;/span&gt;GetRealType();&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:green"&gt;// 如果参数是简单类型，则直接从HttpRequest中读取并赋值&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( paramterType&lt;span style="color:red"&gt;.&lt;/span&gt;IsSimpleType() ) {&lt;br/&gt;                &lt;span style="color:blue"&gt;object &lt;/span&gt;val &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ModelHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetValueByKeyAndTypeFrommRequest(&lt;br/&gt;                                                context&lt;span style="color:red"&gt;.&lt;/span&gt;Request, p&lt;span style="color:red"&gt;.&lt;/span&gt;Name, paramterType, &lt;span style="color:blue"&gt;null&lt;/span&gt;);&lt;br/&gt;                &lt;span style="color:blue"&gt;if&lt;/span&gt;( val &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;                    parameters[i] &lt;span style="color:red"&gt;= &lt;/span&gt;val;&lt;br/&gt;            }&lt;br/&gt;            &lt;span style="color:blue"&gt;else &lt;/span&gt;{&lt;br/&gt;                &lt;span style="color:green"&gt;// 自定义的类型。首先创建实例，然后给所有成员赋值。&lt;br/&gt;                // 注意：这里不支持嵌套类型的自定义类型。&lt;br/&gt;                &lt;/span&gt;&lt;span style="color:blue"&gt;object &lt;/span&gt;item &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Activator&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;CreateInstance(paramterType);&lt;br/&gt;                &lt;span style="color:#2b91af"&gt;ModelHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;FillModel(context&lt;span style="color:red"&gt;.&lt;/span&gt;Request, item, p&lt;span style="color:red"&gt;.&lt;/span&gt;Name);&lt;br/&gt;                parameters[i] &lt;span style="color:red"&gt;= &lt;/span&gt;item;&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;parameters;&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;要理解这段代码还要从前面的【查找Action的过程】说起，在那个阶段，可以获取一个Action的描述，具体在框架内部表示为ActionDescription类型：&lt;a href="javascript:void(0);" codeId="pre-ActionDescription"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal sealed class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ActionDescription &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;BaseDescription&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ControllerDescription &lt;/span&gt;PageController; &lt;span style="color:green"&gt;//为PageAction保留&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MethodInfo &lt;/span&gt;MethodInfo { &lt;span style="color:blue"&gt;get&lt;/span&gt;; &lt;span style="color:blue"&gt;private set&lt;/span&gt;; }&lt;br/&gt;    &lt;span style="color:blue"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ActionAttribute &lt;/span&gt;Attr { &lt;span style="color:blue"&gt;get&lt;/span&gt;; &lt;span style="color:blue"&gt;private set&lt;/span&gt;; }&lt;br/&gt;    &lt;span style="color:blue"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ParameterInfo&lt;/span&gt;[] Parameters { &lt;span style="color:blue"&gt;get&lt;/span&gt;; &lt;span style="color:blue"&gt;private set&lt;/span&gt;; }&lt;br/&gt;    &lt;span style="color:blue"&gt;public bool &lt;/span&gt;HasReturn { &lt;span style="color:blue"&gt;get&lt;/span&gt;; &lt;span style="color:blue"&gt;private set&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public &lt;/span&gt;ActionDescription(&lt;span style="color:#2b91af"&gt;MethodInfo &lt;/span&gt;m, &lt;span style="color:#2b91af"&gt;ActionAttribute &lt;/span&gt;atrr) : &lt;span style="color:blue"&gt;base&lt;/span&gt;(m)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;MethodInfo &lt;span style="color:red"&gt;= &lt;/span&gt;m;&lt;br/&gt;        &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Attr &lt;span style="color:red"&gt;= &lt;/span&gt;atrr;&lt;br/&gt;        &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Parameters &lt;span style="color:red"&gt;= &lt;/span&gt;m&lt;span style="color:red"&gt;.&lt;/span&gt;GetParameters();&lt;br/&gt;        &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;HasReturn &lt;span style="color:red"&gt;= &lt;/span&gt;m&lt;span style="color:red"&gt;.&lt;/span&gt;ReturnType &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ReflectionHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;VoidType;&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;在构造函数的第三行代码中，我就可以得到这个方法的所有参数情况。&lt;br /&gt;然后，我在就可以在GetActionCallParameters方法中，循环每个参数的定义，为它们赋值。&lt;br /&gt;这段代码也解释了前面所说的只支持4种NameValueCollection集合的原因。&lt;/p&gt;&lt;p&gt;注意了，我在获取每个参数的类型时，是使用了下面的语句：&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:#2b91af"&gt;Type &lt;/span&gt;paramterType &lt;span style="color:red"&gt;= &lt;/span&gt;p&lt;span style="color:red"&gt;.&lt;/span&gt;ParameterType&lt;span style="color:red"&gt;.&lt;/span&gt;GetRealType();&lt;br/&gt;&lt;br/&gt;&lt;p&gt;实际上，ParameterType就已经反映了参数的类型，为什么不直接使用它呢？&lt;br /&gt;答：因为【可空泛型】的原因。这个类型我们需要特殊的处理。&lt;br /&gt;例如：如果某个参数是这样声明的： int? id &lt;br /&gt;那么，即使在QueryString中包含id这样一个参数，我也不能直接转成 int?  使用这种类型，必须得到它的【实际类型】。&lt;br /&gt;GetRealType()是个扩展方法，它就专门完成这个功能：&lt;a href="javascript:void(0);" codeId="pre-GetRealType"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;得到一个实际的类型（排除Nullable类型的影响）。比如：int? 最后将得到int&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;/// &amp;lt;param name="type"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Type &lt;/span&gt;GetRealType(&lt;span style="color:blue"&gt;this &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Type &lt;/span&gt;type)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( type&lt;span style="color:red"&gt;.&lt;/span&gt;IsGenericType )&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Nullable&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetUnderlyingType(type) &lt;span style="color:red"&gt;?? &lt;/span&gt;type;&lt;br/&gt;    &lt;span style="color:blue"&gt;else&lt;br/&gt;        return &lt;/span&gt;type;&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;如果某个参数的类型是一个自定义的类型，框架会先创建实例（调用无参的构造函数），然后给它的Property, Field赋值。&lt;/p&gt;&lt;p&gt;注意了：自定义的类型，一定要提供一个无参的构造函数。&lt;/p&gt;&lt;p&gt;为自定义类型的实例填充数据成员的代码如下：&lt;a href="javascript:void(0);" codeId="pre-ModelHelper"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal static class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ModelHelper&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;public static readonly bool &lt;/span&gt;IsDebugMode;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;static &lt;/span&gt;ModelHelper()&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;CompilationSection &lt;/span&gt;configSection &lt;span style="color:red"&gt;= &lt;br/&gt;                    &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ConfigurationManager&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetSection(&lt;span style="color:#a31515"&gt;"system.web/compilation"&lt;/span&gt;) &lt;span style="color:blue"&gt;as &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CompilationSection&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( configSection &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            IsDebugMode &lt;span style="color:red"&gt;= &lt;/span&gt;configSection&lt;span style="color:red"&gt;.&lt;/span&gt;Debug;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;根据HttpRequest填充一个数据实体。&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;这里不支持嵌套类型的数据实体，且要求各数据成员都是简单的数据类型。&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    /// &amp;lt;param name="request"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;    /// &amp;lt;param name="model"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;public static void &lt;/span&gt;FillModel(&lt;span style="color:#2b91af"&gt;HttpRequest &lt;/span&gt;request, &lt;span style="color:blue"&gt;object &lt;/span&gt;model, &lt;span style="color:blue"&gt;string &lt;/span&gt;paramName)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;ModelDescripton &lt;/span&gt;descripton &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ReflectionHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetModelDescripton(model&lt;span style="color:red"&gt;.&lt;/span&gt;GetType());&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;object &lt;/span&gt;val &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color:blue"&gt;foreach&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;DataMember &lt;/span&gt;field &lt;span style="color:blue"&gt;in &lt;/span&gt;descripton&lt;span style="color:red"&gt;.&lt;/span&gt;Fields ) {&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:green"&gt;// 这里的实现方式不支持嵌套类型的数据实体。&lt;br/&gt;            // 如果有这方面的需求，可以将这里改成递归的嵌套调用。&lt;br/&gt;&lt;br/&gt;            &lt;/span&gt;val &lt;span style="color:red"&gt;= &lt;/span&gt;GetValueByKeyAndTypeFrommRequest(&lt;br/&gt;                                request, field&lt;span style="color:red"&gt;.&lt;/span&gt;Name, field&lt;span style="color:red"&gt;.&lt;/span&gt;Type&lt;span style="color:red"&gt;.&lt;/span&gt;GetRealType(), paramName);&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( val &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;                field&lt;span style="color:red"&gt;.&lt;/span&gt;SetValue(model, val);&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// &lt;/span&gt;&lt;span style="color:green"&gt;读取一个HTTP参数值。这里只读取QueryString以及Form&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;    /// &amp;lt;param name="request"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;    /// &amp;lt;param name="key"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;public static string &lt;/span&gt;GetHttpValue(&lt;span style="color:#2b91af"&gt;HttpRequest &lt;/span&gt;request, &lt;span style="color:blue"&gt;string &lt;/span&gt;key)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;string &lt;/span&gt;val &lt;span style="color:red"&gt;= &lt;/span&gt;request&lt;span style="color:red"&gt;.&lt;/span&gt;QueryString[key];&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( val &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            val &lt;span style="color:red"&gt;= &lt;/span&gt;request&lt;span style="color:red"&gt;.&lt;/span&gt;Form[key];&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;val;&lt;br/&gt;    }&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color:blue"&gt;public static object &lt;/span&gt;GetValueByKeyAndTypeFrommRequest(&lt;br/&gt;                        &lt;span style="color:#2b91af"&gt;HttpRequest &lt;/span&gt;request, &lt;span style="color:blue"&gt;string &lt;/span&gt;key, &lt;span style="color:#2b91af"&gt;Type &lt;/span&gt;type, &lt;span style="color:blue"&gt;string &lt;/span&gt;paramName)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:green"&gt;// 不支持复杂类型&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( type&lt;span style="color:red"&gt;.&lt;/span&gt;IsSimpleType() &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;string &lt;/span&gt;val &lt;span style="color:red"&gt;= &lt;/span&gt;GetHttpValue(request, key);&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( val &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) {&lt;br/&gt;            &lt;span style="color:green"&gt;// 再试一次。有可能是多个自定义类型，Form表单元素采用变量名做为前缀。&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;IsNullOrEmpty(paramName) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;) {&lt;br/&gt;                val &lt;span style="color:red"&gt;= &lt;/span&gt;GetHttpValue(request, paramName &lt;span style="color:red"&gt;+ &lt;/span&gt;&lt;span style="color:#a31515"&gt;"." &lt;/span&gt;&lt;span style="color:red"&gt;+ &lt;/span&gt;key);&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( val &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;                &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;SafeChangeType(val&lt;span style="color:red"&gt;.&lt;/span&gt;Trim(), type);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public static object &lt;/span&gt;SafeChangeType(&lt;span style="color:blue"&gt;string &lt;/span&gt;value, &lt;span style="color:#2b91af"&gt;Type &lt;/span&gt;conversionType)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( conversionType &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;typeof&lt;/span&gt;(&lt;span style="color:blue"&gt;string&lt;/span&gt;) )&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;value;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( value &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;&lt;span style="color:red"&gt;|| &lt;/span&gt;value&lt;span style="color:red"&gt;.&lt;/span&gt;Length &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:purple"&gt;0 &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:green"&gt;// 空字符串根本不能做任何转换，所以直接返回null&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;try &lt;/span&gt;{&lt;br/&gt;            &lt;span style="color:green"&gt;// 为了简单，直接调用 .net framework中的方法。&lt;br/&gt;            // 如果转换失败，则会抛出异常。&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Convert&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;ChangeType(value, conversionType);&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color:blue"&gt;catch &lt;/span&gt;{&lt;br/&gt;            &lt;span style="color:blue"&gt;if&lt;/span&gt;( IsDebugMode )&lt;br/&gt;                &lt;span style="color:blue"&gt;throw&lt;/span&gt;;            &lt;span style="color:green"&gt;// Debug 模式下抛异常&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:blue"&gt;else&lt;br/&gt;                return null&lt;/span&gt;;    &lt;span style="color:green"&gt;// Release模式下忽略异常（防止恶意用户错误输入）&lt;br/&gt;        &lt;/span&gt;}&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;在给自定义的数据类型实例加载数据前，需要先知道这个实例对象有哪些属性以及字段，这个过程的代码如下：&lt;a href="javascript:void(0);" codeId="pre-GetModelDescripton"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;返回一个实体类型的描述信息（全部属性及字段）。&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;/// &amp;lt;param name="type"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ModelDescripton &lt;/span&gt;GetModelDescripton(&lt;span style="color:#2b91af"&gt;Type &lt;/span&gt;type)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( type &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;        &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"type"&lt;/span&gt;);&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color:blue"&gt;string &lt;/span&gt;key &lt;span style="color:red"&gt;= &lt;/span&gt;type&lt;span style="color:red"&gt;.&lt;/span&gt;FullName;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;ModelDescripton &lt;/span&gt;mm &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;ModelDescripton&lt;/span&gt;)s_modelTable[key];&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( mm &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) {&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;DataMember&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;list &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;List&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;DataMember&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt;&lt;/span&gt;();&lt;br/&gt;&lt;br/&gt;        (&lt;span style="color:blue"&gt;from &lt;/span&gt;p &lt;span style="color:blue"&gt;in &lt;/span&gt;type&lt;span style="color:red"&gt;.&lt;/span&gt;GetProperties(&lt;span style="color:#2b91af"&gt;BindingFlags&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Instance &lt;span style="color:red"&gt;| &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BindingFlags&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Public)&lt;br/&gt;         &lt;span style="color:blue"&gt;select new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;PropertyMember&lt;/span&gt;(p))&lt;span style="color:red"&gt;.&lt;/span&gt;ToList()&lt;span style="color:red"&gt;.&lt;/span&gt;ForEach(x&lt;span style="color:red"&gt;=&amp;gt;&lt;/span&gt;list&lt;span style="color:red"&gt;.&lt;/span&gt;Add(x));&lt;br/&gt;&lt;br/&gt;        (&lt;span style="color:blue"&gt;from &lt;/span&gt;f &lt;span style="color:blue"&gt;in &lt;/span&gt;type&lt;span style="color:red"&gt;.&lt;/span&gt;GetFields(&lt;span style="color:#2b91af"&gt;BindingFlags&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Instance &lt;span style="color:red"&gt;| &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BindingFlags&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Public)&lt;br/&gt;         &lt;span style="color:blue"&gt;select new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;FieldMember&lt;/span&gt;(f))&lt;span style="color:red"&gt;.&lt;/span&gt;ToList()&lt;span style="color:red"&gt;.&lt;/span&gt;ForEach(x &lt;span style="color:red"&gt;=&amp;gt; &lt;/span&gt;list&lt;span style="color:red"&gt;.&lt;/span&gt;Add(x));&lt;br/&gt;&lt;br/&gt;        mm &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ModelDescripton &lt;/span&gt;{ Fields &lt;span style="color:red"&gt;= &lt;/span&gt;list&lt;span style="color:red"&gt;.&lt;/span&gt;ToArray() };&lt;br/&gt;        s_modelTable[key] &lt;span style="color:red"&gt;= &lt;/span&gt;mm;&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;mm;&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;在拿到一个类型的所有属性以及字段的描述信息后，就可以通过循环的方式，根据这些数据成员的名字去QueryString，Form读取所需的数据了。&lt;/p&gt;&lt;p&gt;参数准备好了，前面的调用就应该没有问题了吧？&lt;/p&gt;&lt;p&gt;&lt;strong&gt;MyMVC框架的实现原理 - 处理返回值&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;MyMVC框架处理返回值的时机是在ExecuteAction方法中（前面有那段代码）。&lt;br /&gt;这里只做个简单的补充说明。&lt;/p&gt;&lt;p&gt;我为Action的结果定义了一个接口：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public interface &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IActionResult&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;void &lt;/span&gt;Ouput(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context);&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;框架内实现了4种ActionResult：&lt;a href="javascript:void(0);" codeId="pre-ActionResult"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;表示一个用户控件结果（用户控件将由框架执行）&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public sealed class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;UcResult &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IActionResult&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;表示一个重定向的结果&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public sealed class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;RedirectResult &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IActionResult&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;一个Json对象结果&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public sealed class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;JsonResult &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IActionResult&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;表示一个页面结果（页面将由框架执行）&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public sealed class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;PageResult &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IActionResult&lt;/span&gt;&lt;br/&gt;&lt;p&gt;要输出返回值的时候，不仅使用了IActionResult接口，我还使用下面这个调用：&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Write(result&lt;span style="color:red"&gt;.&lt;/span&gt;ToString());&lt;br/&gt;&lt;br/&gt;&lt;p&gt;不要小看了ToString()的调用。&lt;br /&gt;对于自定义的数据类型来说，可以用它来控制最终输出给客户端的是JSON或者是XML，或者是您自己定义的文本序列化格式（比如：特殊分隔符拼接而成），因此，它有足够的能力可以取代JsonResult类型，而且同样不影响Action的单元测试。&lt;br /&gt;ToString()的强大原因在于它是个虚方法，可以被派生类重写。&lt;/p&gt;&lt;p&gt;所以，如果您只打算返回一个数据实体对象给客户端，那么既可以实现IActionResult接口，还可以重写ToString方法。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;MyMVC框架的实现原理 - 如何返回HTML片段&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;AJAX调用中，虽然以返回数据居多，但有时也会要求返回一段HTML，毕竟拼HTML代码在服务端会容易些。&lt;/p&gt;&lt;p&gt;MyMVC提供UcResult类型，用来将一个用户控件的呈现结果做为HTML输出。当然了，您也可以创建一个Page，采用Page来输出HTML，那么就要用到PageResult类型了。它们的使用代码如下：&lt;a href="javascript:void(0);" codeId="pre-ShowCustomerPicker"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public object &lt;/span&gt;ShowCustomerPicker(&lt;span style="color:blue"&gt;string &lt;/span&gt;searchWord, &lt;span style="color:blue"&gt;int&lt;/span&gt;&lt;span style="color:red"&gt;? &lt;/span&gt;page)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;CustomerSearchInfo &lt;/span&gt;info &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CustomerSearchInfo&lt;/span&gt;();&lt;br/&gt;    info&lt;span style="color:red"&gt;.&lt;/span&gt;SearchWord &lt;span style="color:red"&gt;= &lt;/span&gt;searchWord &lt;span style="color:red"&gt;?? &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Empty;&lt;br/&gt;    info&lt;span style="color:red"&gt;.&lt;/span&gt;PageIndex &lt;span style="color:red"&gt;= &lt;/span&gt;page&lt;span style="color:red"&gt;.&lt;/span&gt;HasValue &lt;span style="color:red"&gt;? &lt;/span&gt;page&lt;span style="color:red"&gt;.&lt;/span&gt;Value &lt;span style="color:red"&gt;- &lt;/span&gt;&lt;span style="color:purple"&gt;1 &lt;/span&gt;: &lt;span style="color:purple"&gt;0&lt;/span&gt;;&lt;br/&gt;    info&lt;span style="color:red"&gt;.&lt;/span&gt;PageSize &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;AppHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;DefaultPageSize;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;CustomerPickerModel &lt;/span&gt;data &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;CustomerPickerModel&lt;/span&gt;();&lt;br/&gt;    data&lt;span style="color:red"&gt;.&lt;/span&gt;SearchInfo &lt;span style="color:red"&gt;= &lt;/span&gt;info;&lt;br/&gt;    data&lt;span style="color:red"&gt;.&lt;/span&gt;List &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BllFactory&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetCustomerBLL()&lt;span style="color:red"&gt;.&lt;/span&gt;GetList(info);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;UcResult&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"/Controls/Style1/CustomerPicker.ascx"&lt;/span&gt;, data);&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;由于我从来不用Page输出一段HTML，因此没有准备在Ajax中使用PageResult的示例。但是，它们的使用方法是一样，因为：PageResult和UcResult的构造函数有着一致的签名方式。&lt;/p&gt;&lt;p&gt;再来说说创建UcResult对象那行代码：传入二个参数，第一个参数表示用户控件的位置（View），第二个参数表示呈现用户控件所需的数据（Model）。至于这个地方为什么要设计二个参数，请关注我的后续博客，因为它涉及到MVC的核心思想，今天的博客不打算谈这个话题。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;MyMVC框架的实现原理 - 多命名空间的支持&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;前面的示例代码都是演示了如何设计一个能供JS调用的Action，事实上，您也看到了，其实就是加了个[Action]的方法而已，没有其它的特别之处了。不过，在现实开发中，类型的名字可能会冲突。比如：.NET就引入了命名空间来处理这种冲突的类名。&lt;/p&gt;&lt;p&gt;MyMVC支持同名的Controller的名字吗？&lt;br /&gt;答案是肯定的：支持。&lt;/p&gt;&lt;p&gt;例如，我有下面二个类型。注意它们的名字是相同的。&lt;a href="javascript:void(0);" codeId="pre-namespace"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;namespace &lt;/span&gt;Fish&lt;span style="color:red"&gt;.&lt;/span&gt;AA&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;AjaxTest&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;public int &lt;/span&gt;Add(&lt;span style="color:blue"&gt;int &lt;/span&gt;a, &lt;span style="color:blue"&gt;int &lt;/span&gt;b)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;a &lt;span style="color:red"&gt;+ &lt;/span&gt;b;&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;namespace &lt;/span&gt;Fish&lt;span style="color:red"&gt;.&lt;/span&gt;BB&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;AddInfo&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color:blue"&gt;public int &lt;/span&gt;A;&lt;br/&gt;        &lt;span style="color:blue"&gt;public int &lt;/span&gt;B;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;AjaxTest&lt;br/&gt;    &lt;/span&gt;{&lt;br/&gt;        [&lt;span style="color:#2b91af"&gt;Action&lt;/span&gt;]&lt;br/&gt;        &lt;span style="color:blue"&gt;public int &lt;/span&gt;Add(&lt;span style="color:#2b91af"&gt;AddInfo &lt;/span&gt;info)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;info&lt;span style="color:red"&gt;.&lt;/span&gt;A &lt;span style="color:red"&gt;+ &lt;/span&gt;info&lt;span style="color:red"&gt;.&lt;/span&gt;B &lt;span style="color:red"&gt;+ &lt;/span&gt;&lt;span style="color:purple"&gt;10&lt;/span&gt;;    &lt;span style="color:green"&gt;// 故意写错。&lt;br/&gt;        &lt;/span&gt;}&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;这二个类型不仅同名，而且还包含了同名的方法。（事实上，方法的签名也可以完全一样。）&lt;/p&gt;&lt;p&gt;那么，对于这种情况，JS如何去调用它们呢？&lt;/p&gt;&lt;p&gt;为了回答这个问题，我特意准备了一个示例，HTML代码如下：&lt;a href="javascript:void(0);" codeId="pre-namespace-html"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;fieldset&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;legend&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;Fish.AA.AjaxTest.Add&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;legend&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text" &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="txtA1" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;: &lt;span style="color:blue"&gt;50px" &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="3" /&amp;gt; &lt;/span&gt;+&lt;br/&gt;    &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text" &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="txtB1" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;: &lt;span style="color:blue"&gt;50px" &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="2" /&amp;gt; &lt;/span&gt;=&lt;br/&gt;    &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;span &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="spanResult1"&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;span&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="button" &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="btnAdd1" &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="Add" /&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;fieldset&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;fieldset&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;legend&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;Fish.BB.AjaxTest.Add&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;legend&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text" &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="txtA2" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;: &lt;span style="color:blue"&gt;50px" &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="3" /&amp;gt; &lt;/span&gt;+&lt;br/&gt;    &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="text" &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="txtB2" &lt;/span&gt;&lt;span style="color:red"&gt;style&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="color:red"&gt;width&lt;/span&gt;: &lt;span style="color:blue"&gt;50px" &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="2" /&amp;gt; &lt;/span&gt;=&lt;br/&gt;    &lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;span &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="spanResult2"&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;span&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;input &lt;/span&gt;&lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;="button" &lt;/span&gt;&lt;span style="color:red"&gt;id&lt;/span&gt;&lt;span style="color:blue"&gt;="btnAdd2" &lt;/span&gt;&lt;span style="color:red"&gt;value&lt;/span&gt;&lt;span style="color:blue"&gt;="Add" /&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;fieldset&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;客户端的JS代码如下：&lt;a href="javascript:void(0);" codeId="pre-namespace-js"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;$(&lt;span style="color:blue"&gt;function&lt;/span&gt;(){&lt;br/&gt;    $(&lt;span style="color:#a31515"&gt;"#btnAdd1"&lt;/span&gt;).click(&lt;span style="color:blue"&gt;function&lt;/span&gt;(){&lt;br/&gt;        $.ajax({&lt;br/&gt;            url&lt;span style="color:red"&gt;: &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/Fish.AA.AjaxTest/Add.cspx"&lt;/span&gt;&lt;span style="color:red"&gt;,&lt;br/&gt;            &lt;/span&gt;data&lt;span style="color:red"&gt;: &lt;/span&gt;{a&lt;span style="color:red"&gt;: &lt;/span&gt;$(&lt;span style="color:#a31515"&gt;"#txtA1"&lt;/span&gt;).val()&lt;span style="color:red"&gt;, &lt;/span&gt;b&lt;span style="color:red"&gt;: &lt;/span&gt;$(&lt;span style="color:#a31515"&gt;"#txtB1"&lt;/span&gt;).val()}&lt;span style="color:red"&gt;,&lt;br/&gt;            &lt;/span&gt;success&lt;span style="color:red"&gt;: &lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt;(responseText){&lt;br/&gt;                $(&lt;span style="color:#a31515"&gt;"#spanResult1"&lt;/span&gt;).text(responseText);&lt;br/&gt;            }&lt;br/&gt;        });&lt;br/&gt;    });&lt;br/&gt;    &lt;br/&gt;    $(&lt;span style="color:#a31515"&gt;"#btnAdd2"&lt;/span&gt;).click(&lt;span style="color:blue"&gt;function&lt;/span&gt;(){&lt;br/&gt;        $.ajax({&lt;br/&gt;            &lt;span style="color:green"&gt;// 以下二个URL地址都是有效的。&lt;br/&gt;            //url: "/Fish.BB.AjaxTest.Add.cspx",&lt;br/&gt;            &lt;/span&gt;url&lt;span style="color:red"&gt;: &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/Fish/BB/AjaxTest/Add.cspx"&lt;/span&gt;&lt;span style="color:red"&gt;,&lt;br/&gt;            &lt;/span&gt;data&lt;span style="color:red"&gt;: &lt;/span&gt;{a&lt;span style="color:red"&gt;: &lt;/span&gt;$(&lt;span style="color:#a31515"&gt;"#txtA2"&lt;/span&gt;).val()&lt;span style="color:red"&gt;, &lt;/span&gt;b&lt;span style="color:red"&gt;: &lt;/span&gt;$(&lt;span style="color:#a31515"&gt;"#txtB2"&lt;/span&gt;).val()}&lt;span style="color:red"&gt;,&lt;br/&gt;            &lt;/span&gt;success&lt;span style="color:red"&gt;: &lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt;(responseText){&lt;br/&gt;                $(&lt;span style="color:#a31515"&gt;"#spanResult2"&lt;/span&gt;).text(responseText);&lt;br/&gt;            }&lt;br/&gt;        });&lt;br/&gt;    });&lt;br/&gt;});&lt;br/&gt;&lt;p&gt;最终的调用结果如下：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012021222074144.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;注意：&lt;b&gt;下方的调用结果虽然是错误的，但表示调用的方法是正确的。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;让我们再来回顾一下UrlParser类中定义的那个正则表达式吧：&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal static readonly string &lt;/span&gt;AjaxUrlPattern&lt;br/&gt;    &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;@"/(?&amp;lt;name&amp;gt;(\w[\./\w]*)?(?=Ajax)\w+)[/\.](?&amp;lt;method&amp;gt;\w+)\.[a-zA-Z]+"&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;它可以解析这些格式的URL：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:green"&gt;/*&lt;br/&gt;    可以解析以下格式的URL：（前三个表示包含命名空间的）&lt;br/&gt;&lt;br/&gt;    /Fish.AA.AjaxTest/Add.cspx&lt;br/&gt;    /Fish.BB.AjaxTest.Add.cspx&lt;br/&gt;    /Fish/BB/AjaxTest/Add.cspx&lt;br/&gt;    /AjaxDemo/GetMd5.cspx&lt;br/&gt;    /AjaxDemo.GetMd5.cspx&lt;br/&gt;*/&lt;/span&gt;&lt;br/&gt;&lt;p&gt;值得说明的是：这个正则表达式并没有限定用什么样的扩展名，而且也不限制URL中的查询字符串参数。&lt;/p&gt;&lt;p&gt;但是，就算它再强大，还需要在web.config中注册时，要保证匹配的URL能被传入，否则代码根本没有机会运行。&lt;/p&gt;&lt;p&gt;重温httpHandlers的注册：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;add &lt;/span&gt;&lt;span style="color:red"&gt;path&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*Ajax*/*.cspx,*Ajax*.*.cspx&lt;/span&gt;" &lt;span style="color:red"&gt;verb&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*&lt;/span&gt;" &lt;br/&gt;            &lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;MyMVC.AjaxHandlerFactory, MyMVC&lt;/span&gt;" &lt;span style="color:red"&gt;validate&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;true&lt;/span&gt;"&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;感谢微软的天才设计，让我可以用通配符的方式写正则表达式。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;关于反射的使用&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;反射。&lt;/p&gt;&lt;p&gt;我想有些人听到这个名字，首先想到的会是低性能，并积极地拒绝使用。&lt;br /&gt;在那些人的心目中，反射就是低性能的代名词。&lt;br /&gt;有趣的是，那些人可能在乐滋滋地用着ASP.NET MVC, WCF, EntryFramewok这类框架。&lt;/p&gt;&lt;p&gt;这里我要说明的是，我并没有说那些框架比较差，而是想说：&lt;br /&gt;那些框架其实也在大量地使用反射，只是微软没有直接说出来而已。&lt;br /&gt;我不知道那些不喜欢的反射的人，知道这些框架在大量使用反射时，会有什么样的想法。&lt;/p&gt;&lt;p&gt;其实想知道一个框架有没有在使用反射，有个简单的识别方法：&lt;br /&gt;1. 它有没有序列化和反序列化。&lt;br /&gt;2. 有没有把类名与方法写在字符串中。&lt;br /&gt;3. 它是不是可以神奇地知道你的任何对象拥有哪些成员？&lt;br /&gt;4. 有没有使用[Attribute]。您不会以为这个标记是给编译器看的吧？&lt;/p&gt;&lt;p&gt;WCF简直是把这些全用上了，而且是在大量使用，ASP.NET MVC，EntryFramewok也没少用！&lt;/p&gt;&lt;p&gt;在实现MyMVC的过程，我大量地使用了反射。&lt;br /&gt;没办法，不用反射，我真的写不出来什么东西。&lt;/p&gt;&lt;p&gt;我认为：&lt;b&gt;没有哪个框架可以不使用反射的。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;不使用反射，就意味着：在事先就需要知道将调用哪些类型的哪些方法，这样哪来的灵活性？&lt;br /&gt;反射还有另一个好处就是简化代码，许多类似的代码，就像前面【回忆以往AJAX的实现方式】中总结的那样。那些类似的代码差别在于：&lt;b&gt;参数的名字不同，参数的类型不同，参数的个数不同，要调用的方法以及返回值不同。&lt;/b&gt;那些惊呼【非ASP.NET MVC框架不可】的人或许也是厌倦了这些重复劳动，然而，ASP.NET MVC解决这个问题的办法还是反射。&lt;/p&gt;&lt;p&gt;所以，不必害怕反射，它的确会影响性能。&lt;br /&gt;但是，你可以保证你的其它代码都是性能很好吗？&lt;br /&gt;我见过的低性能代码实在是太多了。&lt;/p&gt;&lt;p&gt;反射是会影响性能，但好消息是，它对性能的影响是可以优化的，因此，不同的写法，所表现出来的影响也是不一样的。不过，反射的优化也是个复杂的话题，我打算以后有机会再谈。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;结束语&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;今天的博客演示了我的MVC框架对于AJAX的支持，也展示了在ASP.NET上开发一个框架的具体过程，虽然还未全部说完，但核心部分已经实现了，那就是：&lt;b class="redText"&gt;根据URL动态调用一个方法。&lt;/b&gt;先说AJAX的实现是因为，它是【无界面】的，无界面的东西通常会比较简单。&lt;/p&gt;&lt;p&gt;说到【无界面】又让我想到一些人把微软的ASP.NET MVC用于【无界面】的项目，还在信誓旦旦地说：此类型的项目非微软的ASP.NET MVC不可！&lt;/p&gt;&lt;p&gt;如何评价这些人呢？我只想说：你们还是小点声吧，小心遭人鄙视！&lt;/p&gt;&lt;p&gt;说到写框架，我想还是有必要再说说我写框架的原因：（引用我在博客&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/09/05/2168073.html" target="_blank"&gt;【用Asp.net写自己的服务框架】&lt;/a&gt;中的原话）&lt;/p&gt;&lt;p&gt;&lt;b&gt;自己写框架的好处不在于能将它做得多强大，多完美，而是从写框架的过程中，可以学到很多东西。&lt;br /&gt;一个框架写完了，不在乎要给多少人使用，而是自己感觉有没有进步，这才是关键。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;不管你信不信，那些喜欢说【非什么什么不可】的人，通常是从来不会写框架的。&lt;/p&gt;&lt;p&gt;MyMVC的介绍还未结束，下篇博客将会继续，下篇博客的重点在于UI部分的支持和实现，这也正是MVC思想存在的必要性，当然也可以反映出MVC框架的核心价值。&lt;/p&gt;&lt;p&gt;说到这里，我打算给下篇博客做个预告：&lt;br /&gt;MyMVC框架的后半部分在设计上主要体现了MVC这三者的关系，在设计时主要遵循了Martin Fowler大叔的总结：&lt;b class="redText"&gt;从模型中分离表现和从视图中分离控制器。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;最终MyMVC对于UI部分支持的结果是：多个URL可以映射到一个Action，一个Action可以将结果指定给多个View来输出。也就是说：请求与View是一种多对多的关系，而中间的Controller只是一个。至于Model的返回，可以由Controller根据运行的上下文条件给出不同的结果，同一个Model可以交给不同的View来显示，也可以返回不同的Model，分别交给不同的View来显示。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;写博客真不容易，为了写这篇博客，我先要写MyMVC框架以及准备示例代码，再准备一些Visio图，最后是文字部分，总共花了整整二个星期。这还不包括前面二篇做为铺垫的博客：&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/01/11/2320027.html" target="_blank"&gt;【细说 ASP.NET控制HTTP缓存】&lt;/a&gt;和&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/01/29/2331477.html" target="_blank"&gt;【细说 HttpHandler 的映射过程】&lt;/a&gt;。但是，每当看到自己写的博客在博客园上拥有较高的【推荐数量】时，感觉宽慰了许多。但愿今天的博客能受欢迎。&lt;/p&gt;&lt;p&gt;感谢 Amy（黄敏）同学为本文所做的校对工作，她已帮我找了好多处文字上的错误。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/21/2361982.html" target="_blank"&gt;获取MyMVC框架源代码及示例代码请点击此处进入下载页面&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;&lt;div class="articleFooter"&gt;&lt;p&gt;如果，您认为阅读这篇博客让您有些收获，不妨点击一下右下角的&lt;a id="btnRecommendMyBlog" href="javascript:void(0);"&gt;【&lt;b&gt;推荐&lt;/b&gt;】&lt;/a&gt;按钮。&lt;br /&gt;如果，您希望更容易地发现我的新博客，不妨点击一下右下角的&lt;a id="btnFollowFishLi" href="javascript:void(0);"&gt;【&lt;b&gt;关注 Fish Li&lt;/b&gt;】&lt;/a&gt;。&lt;br /&gt;因为，我的写作热情也离不开您的肯定支持。&lt;/p&gt;&lt;p&gt;感谢您的阅读，如果您对我的博客所讲述的内容有兴趣，请继续关注我的后续博客，我是Fish Li 。&lt;span class="icon_smile"&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/fish-li/aggbug/2348395.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/02/12/2348395.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/fish-li/archive/2012/01/29/2331477.html</id><title type="text">细说 HttpHandler 的映射过程</title><summary type="text">在ASP.NET编程模型中，一个来自客户端的请求要经过一个称为管线的处理过程。在整个处理请求中，相对于其它对象来说，HttpHandler的处理算得上是整个过程的核心部分。由于HttpHandler的重要地位，我前面已经有二篇博客对它过一些使用上的介绍。【用Asp.net写自己的服务框架】中谈到了它的一般使用方法。【细说ASP.NET的各种异步操作】又详细地介绍了异步HttpHandler的使用方式。今天的博客将着重介绍HttpHandler的配置，创建以及重用过程，还将涉及HttpHandlerFactory的内容。回顾HttpHandlerHttpHandler其实是一类统称：泛指实现了I</summary><published>2012-01-29T14:14:00Z</published><updated>2012-01-29T14:14:00Z</updated><author><name>Fish Li</name><uri>http://www.cnblogs.com/fish-li/</uri></author><link rel="alternate" href="http://www.cnblogs.com/fish-li/archive/2012/01/29/2331477.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/fish-li/archive/2012/01/29/2331477.html"/><content type="html">&lt;p&gt;在ASP.NET编程模型中，一个来自客户端的请求要经过一个称为管线的处理过程。在整个处理请求中，相对于其它对象来说，HttpHandler的处理算得上是整个过程的核心部分。由于HttpHandler的重要地位，我前面已经有二篇博客对它过一些使用上的介绍。&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/09/05/2168073.html" target="_blank"&gt;【用Asp.net写自己的服务框架】&lt;/a&gt;中谈到了它的一般使用方法。&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/11/20/2256385.html" target="_blank"&gt;【细说ASP.NET的各种异步操作】&lt;/a&gt;又详细地介绍了异步HttpHandler的使用方式。&lt;/p&gt;&lt;p&gt;今天的博客将着重介绍HttpHandler的配置，创建以及重用过程，还将涉及HttpHandlerFactory的内容。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;回顾HttpHandler&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;HttpHandler其实是一类统称：泛指实现了IHttpHandler接口的一些类型，这些类型有一个共同的功能，那就是可以用来处理HTTP请求。IHttpHandler的接口定义如下：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:green"&gt;// 定义 ASP.NET 为使用自定义 HTTP 处理程序同步处理 HTTP Web 请求而实现的协定。&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public interface &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IHttpHandler&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;// 获取一个值，该值指示其他请求是否可以使用 System.Web.IHttpHandler 实例。&lt;br/&gt;    //&lt;br/&gt;    // 返回结果:&lt;br/&gt;    //     如果 System.Web.IHttpHandler 实例可再次使用，则为 true；否则为 false。&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;bool &lt;/span&gt;IsReusable { &lt;span style="color:blue"&gt;get&lt;/span&gt;; }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;// 通过实现 System.Web.IHttpHandler 接口的自定义 HttpHandler 启用 HTTP Web 请求的处理。&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;void &lt;/span&gt;ProcessRequest(HttpContext context);&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;有关HttpHandler的各类用法，可参考我的博客&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/09/05/2168073.html" target="_blank"&gt;【用Asp.net写自己的服务框架】&lt;/a&gt;，本文将不再重复说明了。它还有一个异步版本：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:green"&gt;// 摘要:&lt;br/&gt;//     定义 HTTP 异步处理程序对象必须实现的协定。&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public interface &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IHttpAsyncHandler &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IHttpHandler&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;// 摘要:&lt;br/&gt;    //     启动对 HTTP 处理程序的异步调用。&lt;br/&gt;    //&lt;br/&gt;    // 参数:&lt;br/&gt;    //   context:&lt;br/&gt;    //     一个 System.Web.HttpContext 对象，该对象提供对用于向 HTTP 请求提供服务的内部服务器对象（如 Request、Response、Session&lt;br/&gt;    //     和 Server）的引用。&lt;br/&gt;    //&lt;br/&gt;    //   extraData:&lt;br/&gt;    //     处理该请求所需的所有额外数据。&lt;br/&gt;    //&lt;br/&gt;    //   cb:&lt;br/&gt;    //     异步方法调用完成时要调用的 System.AsyncCallback。如果 cb 为 null，则不调用委托。&lt;br/&gt;    //&lt;br/&gt;    // 返回结果:&lt;br/&gt;    //     包含有关进程状态信息的 System.IAsyncResult。&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IAsyncResult &lt;/span&gt;BeginProcessRequest(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context, &lt;span style="color:#2b91af"&gt;AsyncCallback &lt;/span&gt;cb, &lt;span style="color:blue"&gt;object &lt;/span&gt;extraData);&lt;br/&gt;    &lt;span style="color:green"&gt;//&lt;br/&gt;    // 摘要:&lt;br/&gt;    //     进程结束时提供异步处理 End 方法。&lt;br/&gt;    //&lt;br/&gt;    // 参数:&lt;br/&gt;    //   result:&lt;br/&gt;    //     包含有关进程状态信息的 System.IAsyncResult。&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;void &lt;/span&gt;EndProcessRequest(&lt;span style="color:#2b91af"&gt;IAsyncResult &lt;/span&gt;result);&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;IHttpAsyncHandler接口的二个方法该如何使用，可参考我的博客&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/11/20/2256385.html" target="_blank"&gt;【细说ASP.NET的各种异步操作】&lt;/a&gt;，本文也将不再重复讲解。&lt;/p&gt;&lt;p&gt;如果我们创建了一个自定义的HttpHandler，那么为了能让它处理某些HTTP请求，我们还需将它注册到web.config中，就像下面这样：&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;add &lt;/span&gt;&lt;span style="color:red"&gt;path&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*.fish&lt;/span&gt;" &lt;span style="color:red"&gt;verb&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*&lt;/span&gt;" &lt;span style="color:red"&gt;validate&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;true&lt;/span&gt;" &lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;MySimpleServiceFramework.AjaxServiceHandler&lt;/span&gt;"&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;虽然我以前的博客中也曾多次涉及到HttpHandler，但感觉还是没有把它完整地说清楚，今天的博客将继续以前的话题，因为我认为HttpHandler实在是太重要了。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;HttpHandler的映射过程&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在博客&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/09/05/2168073.html" target="_blank"&gt;【用Asp.net写自己的服务框架】&lt;/a&gt;中，我从MSDN中摘选了一些ASP.NET管线事件，在这些事件中，第10个事件【&lt;b&gt;根据所请求资源的文件扩展名（在应用程序的配置文件中映射），选择实现 IHttpHandler 的类，对请求进行处理&lt;/b&gt;】就是本文要介绍的重点事件。这个事件也是HttpHandler创建的地方。&lt;/p&gt;&lt;p&gt;由于IIS6,7在管线事件触发机制上的有一定的差别，本文将以ASP.NET 2.0以及IIS6的运行方式来介绍这个过程，IIS7的集成模式下只是触发机制不同，但事件的绝大部分是一样的。管线事件由HttpApplication控制，由MapHandlerExecutionStep负责封装这个事件的执行过程：&lt;a href="javascript:void(0);" codeId="pre-MapHandlerExecutionStep"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MapHandlerExecutionStep &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;HttpApplication&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;&lt;span style="color:#2b91af"&gt;IExecutionStep&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpApplication &lt;/span&gt;_application;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;void &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpApplication&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;&lt;span style="color:#2b91af"&gt;IExecutionStep&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Execute()&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;_application&lt;span style="color:red"&gt;.&lt;/span&gt;Context;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;HttpRequest &lt;/span&gt;request &lt;span style="color:red"&gt;= &lt;/span&gt;context&lt;span style="color:red"&gt;.&lt;/span&gt;Request;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;//我删除了一些与本文无关的调用代码&lt;br/&gt;&lt;br/&gt;        &lt;/span&gt;context&lt;span style="color:red"&gt;.&lt;/span&gt;Handler &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;_application&lt;span style="color:red"&gt;.&lt;/span&gt;MapHttpHandler(&lt;br/&gt;                context, request&lt;span style="color:red"&gt;.&lt;/span&gt;RequestType, request&lt;span style="color:red"&gt;.&lt;/span&gt;FilePathObject, request&lt;span style="color:red"&gt;.&lt;/span&gt;PhysicalPathInternal, &lt;span style="color:blue"&gt;false&lt;/span&gt;);&lt;br/&gt;    }&lt;br/&gt;&lt;p&gt;Execute()最终调用了MapHttpHandler()方法，这个映射过程是由HttpApplication实现的。&lt;br /&gt;MapHttpHandler方法的实现如下：&lt;b class="redText"&gt;注意代码中我加入的注释。&lt;/b&gt;&lt;a href="javascript:void(0);" codeId="pre-MapHttpHandler"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;根据虚拟路径映射到具体的HttpHandler对象&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;/// &amp;lt;param name="context"&amp;gt;&lt;/span&gt;&lt;span style="color:green"&gt;HttpContext的实例&lt;/span&gt;&lt;span style="color:gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;/// &amp;lt;param name="requestType"&amp;gt;&lt;/span&gt;&lt;span style="color:green"&gt;GET, POST ...&lt;/span&gt;&lt;span style="color:gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;/// &amp;lt;param name="path"&amp;gt;&lt;/span&gt;&lt;span style="color:green"&gt;一个虚拟路径映射的字符串: /abc.aspx&lt;/span&gt;&lt;span style="color:gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;/// &amp;lt;param name="pathTranslated"&amp;gt;&lt;/span&gt;&lt;span style="color:green"&gt;要请求的物理文件的路径&lt;/span&gt;&lt;span style="color:gray"&gt;&amp;lt;/param&amp;gt;&lt;br/&gt;/// &amp;lt;param name="useAppConfig"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;/// &amp;lt;returns&amp;gt;&lt;/span&gt;&lt;span style="color:green"&gt;具体的HttpHandler对象&lt;/span&gt;&lt;span style="color:gray"&gt;&amp;lt;/returns&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;internal &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;MapHttpHandler(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context, &lt;span style="color:blue"&gt;string &lt;/span&gt;requestType, &lt;br/&gt;                                    &lt;span style="color:#2b91af"&gt;VirtualPath &lt;/span&gt;path, &lt;span style="color:blue"&gt;string &lt;/span&gt;pathTranslated, &lt;span style="color:blue"&gt;bool &lt;/span&gt;useAppConfig)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;// 说明：这段代码是我精简后的代码。为了便于理解，我去掉了一些与请求无关的代码行。&lt;br/&gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;handler &lt;span style="color:red"&gt;= &lt;/span&gt;(context&lt;span style="color:red"&gt;.&lt;/span&gt;ServerExecuteDepth &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;) &lt;span style="color:red"&gt;? &lt;/span&gt;context&lt;span style="color:red"&gt;.&lt;/span&gt;RemapHandlerInstance : &lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:green"&gt;//用于将当前线程的运行帐号切换为web.config指定的帐号&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;using&lt;/span&gt;( &lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ApplicationImpersonationContext&lt;/span&gt;() ) {&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 如果之前调用过context.RemapHandler()，则直接返回那个HttpHandler&lt;br/&gt;        // 把这个判断放在这里似乎没有意义，应该放在using前面，那样岂不是更快吗？【fish li个人意见】&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( handler &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;handler;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 到 &amp;lt;httpHandlers&amp;gt; 配置中查找一个能与requestType以及path匹配的配置项&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpHandlerAction &lt;/span&gt;mapping &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetHandlerMapping(context, requestType, path, useAppConfig);&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( mapping &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) &lt;br/&gt;            &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"Http_handler_not_found_for_request_type"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 获取IHttpHandlerFactory对象，这是比较重要的调用。&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IHttpHandlerFactory &lt;/span&gt;factory &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetFactory(mapping);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 尝试转换成IHttpHandlerFactory2对象。设计二个IHttpHandlerFactory的原因与参数的可见类型有关。&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IHttpHandlerFactory2 &lt;/span&gt;factory2 &lt;span style="color:red"&gt;= &lt;/span&gt;factory &lt;span style="color:blue"&gt;as &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IHttpHandlerFactory2&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 调用IHttpHandlerFactory对象的GetHandler方法获取具体的HttpHandler对象&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( factory2 &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) &lt;br/&gt;            handler &lt;span style="color:red"&gt;= &lt;/span&gt;factory2&lt;span style="color:red"&gt;.&lt;/span&gt;GetHandler(context, requestType, path, pathTranslated);                &lt;br/&gt;        &lt;span style="color:blue"&gt;else &lt;br/&gt;            &lt;/span&gt;handler &lt;span style="color:red"&gt;= &lt;/span&gt;factory&lt;span style="color:red"&gt;.&lt;/span&gt;GetHandler(context, requestType, path&lt;span style="color:red"&gt;.&lt;/span&gt;VirtualPathString, pathTranslated);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 将这二个对象都添加到【临时】回收列表。在管线处理的结尾处，会调用HandlerWithFactory.Recycle()&lt;br/&gt;        // 进而会调用factory.ReleaseHandler()，最后会丢掉_handlerRecycleList的引用。&lt;br/&gt;        // 因此factory的重用与这里无关，它只可能会影响handler&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;_handlerRecycleList&lt;span style="color:red"&gt;.&lt;/span&gt;Add(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HandlerWithFactory&lt;/span&gt;(handler, factory));&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;handler;&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;今天的代码将着重分析这段代码，以揭示HttpHandler的映射过程。&lt;/p&gt;&lt;p&gt;在这段代码中，有3个主要的调用过程：&lt;br /&gt;1. this.GetHandlerMapping(context, requestType, path, useAppConfig)&lt;br /&gt;2. this.GetFactory(mapping)&lt;br /&gt;3. factory.GetHandler(context, requestType, path.VirtualPathString, pathTranslated)&lt;br /&gt;后面将着重分析这三个调用。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;HttpContext.RemapHandler()&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在MapHttpHandler()方法的开始处，有这么一段代码，不知您注意没有？&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;handler &lt;span style="color:red"&gt;= &lt;/span&gt;(context&lt;span style="color:red"&gt;.&lt;/span&gt;ServerExecuteDepth &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;) &lt;span style="color:red"&gt;? &lt;/span&gt;context&lt;span style="color:red"&gt;.&lt;/span&gt;RemapHandlerInstance : &lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( handler &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;handler;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;这段代码是什么意思呢？&lt;br /&gt;为了能让您较为简单地理解这段代码的意义，请看我准备的一个示例：&lt;br /&gt;我创建了一个TestRemapHandler.ashx文件：&lt;a href="javascript:void(0);" codeId="pre-TestRemapHandler"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;@ &lt;/span&gt;&lt;span style="color:#a31515"&gt;WebHandler &lt;/span&gt;&lt;span style="color:red"&gt;Language&lt;/span&gt;&lt;span style="color:blue"&gt;="C#" &lt;/span&gt;&lt;span style="color:red"&gt;Class&lt;/span&gt;&lt;span style="color:blue"&gt;="TestRemapHandler" &lt;/span&gt;&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;using &lt;/span&gt;System;&lt;br/&gt;&lt;span style="color:blue"&gt;using &lt;/span&gt;System&lt;span style="color:red"&gt;.&lt;/span&gt;Web;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;TestRemapHandler &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;{&lt;br/&gt;    &lt;br/&gt;    &lt;span style="color:blue"&gt;public void &lt;/span&gt;ProcessRequest (&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context) {&lt;br/&gt;        context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;ContentType &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"text/plain"&lt;/span&gt;;&lt;br/&gt;        context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"Hello TestRemapHandler"&lt;/span&gt;);&lt;br/&gt;    }&lt;br/&gt; &lt;br/&gt;    &lt;span style="color:blue"&gt;public bool &lt;/span&gt;IsReusable {&lt;br/&gt;        &lt;span style="color:blue"&gt;get &lt;/span&gt;{&lt;br/&gt;            &lt;span style="color:blue"&gt;return false&lt;/span&gt;;&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;至于这个文件在运行时能输出什么，我想我就不用截图了。&lt;br /&gt;接下来，我再创建一个Global.asax文件，并写了一个事件处理方法：&lt;a href="javascript:void(0);" codeId="pre-Application_PostResolveRequestCache"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:green"&gt;//protected void Application_PostResolveRequestCache(object sender, EventArgs e)&lt;br/&gt;//{&lt;br/&gt;//    HttpApplication app = (HttpApplication)sender;&lt;br/&gt;//    if( app.Request.FilePath.EndsWith(".ashx", StringComparison.OrdinalIgnoreCase) )&lt;br/&gt;//        app.Context.RemapHandler(new MyTestHandler());&lt;br/&gt;//}&lt;br/&gt;&lt;br/&gt;// 或者是下面这样&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;protected void &lt;/span&gt;Application_PostResolveRequestCache(&lt;span style="color:blue"&gt;object &lt;/span&gt;sender, &lt;span style="color:#2b91af"&gt;EventArgs &lt;/span&gt;e)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;HttpApplication &lt;/span&gt;app &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;HttpApplication&lt;/span&gt;)sender;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( app&lt;span style="color:red"&gt;.&lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;FilePath&lt;span style="color:red"&gt;.&lt;/span&gt;EndsWith(&lt;span style="color:#a31515"&gt;"/TestRemapHandler.ashx"&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;StringComparison&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;OrdinalIgnoreCase) )&lt;br/&gt;        app&lt;span style="color:red"&gt;.&lt;/span&gt;Context&lt;span style="color:red"&gt;.&lt;/span&gt;RemapHandler(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyTestHandler&lt;/span&gt;());&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;MyTestHandler是我定义的一个自定义的HttpHandler，后面的示例也会用到它，所以，我现在就将它的实现代码贴出来：&lt;a href="javascript:void(0);" codeId="pre-MyTestHandler"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyTestHandler &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IHttpHandler&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Counter &lt;/span&gt;_counter &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Counter&lt;/span&gt;();&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public bool &lt;/span&gt;IsReusable&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;get &lt;/span&gt;{ &lt;span style="color:blue"&gt;return true&lt;/span&gt;; }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public void &lt;/span&gt;ProcessRequest(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context)&lt;br/&gt;    {&lt;br/&gt;        _counter&lt;span style="color:red"&gt;.&lt;/span&gt;ShowCountAndRequestInfo(context);&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;类型Counter是一个简单的计数器，它的实现如下：&lt;a href="javascript:void(0);" codeId="pre-Counter"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;/// &lt;/span&gt;&lt;span style="color:green"&gt;一个简单的计数器&lt;br/&gt;&lt;/span&gt;&lt;span style="color:gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Counter&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;private int &lt;/span&gt;_count;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public void &lt;/span&gt;ShowCountAndRequestInfo(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context)&lt;br/&gt;    {&lt;br/&gt;        _count&lt;span style="color:red"&gt;++&lt;/span&gt;;&lt;br/&gt;        context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;ContentType &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#a31515"&gt;"text/plain"&lt;/span&gt;;&lt;br/&gt;        context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"count: " &lt;/span&gt;&lt;span style="color:red"&gt;+ &lt;/span&gt;_count&lt;span style="color:red"&gt;.&lt;/span&gt;ToString());&lt;br/&gt;        context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Write(&lt;span style="color:#a31515"&gt;"\r\n"&lt;/span&gt;);&lt;br/&gt;        context&lt;span style="color:red"&gt;.&lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Write(context&lt;span style="color:red"&gt;.&lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;RawUrl);&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;现在，您可以想像一下当我再次访问TestRemapHandler.ashx时，会在浏览器中看到什么？&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;以下是我看到的结果：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012012815442331.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;从截图中，我们可以看出，服务端的输出并不是TestRemapHandler.ashx产生的，而是由MyTestHandler产生的。这也说明我调用Context.RemapHandler()确实影响了后面的MapHttpHandler过程。现在我们再回过头来再看一下前面那段代码：&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;handler &lt;span style="color:red"&gt;= &lt;/span&gt;(context&lt;span style="color:red"&gt;.&lt;/span&gt;ServerExecuteDepth &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;) &lt;span style="color:red"&gt;? &lt;/span&gt;context&lt;span style="color:red"&gt;.&lt;/span&gt;RemapHandlerInstance : &lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( handler &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;handler;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;这段代码也主要是为配合HttpContext.RemapHandler()一起工作的。这里要补充的是：context.ServerExecuteDepth的判断是说有没有调用HttpServerUtility.Execute()&lt;/p&gt;&lt;p&gt;&lt;b&gt;小结：&lt;/b&gt;如果我们在MapHttpHandler事件前调用HttpContext.RemapHandler()，将会直接影响后面的映射过程，或者说，我们可以直接指定一个HttpHandler，而不是让ASP.NET来替我们来决定。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;HttpContext.RemapHandler()的另类用途&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;我在&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/09/05/2168073.html" target="_blank"&gt;【用Asp.net写自己的服务框架】&lt;/a&gt;曾演示过ASP.NET URL路由的设计思路，虽然那个示例能较好地反映微软的Routing组件的工作方式，但对于示例来说，有些代码还是可以简化的。今天我将使用HttpContext.RemapHandler()来简化那段代码，简化后的版本如下：&lt;a href="javascript:void(0);" codeId="pre-MyServiceUrlRoutingModule2"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyServiceUrlRoutingModule2 &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IHttpModule&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;public void &lt;/span&gt;Init(&lt;span style="color:#2b91af"&gt;HttpApplication &lt;/span&gt;app)&lt;br/&gt;    {&lt;br/&gt;        app&lt;span style="color:red"&gt;.&lt;/span&gt;PostResolveRequestCache &lt;span style="color:red"&gt;+= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;EventHandler&lt;/span&gt;(app_PostResolveRequestCache);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;private void &lt;/span&gt;app_PostResolveRequestCache(&lt;span style="color:blue"&gt;object &lt;/span&gt;sender, &lt;span style="color:#2b91af"&gt;EventArgs &lt;/span&gt;e)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;HttpApplication &lt;/span&gt;app &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;HttpApplication&lt;/span&gt;)sender;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 根据HttpContext，获取合适的HttpHandler，这个过程俗称路由&lt;br/&gt;        // 通常就是根据URL去主动寻找一个合适的HttpHandler&lt;br/&gt;&lt;br/&gt;        // 查找过程仍使用上一版的方法&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyServiceHandler &lt;/span&gt;handler &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyServiceUrlRoutingModule&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetHandler(app&lt;span style="color:red"&gt;.&lt;/span&gt;Context);&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( handler &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            &lt;span style="color:green"&gt;// 直接设置已找到的HttpHandler&lt;br/&gt;            &lt;/span&gt;app&lt;span style="color:red"&gt;.&lt;/span&gt;Context&lt;span style="color:red"&gt;.&lt;/span&gt;RemapHandler(handler);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public void &lt;/span&gt;Dispose()&lt;br/&gt;    {&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;在MyServiceUrlRoutingModule2这个新版本中，基本上跳过了MapHttpHandler()中所有复杂的处理逻辑，因此会更快。&lt;/p&gt;&lt;p&gt;这种方法虽然更简单，但它只能设置一个参数IHttpHandler，因此，如果有其它的参数需要一起传递，则要修改相关的HttpHandler类型，以便容纳需要传递的参数。例如，在&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/09/05/2168073.html" target="_blank"&gt;【我的服务框架】&lt;/a&gt;中，MyServiceHandler类型就专门定义了一个属性ServiceInfo来保存要调用的方法信息。MyServiceUrlRoutingModule.GetHandler()的实现代码如下：&lt;a href="javascript:void(0);" codeId="pre-MyServiceUrlRoutingModule-GetHandler"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal static &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyServiceHandler &lt;/span&gt;GetHandler(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;NamesPair &lt;/span&gt;pair &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;FrameworkRules&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;ParseNamesPair(context&lt;span style="color:red"&gt;.&lt;/span&gt;Request);&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( pair &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;        &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;InvokeInfo &lt;/span&gt;vkInfo &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ReflectionHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetInvokeInfo(pair);&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( vkInfo &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;ExceptionHelper&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Throw404Exception(context);&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;MyServiceHandler &lt;/span&gt;handler &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyServiceHandlerFactory&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetHandler(vkInfo);&lt;br/&gt;    handler&lt;span style="color:red"&gt;.&lt;/span&gt;ServiceInfo &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ServiceInfo&lt;/span&gt;(pair, vkInfo);&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;handler;&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;写到这里，有个问题把我难住了：为什么ASP.NET 3.5 UrlRoutingModule不用RemapHandler()而是采用较复杂的方法呢？难道是为了能保留二个参数吗？但那个【context.Request.Path】没有必要保存呢。实在是没有想通，最后想到ASP.NET 4.0 UrlRoutingModule会不会不一样了？于是，只好再次安装 .net framework 4.0 了（没办法，老家的旧机器上还真没有.net 4.0），结果当我用Reflector.exe找到4.0版本的UrlRoutingModule时，发现它已被移到System.Web.dll中，而且，ASPL.NET 4.0也在使用RemapHandler() ！ 看来微软当初忘记了这个方法。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;GetHandlerMapping()&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在MapHttpHandler()方法中，有下面这个调用：&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:green"&gt;// 到 &amp;lt;httpHandlers&amp;gt; 配置中查找一个能与requestType以及path匹配的配置项&lt;br/&gt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpHandlerAction &lt;/span&gt;mapping &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetHandlerMapping(context, requestType, path, useAppConfig);&lt;br/&gt;&lt;br/&gt;&lt;p&gt;接下来，我们再来看一下这个调用的实现代码：&lt;a href="javascript:void(0);" codeId="pre-GetHandlerMapping"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpHandlerAction &lt;/span&gt;GetHandlerMapping(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context, &lt;span style="color:blue"&gt;string &lt;/span&gt;requestType, &lt;span style="color:#2b91af"&gt;VirtualPath &lt;/span&gt;path, &lt;span style="color:blue"&gt;bool &lt;/span&gt;useAppConfig)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;CachedPathData &lt;/span&gt;pathData &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;HandlerMappingMemo &lt;/span&gt;cachedHandler &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;HttpHandlerAction &lt;/span&gt;mapping &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;    &lt;span style="color:blue"&gt;if &lt;/span&gt;(&lt;span style="color:red"&gt;!&lt;/span&gt;useAppConfig)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:green"&gt;// 先从缓存中查找&lt;br/&gt;        &lt;/span&gt;pathData &lt;span style="color:red"&gt;= &lt;/span&gt;context&lt;span style="color:red"&gt;.&lt;/span&gt;GetPathData(path);&lt;br/&gt;        cachedHandler &lt;span style="color:red"&gt;= &lt;/span&gt;pathData&lt;span style="color:red"&gt;.&lt;/span&gt;CachedHandler;&lt;br/&gt;        &lt;span style="color:blue"&gt;if &lt;/span&gt;((cachedHandler &lt;span style="color:red"&gt;!= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;) &lt;span style="color:red"&gt;&amp;amp;&amp;amp; !&lt;/span&gt;cachedHandler&lt;span style="color:red"&gt;.&lt;/span&gt;IsMatch(requestType, path))&lt;br/&gt;        {&lt;br/&gt;            cachedHandler &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;if &lt;/span&gt;(cachedHandler &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:green"&gt;// 根据配置文件，查找映射&lt;br/&gt;        &lt;/span&gt;mapping &lt;span style="color:red"&gt;= &lt;/span&gt;(useAppConfig &lt;span style="color:red"&gt;? &lt;/span&gt;&lt;span style="color:#2b91af"&gt;RuntimeConfig&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetAppConfig()&lt;span style="color:red"&gt;.&lt;/span&gt;HttpHandlers &lt;br/&gt;                                : &lt;span style="color:#2b91af"&gt;RuntimeConfig&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetConfig(context)&lt;span style="color:red"&gt;.&lt;/span&gt;HttpHandlers)&lt;br/&gt;            &lt;span style="color:red"&gt;.&lt;/span&gt;FindMapping(requestType, path);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if &lt;/span&gt;(&lt;span style="color:red"&gt;!&lt;/span&gt;useAppConfig)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:green"&gt;// 将查找到的结果放入缓存&lt;br/&gt;            &lt;/span&gt;cachedHandler &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HandlerMappingMemo&lt;/span&gt;(mapping, requestType, path);&lt;br/&gt;            pathData&lt;span style="color:red"&gt;.&lt;/span&gt;CachedHandler &lt;span style="color:red"&gt;= &lt;/span&gt;cachedHandler;&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;mapping;&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;return &lt;/span&gt;cachedHandler&lt;span style="color:red"&gt;.&lt;/span&gt;Mapping;&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;代码中的重要阶段，我加了一点注释。我们尤其要注意的FindMapping(requestType, path)的那个调用。&lt;br /&gt;但前面的那个RuntimeConfig.GetAppConfig().HttpHandlers 和RuntimeConfig.GetConfig(context).HttpHandlers)又可以得到什么结果呢？&lt;br /&gt;为了能让您更容易地理解这个调用，我准备了一段代码，可以直观地显示这个调用结果：&lt;a href="javascript:void(0);" codeId="pre-TestRuntimeConfig"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public partial class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;TestRuntimeConfig &lt;/span&gt;: System&lt;span style="color:red"&gt;.&lt;/span&gt;Web&lt;span style="color:red"&gt;.&lt;/span&gt;UI&lt;span style="color:red"&gt;.&lt;/span&gt;&lt;span style="color:#2b91af"&gt;Page&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;protected string &lt;/span&gt;HttpHandlers;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;protected void &lt;/span&gt;Page_Load(&lt;span style="color:blue"&gt;object &lt;/span&gt;sender, &lt;span style="color:#2b91af"&gt;EventArgs &lt;/span&gt;e)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;string &lt;/span&gt;typeName &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;typeof&lt;/span&gt;(&lt;span style="color:#2b91af"&gt;HttpRequest&lt;/span&gt;)&lt;span style="color:red"&gt;.&lt;/span&gt;AssemblyQualifiedName&lt;br/&gt;                                        &lt;span style="color:red"&gt;.&lt;/span&gt;Replace(&lt;span style="color:#a31515"&gt;"HttpRequest"&lt;/span&gt;, &lt;span style="color:#a31515"&gt;"Configuration.RuntimeConfig"&lt;/span&gt;);&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;Type &lt;/span&gt;type &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Type&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetType(typeName);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;bool &lt;/span&gt;useAppConfig &lt;span style="color:red"&gt;= &lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;QueryString[&lt;span style="color:#a31515"&gt;"useAppConfig"&lt;/span&gt;] &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:#a31515"&gt;"1"&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 由于RuntimeConfig类型的可见性是internal，&lt;br/&gt;        // 所以，我不能直接用它声明变量，只能使用object类型&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:blue"&gt;object &lt;/span&gt;config &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( useAppConfig )&lt;br/&gt;            config &lt;span style="color:red"&gt;= &lt;/span&gt;type&lt;span style="color:red"&gt;.&lt;/span&gt;InvokeMember(&lt;span style="color:#a31515"&gt;"GetAppConfig"&lt;/span&gt;,&lt;br/&gt;                &lt;span style="color:#2b91af"&gt;BindingFlags&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;InvokeMethod &lt;span style="color:red"&gt;| &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BindingFlags&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Static &lt;span style="color:red"&gt;| &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BindingFlags&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;NonPublic,&lt;br/&gt;                &lt;span style="color:blue"&gt;null&lt;/span&gt;, &lt;span style="color:blue"&gt;null&lt;/span&gt;, &lt;span style="color:blue"&gt;null&lt;/span&gt;);&lt;br/&gt;        &lt;span style="color:blue"&gt;else&lt;br/&gt;            &lt;/span&gt;config &lt;span style="color:red"&gt;= &lt;/span&gt;type&lt;span style="color:red"&gt;.&lt;/span&gt;InvokeMember(&lt;span style="color:#a31515"&gt;"GetConfig"&lt;/span&gt;,&lt;br/&gt;                &lt;span style="color:#2b91af"&gt;BindingFlags&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;InvokeMethod &lt;span style="color:red"&gt;| &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BindingFlags&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Static &lt;span style="color:red"&gt;| &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BindingFlags&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;NonPublic,&lt;br/&gt;                &lt;span style="color:blue"&gt;null&lt;/span&gt;, &lt;span style="color:blue"&gt;null&lt;/span&gt;, &lt;span style="color:blue"&gt;new object&lt;/span&gt;[] { &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Context });&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;HttpHandlersSection &lt;/span&gt;section &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;HttpHandlersSection&lt;/span&gt;)type&lt;span style="color:red"&gt;.&lt;/span&gt;InvokeMember(&lt;span style="color:#a31515"&gt;"HttpHandlers"&lt;/span&gt;,&lt;br/&gt;             &lt;span style="color:#2b91af"&gt;BindingFlags&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetProperty &lt;span style="color:red"&gt;| &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BindingFlags&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Instance &lt;span style="color:red"&gt;| &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BindingFlags&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;NonPublic,&lt;br/&gt;             &lt;span style="color:blue"&gt;null&lt;/span&gt;, config, &lt;span style="color:blue"&gt;null&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;        HttpHandlers &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Format(&lt;span style="color:#a31515"&gt;"总共 {0} 个配置项。&amp;lt;br /&amp;gt;"&lt;/span&gt;, section&lt;span style="color:red"&gt;.&lt;/span&gt;Handlers&lt;span style="color:red"&gt;.&lt;/span&gt;Count) &lt;span style="color:red"&gt;+&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Join(&lt;span style="color:#a31515"&gt;"&amp;lt;br /&amp;gt;"&lt;/span&gt;, (&lt;br/&gt;                &lt;span style="color:blue"&gt;from &lt;/span&gt;h &lt;span style="color:blue"&gt;in &lt;/span&gt;section&lt;span style="color:red"&gt;.&lt;/span&gt;Handlers&lt;span style="color:red"&gt;.&lt;/span&gt;Cast&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpHandlerAction&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt;&lt;/span&gt;()&lt;br/&gt;                &lt;span style="color:blue"&gt;let &lt;/span&gt;action &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Format(&lt;span style="color:#a31515"&gt;"path=\"{0}\" verb=\"{1}\" validate=\"{2}\" type=\"{3}\""&lt;/span&gt;,&lt;br/&gt;                        h&lt;span style="color:red"&gt;.&lt;/span&gt;Path, h&lt;span style="color:red"&gt;.&lt;/span&gt;Verb, h&lt;span style="color:red"&gt;.&lt;/span&gt;Validate, h&lt;span style="color:red"&gt;.&lt;/span&gt;Type)&lt;br/&gt;                &lt;span style="color:blue"&gt;select &lt;/span&gt;action)&lt;span style="color:red"&gt;.&lt;/span&gt;ToArray());&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;我的示例网站中的web.config中的&amp;lt;httpHandlers&amp;gt;配置节定义如下：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;add &lt;/span&gt;&lt;span style="color:red"&gt;path&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;Ajax*.*.aspx,Ajax*/*.aspx&lt;/span&gt;" &lt;span style="color:red"&gt;verb&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*&lt;/span&gt;" &lt;span style="color:red"&gt;validate&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;true&lt;/span&gt;" &lt;br/&gt;                &lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;MySimpleServiceFramework.AjaxServiceHandler, MySimpleServiceFramework&lt;/span&gt;" &lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;add &lt;/span&gt;&lt;span style="color:red"&gt;path&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*.test&lt;/span&gt;" &lt;span style="color:red"&gt;verb&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*&lt;/span&gt;" &lt;span style="color:red"&gt;validate&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;true&lt;/span&gt;" &lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;MyTestHandler&lt;/span&gt;" &lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;那么，前面的示例代码的运行结果如下：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012012815450694.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;通过前面分析可知，代码中的HttpHandlers实际就是在运行时所能访问到的&amp;lt;httpHandlers&amp;gt;配置集合。而且，我们在网站中所指定的配置会放在集合的前面，ASP.NET的默认配置会在靠后的位置。接下来的FindMapping(requestType, path)的实现如下：&lt;a href="javascript:void(0);" codeId="pre-FindMapping"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpHandlerAction &lt;/span&gt;FindMapping(&lt;span style="color:blue"&gt;string &lt;/span&gt;verb, &lt;span style="color:#2b91af"&gt;VirtualPath &lt;/span&gt;path)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;ValidateHandlers();&lt;br/&gt;    &lt;span style="color:blue"&gt;for &lt;/span&gt;(&lt;span style="color:blue"&gt;int &lt;/span&gt;i &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;0&lt;/span&gt;; i &lt;span style="color:red"&gt;&amp;lt; &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Handlers&lt;span style="color:red"&gt;.&lt;/span&gt;Count; i&lt;span style="color:red"&gt;++&lt;/span&gt;)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;HttpHandlerAction &lt;/span&gt;action &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Handlers[i];&lt;br/&gt;        &lt;span style="color:blue"&gt;if &lt;/span&gt;(action&lt;span style="color:red"&gt;.&lt;/span&gt;IsMatch(verb, path))&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color:blue"&gt;return &lt;/span&gt;action;&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;return null&lt;/span&gt;;&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;从代码可以看出，其实所谓的【查找】过程，也就是&lt;b class="redText"&gt;【逐一匹配】&lt;/b&gt;每个在&amp;lt;httpHandlers&amp;gt;定义的配置项。&lt;/p&gt;&lt;p&gt;至于action.IsMatch()的匹配方式，我们可以从调用所传递的参数看出，其实只是判断【verb, path】这二个参数而已。这个匹配过程的实现代码较长，我就不贴出它们的实现代码了，而是打算通过示例来说明它是如何匹配的。&lt;/p&gt;&lt;p&gt;action.IsMatch()的匹配方式也可以算是GetHandlerMapping()的核心过程。而这里的action的类型其实是HttpHandlerAction，它与&amp;lt;httpHandlers&amp;gt;配置项一一对应。我们可以先来看一下MSDN是如何解释这个配置项的：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012012815453351.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;从MSDN的解释中可以看出：verb,path都可以支持【通配符(*)】，并且可以使用逗号(,)来分隔多个预期项。ASP.NET在实现通配符时，内部使用正则表达式的方式，具体过程可以自己去阅读相关代码。&lt;/p&gt;&lt;p&gt;下面，我将通过一个具体的配置项来分析这些配置参数：&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;add &lt;/span&gt;&lt;span style="color:red"&gt;path&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;Ajax*.*.aspx,Ajax*/*.aspx&lt;/span&gt;" &lt;span style="color:red"&gt;verb&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*&lt;/span&gt;" &lt;span style="color:red"&gt;validate&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;true&lt;/span&gt;" &lt;br/&gt;        &lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;MySimpleServiceFramework.AjaxServiceHandler, MySimpleServiceFramework&lt;/span&gt;" &lt;span style="color:blue"&gt;/&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;1. path="Ajax*.*.aspx,Ajax*/*.aspx"：表示可以接受【Ajax*.*.aspx】或者【Ajax*/*.aspx】这样的URL格式。&lt;br /&gt;2. verb="*": 表示可以接受所有的HTTP调用，如：GET,POST 等等。&lt;br /&gt;3. type="MySimpleServiceFramework.AjaxServiceHandler, MySimpleServiceFramework": 表示当某个请求匹配path,verb时，交给MySimpleServiceFramework程序集中的MySimpleServiceFramework.AjaxServiceHandler来处理请求。&lt;br /&gt;4. validate="true"：表示在第一次读取&amp;lt;httpHandlers&amp;gt;时，验证type的设置是否有效。如果此项设为false，则表示延迟验证（创建时）。默认值：true&lt;/p&gt;&lt;p&gt;对于这4个属性，有2个比较重要：&lt;br /&gt;1. type:  type中的字符串必须能在运行时找到一个可创建的类型，且该类型必须实现IHttpHandler或者IHttpHandlerFactory接口。&lt;br /&gt;2. path:  在很多资料以及技术书籍中，一般都设置为&lt;b&gt;某类文件扩展名&lt;/b&gt;，如：*.xxx ，事实上，我们完全可以设置为一个URL模式，而且还可以设置多个URL模式。比如上面的配置示例中的path参数，具体在使用时，可以响应来自客户端的以下请求：&lt;a href="javascript:void(0);" codeId="pre-ajax-url"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;$(&lt;span style="color:blue"&gt;function&lt;/span&gt;(){&lt;br/&gt;    $(&lt;span style="color:#a31515"&gt;"#btnSubmit"&lt;/span&gt;).click( &lt;span style="color:blue"&gt;function&lt;/span&gt;(){&lt;br/&gt;        $.ajax({&lt;br/&gt;                &lt;span style="color:green"&gt;// 注意：下面的二个url地址都是可以使用的。&lt;br/&gt;                &lt;/span&gt;url&lt;span style="color:red"&gt;: &lt;/span&gt;&lt;span style="color:#a31515"&gt;"/AjaxServices/GetMd5.aspx"&lt;/span&gt;&lt;span style="color:red"&gt;,&lt;br/&gt;                &lt;/span&gt;&lt;span style="color:green"&gt;//url: "/AjaxServices.GetMd5.aspx",&lt;br/&gt;                &lt;br/&gt;                // 注意：下面的二种type的设置也都是可以使用的。&lt;br/&gt;                &lt;/span&gt;type&lt;span style="color:red"&gt;: &lt;/span&gt;&lt;span style="color:#a31515"&gt;"POST"&lt;/span&gt;&lt;span style="color:red"&gt;, &lt;br/&gt;                &lt;/span&gt;&lt;span style="color:green"&gt;//type: "GET", &lt;br/&gt;                &lt;br/&gt;                &lt;/span&gt;data&lt;span style="color:red"&gt;: &lt;/span&gt;{ str&lt;span style="color:red"&gt;: &lt;/span&gt;$(&lt;span style="color:#a31515"&gt;"#txtInput"&lt;/span&gt;).val() }&lt;span style="color:red"&gt;,&lt;br/&gt;                &lt;/span&gt;dataType&lt;span style="color:red"&gt;: &lt;/span&gt;&lt;span style="color:#a31515"&gt;"text"&lt;/span&gt;&lt;span style="color:red"&gt;,&lt;br/&gt;                &lt;/span&gt;success&lt;span style="color:red"&gt;: &lt;/span&gt;&lt;span style="color:blue"&gt;function&lt;/span&gt;(responseText){&lt;br/&gt;                    $(&lt;span style="color:#a31515"&gt;"#md5Result"&lt;/span&gt;).text(responseText);&lt;br/&gt;                }&lt;br/&gt;            });    &lt;br/&gt;    });&lt;br/&gt;});&lt;br/&gt;&lt;p&gt;注意：在path中直接使用某个扩展名的好处是不受配置项的顺序影响，而且容易理解，因为可读性较好。&lt;/p&gt;&lt;p&gt;这里要补充一点：MySimpleServiceFramework是我在博客&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/09/05/2168073.html" target="_blank"&gt;【用Asp.net写自己的服务框架】&lt;/a&gt;中实现的那个框架。&lt;br /&gt;在服务端，可以使用下面的代码来处理前面客户端发出的请求：&lt;a href="javascript:void(0);" codeId="pre-AjaxServices"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;[&lt;span style="color:#2b91af"&gt;MyService&lt;/span&gt;]&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;AjaxServices&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    [&lt;span style="color:#2b91af"&gt;MyServiceMethod&lt;/span&gt;]&lt;br/&gt;    &lt;span style="color:blue"&gt;public string &lt;/span&gt;GetMd5(&lt;span style="color:blue"&gt;string &lt;/span&gt;str)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( str &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;)&lt;br/&gt;            str &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Empty;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;byte&lt;/span&gt;[] bb &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MD5CryptoServiceProvider&lt;/span&gt;())&lt;span style="color:red"&gt;.&lt;/span&gt;ComputeHash(&lt;span style="color:#2b91af"&gt;Encoding&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Default&lt;span style="color:red"&gt;.&lt;/span&gt;GetBytes(str));&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BitConverter&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;ToString(bb)&lt;span style="color:red"&gt;.&lt;/span&gt;Replace(&lt;span style="color:#a31515"&gt;"-"&lt;/span&gt;, &lt;span style="color:#a31515"&gt;""&lt;/span&gt;);&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;前面的示例配置中：path="Ajax*.*.aspx,Ajax*/*.aspx" ，我使用了aspx这个扩展名。&lt;br /&gt;我想大家都知道aspx这个扩展名是ASP.NET可处理的扩展名，为什么我还可以使用呢？&lt;br /&gt;其实这个问题的答案在我前面的截图以及FindMapping的实现代码中：由于我们指定的配置要优先于ASP.NET的默认配置，所以先有机会参与匹配，并能匹配成功。&lt;/p&gt;&lt;p&gt;&lt;b&gt;小结：&lt;/b&gt;在GetHandlerMapping()过程中，会根据请求的URL地址以及HTTP调用动作（GET,POST），返回一个在&amp;lt;httpHandlers&amp;gt;定义的配置项（HttpHandlerAction类型）。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;GetFactory()&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在GetHandlerMapping()返回一个HttpHandlerAction的配置项后，HttpApplication会调用this.GetFactory(mapping);获取一个IHttpHandlerFactory ，本小节将来分析这个过程。&lt;/p&gt;&lt;p&gt;首先，我们还是来看一下GetFactory的实现代码：&lt;a href="javascript:void(0);" codeId="pre-GetFactory"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Hashtable &lt;/span&gt;_handlerFactories &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Hashtable&lt;/span&gt;();&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IHttpHandlerFactory &lt;/span&gt;GetFactory(&lt;span style="color:#2b91af"&gt;HttpHandlerAction &lt;/span&gt;mapping)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;// 先尝试从内部缓存中获取&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HandlerFactoryCache &lt;/span&gt;cache &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;HandlerFactoryCache&lt;/span&gt;) &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;_handlerFactories[mapping&lt;span style="color:red"&gt;.&lt;/span&gt;Type];&lt;br/&gt;    &lt;span style="color:blue"&gt;if &lt;/span&gt;(cache &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:green"&gt;// 创建一个缓存项并保存&lt;br/&gt;        &lt;/span&gt;cache &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HandlerFactoryCache&lt;/span&gt;(mapping);&lt;br/&gt;        &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;_handlerFactories[mapping&lt;span style="color:red"&gt;.&lt;/span&gt;Type] &lt;span style="color:red"&gt;= &lt;/span&gt;cache;&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:green"&gt;// 返回工厂对象&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;return &lt;/span&gt;cache&lt;span style="color:red"&gt;.&lt;/span&gt;Factory;&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;代码中做了哪些事情，我在注释中有说明。这个方法的最后一定会返回一个IHttpHandlerFactory的实例。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;看到这里，您觉得奇怪吗？&lt;br /&gt;&lt;b&gt;可能我们仅仅只是实现了一个自定义的IHttpHanlder接口，并没有实现IHttpHandlerFactory，那么ASP.NET是如何处理的呢？&lt;/b&gt;&lt;/p&gt;&lt;p&gt;请注意 new HandlerFactoryCache(mapping) 这行代码，这可不是简单地创建一个缓存对象，具体实现代码如下：&lt;a href="javascript:void(0);" codeId="pre-HandlerFactoryCache"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HandlerFactoryCache&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IHttpHandlerFactory &lt;/span&gt;_factory;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;internal &lt;/span&gt;HandlerFactoryCache(&lt;span style="color:#2b91af"&gt;HttpHandlerAction &lt;/span&gt;mapping)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:green"&gt;// 根据HttpHandlerAction配置中的type字符串创建对应类型的对象&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:blue"&gt;object &lt;/span&gt;obj2 &lt;span style="color:red"&gt;= &lt;/span&gt;mapping&lt;span style="color:red"&gt;.&lt;/span&gt;Create();&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( obj2 &lt;span style="color:blue"&gt;is &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;) {&lt;br/&gt;            &lt;span style="color:green"&gt;// 如果我们的配置是一个IHttpHandler，&lt;br/&gt;            // 那么ASP.NET会为我们包装成一个HandlerFactoryWrapper&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;_factory &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HandlerFactoryWrapper&lt;/span&gt;((&lt;span style="color:#2b91af"&gt;IHttpHandler&lt;/span&gt;)obj2, &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetHandlerType(mapping));&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color:blue"&gt;else &lt;/span&gt;{&lt;br/&gt;            &lt;span style="color:green"&gt;// 如果不是IHttpHandler以及IHttpHandlerFactory，就抛出异常&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:red"&gt;!&lt;/span&gt;(obj2 &lt;span style="color:blue"&gt;is &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IHttpHandlerFactory&lt;/span&gt;) ) {&lt;br/&gt;                &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"Type_not_factory_or_handler"&lt;/span&gt;);&lt;br/&gt;            }&lt;br/&gt;            &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;_factory &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;IHttpHandlerFactory&lt;/span&gt;)obj2;&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;p&gt;代码中，我加入的注释已经回答了前面提出的问题：如果是一个IHttpHandler对象，ASP.NET会再创建一个HandlerFactoryWrapper对象来包装IHttpHandler对象，如果是IHttpHandlerFactory对象，则直接返回。&lt;br /&gt;我们再来看一下HandlerFactoryWrapper的实现代码：&lt;a href="javascript:void(0);" codeId="pre-HandlerFactoryWrapper"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HandlerFactoryWrapper &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IHttpHandlerFactory&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;_handler;&lt;br/&gt;    &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Type &lt;/span&gt;_handlerType;&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;internal &lt;/span&gt;HandlerFactoryWrapper(&lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;handler, &lt;span style="color:#2b91af"&gt;Type &lt;/span&gt;handlerType)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;_handler &lt;span style="color:red"&gt;= &lt;/span&gt;handler;&lt;br/&gt;        &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;_handlerType &lt;span style="color:red"&gt;= &lt;/span&gt;handlerType;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;GetHandler(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context, &lt;br/&gt;                                &lt;span style="color:blue"&gt;string &lt;/span&gt;requestType, &lt;span style="color:blue"&gt;string &lt;/span&gt;url, &lt;span style="color:blue"&gt;string &lt;/span&gt;pathTranslated)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;_handler &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null &lt;/span&gt;) &lt;br/&gt;            &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;_handler &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;IHttpHandler&lt;/span&gt;)&lt;span style="color:#2b91af"&gt;HttpRuntime&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;CreateNonPublicInstance(&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;_handlerType);&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;return this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;_handler;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public void &lt;/span&gt;ReleaseHandler(&lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;handler)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:green"&gt;// 一个HttpHandler是否能重用，这里就是一个典型的实现方式&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:red"&gt;!&lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;_handler&lt;span style="color:red"&gt;.&lt;/span&gt;IsReusable ) &lt;br/&gt;            &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;_handler &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&lt;b&gt;小结：&lt;/b&gt;HttpApplication会根据web.config中的配置去查找一个匹配的IHttpHandlerFactory类型, 即使我们配置的是自定义的IHttpHandler类型，而不是IHttpHandlerFactory类型，调用过程依然如此。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;GetHandler()&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在ASP.NET中，定义了二个版本的HttpHandlerFactory接口，分别为：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public interface &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IHttpHandlerFactory&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;GetHandler(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context, &lt;br/&gt;                            &lt;span style="color:blue"&gt;string &lt;/span&gt;requestType, &lt;span style="color:blue"&gt;string &lt;/span&gt;url, &lt;span style="color:blue"&gt;string &lt;/span&gt;pathTranslated);&lt;br/&gt;    &lt;span style="color:blue"&gt;void &lt;/span&gt;ReleaseHandler(&lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;handler);&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal interface &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IHttpHandlerFactory2 &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IHttpHandlerFactory&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;GetHandler(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context, &lt;br/&gt;                            &lt;span style="color:blue"&gt;string &lt;/span&gt;requestType, &lt;span style="color:#2b91af"&gt;VirtualPath &lt;/span&gt;virtualPath, &lt;span style="color:blue"&gt;string &lt;/span&gt;physicalPath);&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;设计IHttpHandlerFactory接口的目的是为了在创建和重用IHttpHandler对象时，保留了足够的扩展机会，而IHttpHandlerFactory2则是一个仅供微软使用的内部接口（因为VirtualPath类型的可见性也是internal）。&lt;/p&gt;&lt;p&gt;我们都知道aspx, ashx能直接处理HTTP请求，它们都实现了IHttpHandler接口。它们能处理HTTP请求也因为ASP.NET已经配置过它们。以下是它们的默认配置：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;add &lt;/span&gt;&lt;span style="color:red"&gt;path&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*.aspx&lt;/span&gt;" &lt;span style="color:red"&gt;verb&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*&lt;/span&gt;" &lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;System.Web.UI.PageHandlerFactory&lt;/span&gt;" &lt;span style="color:red"&gt;validate&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;true&lt;/span&gt;"&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;add &lt;/span&gt;&lt;span style="color:red"&gt;path&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*.ashx&lt;/span&gt;" &lt;span style="color:red"&gt;verb&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*&lt;/span&gt;" &lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;System.Web.UI.SimpleHandlerFactory&lt;/span&gt;" &lt;span style="color:red"&gt;validate&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;true&lt;/span&gt;"&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;有趣的是：PageHandlerFactory和SimpleHandlerFactory都实现了IHttpHandlerFactory2接口，因此，它们都可以根据要请求的路径创建一个IHttpHandler实例。&lt;/p&gt;&lt;p&gt;从ASP.NET的默认配置，我们也可以看到：&lt;b&gt;type参数是可以设置为一个实现IHttpHandlerFactory接口的类型，而不一定要求是实现IHttpHandler接口的类型。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;小结：&lt;/b&gt;HttpApplication在处理请求时，并不会直接创建一个IHttpHandler的实例，而是先获取一个IHttpHandlerFactory的对象，再以接口的形式调用GetHandler()方法来获取一个IHttpHandler实例。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;IHttpHandler.IsReusable&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;IHttpHandler接口有个IsReusable属性。MSDN对这个属性的说明也非常简单：&lt;/p&gt;&lt;p class="msdnRef"&gt;获取一个值，该值指示其他请求是否可以使用 IHttpHandler 实例。&lt;/p&gt;&lt;p&gt;按照这个说明，当我们直接在创建一个实现IHttpHandler的类型，并在web.config中注册到一个自定义的扩展名时，情况会如何呢？&lt;br /&gt;我们再来看一下前面所提过的示例代码（MyTestHandler的）：&lt;a href="javascript:void(0);" codeId="pre-MyTestHandler2"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;MyTestHandler &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IHttpHandler&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Counter &lt;/span&gt;_counter &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Counter&lt;/span&gt;();&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public bool &lt;/span&gt;IsReusable&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;get &lt;/span&gt;{ &lt;span style="color:blue"&gt;return true&lt;/span&gt;; }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public void &lt;/span&gt;ProcessRequest(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context)&lt;br/&gt;    {&lt;br/&gt;        _counter&lt;span style="color:red"&gt;.&lt;/span&gt;ShowCountAndRequestInfo(context);&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;web.config中的配置为：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;add &lt;/span&gt;&lt;span style="color:red"&gt;path&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*.test&lt;/span&gt;" &lt;span style="color:red"&gt;verb&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*&lt;/span&gt;" &lt;span style="color:red"&gt;validate&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;true&lt;/span&gt;" &lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;MyTestHandler&lt;/span&gt;" &lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;当我连续5次访问 http://localhost:51652/abc.test?id=1 时，会在浏览器中看到以下输出结果：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012012815455511.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;从这个截图来看，显然：MyTestHandler的实例&lt;b&gt;被重用了。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;我想很多人都创建过ashx文件，IDE会为我们创建一个实现了IHttpHandler接口的类型，在实现IsReusable属性时，一般都会这样：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public bool &lt;/span&gt;IsReusable {&lt;br/&gt;    &lt;span style="color:blue"&gt;get &lt;/span&gt;{&lt;br/&gt;        &lt;span style="color:blue"&gt;return false&lt;/span&gt;;&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;有些人看到这个，会想：如果返回true，就可以重用IHttpHandler实例，达到优化性能的目的。但事实上，即使你在ashx中返回true也是无意义的，因为您可以试着这样去实现这个属性：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public bool &lt;/span&gt;IsReusable&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;get &lt;/span&gt;{ &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Exception&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"这里不起作用。"&lt;/span&gt;); }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;如果您访问那个ashx，会发现：根本没有异常出现！&lt;br /&gt;因此，我们可以得出一个结论：默认情况下，IsReusable不能决定一个ashx的实例是否能重用。&lt;/p&gt;&lt;p&gt;这个结果太奇怪了。为什么会这样呢？&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;前面我们看到*.ashx的请求交给SimpleHandlerFactory来创建相应的HttpHandler对象，然而当ASP.NET调用SimpleHandlerFactory.GetHandler()方法时，该方法会&lt;b&gt;直接创建并返回&lt;/b&gt;我们实现的类型实例。换句话说：SimpleHandlerFactory根本不使用IHttpHandler.IsReusable的属性，因此，这种情况下，想重用ashx的实例是不可能的事，所以，即使我在实现IsReusable属性时，写上抛异常的语句，根本也不会被调用。&lt;/p&gt;&lt;p&gt;同样的事情还发在aspx页面的实例上，所以，在默认情况下，我们不可能重用aspx, ashx的实例。&lt;/p&gt;&lt;p&gt;至于aspx的实例不能重用，除了和PageHandlerFactory有关外，还与Page在实现IHttpHandler.IsReusable有关，以下是Page的实现方式：&lt;a href="javascript:void(0);" codeId="pre-page-IsReusable"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public bool &lt;/span&gt;IsReusable&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;get &lt;/span&gt;{ &lt;span style="color:blue"&gt;return false&lt;/span&gt;; }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;从代码可以看到微软在Page是否重用上的明确想法：就是不允许重用！&lt;/p&gt;&lt;p&gt;由于Page的IsReusable属性我们平时看不到，我想没人对它的重用性有产生过疑惑，但ashx就不同了，它的IsReusable属性的代码是摆在我们面前的，任何人都可以看到它，试想一下：当有人发现把它设为true or false时都不起作用，会是个什么想法？估计很多人会郁闷。&lt;/p&gt;&lt;p&gt;&lt;b&gt;小结：&lt;/b&gt;IHttpHandler.IsReusable并不能决定是否重用HttpHanlder ！&lt;/p&gt;&lt;p&gt;&lt;strong&gt;实现自己的HttpHandlerFactory&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;通过前面的示例，我们也看到了，虽然IHttpHandler定义了一个IsReusable属性，但它并不能决定此类型的实例是否能得到重用。重不重用，其实是由HttpHandlerFactory来决定的。ashx的实例不能重用就是一个典型的例子。&lt;/p&gt;&lt;p&gt;下面我就来演示如何实现自己的HttpHandlerFactory来重用ashx的实例。示例代码如下（&lt;b&gt;注意代码中的注释&lt;/b&gt;）：&lt;a href="javascript:void(0);" codeId="pre-ReusableAshxHandlerFactory"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;ReusableAshxHandlerFactory &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IHttpHandlerFactory&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Dictionary&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;IHttpHandler&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt; &lt;/span&gt;_cache &lt;br/&gt;        &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Dictionary&lt;/span&gt;&lt;span style="color:red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:blue"&gt;string&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;IHttpHandler&lt;/span&gt;&lt;span style="color:red"&gt;&amp;gt;&lt;/span&gt;(&lt;span style="color:purple"&gt;200&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;StringComparer&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;OrdinalIgnoreCase);&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;GetHandler(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context, &lt;br/&gt;                            &lt;span style="color:blue"&gt;string &lt;/span&gt;requestType, &lt;span style="color:blue"&gt;string &lt;/span&gt;virtualPath, &lt;span style="color:blue"&gt;string &lt;/span&gt;physicalPath)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;string &lt;/span&gt;cacheKey &lt;span style="color:red"&gt;= &lt;/span&gt;requestType &lt;span style="color:red"&gt;+ &lt;/span&gt;virtualPath;&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 检查是否有缓存的实例（或者可理解为：被重用的实例）&lt;br/&gt;        &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;handler &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( _cache&lt;span style="color:red"&gt;.&lt;/span&gt;TryGetValue(cacheKey, &lt;span style="color:blue"&gt;out &lt;/span&gt;handler) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;) {&lt;br/&gt;            &lt;span style="color:green"&gt;// 根据请求路径创建对应的实例&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Type &lt;/span&gt;handlerType &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;BuildManager&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;GetCompiledType(virtualPath);&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:green"&gt;// 确保一定是IHttpHandler类型&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:blue"&gt;typeof&lt;/span&gt;(&lt;span style="color:#2b91af"&gt;IHttpHandler&lt;/span&gt;)&lt;span style="color:red"&gt;.&lt;/span&gt;IsAssignableFrom(handlerType) &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;false &lt;/span&gt;)&lt;br/&gt;                &lt;span style="color:blue"&gt;throw new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;HttpException&lt;/span&gt;(&lt;span style="color:#a31515"&gt;"要访问的资源没有实现IHttpHandler接口。"&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:green"&gt;// 创建实例，并保存到成员字段中&lt;br/&gt;            &lt;/span&gt;handler &lt;span style="color:red"&gt;= &lt;/span&gt;(&lt;span style="color:#2b91af"&gt;IHttpHandler&lt;/span&gt;)&lt;span style="color:#2b91af"&gt;Activator&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;CreateInstance(handlerType, &lt;span style="color:blue"&gt;true&lt;/span&gt;);&lt;br/&gt;&lt;br/&gt;            &lt;span style="color:green"&gt;// 如果handler要求重用，则保存它的引用。&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( handler&lt;span style="color:red"&gt;.&lt;/span&gt;IsReusable )&lt;br/&gt;                _cache[cacheKey] &lt;span style="color:red"&gt;= &lt;/span&gt;handler;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:blue"&gt;return &lt;/span&gt;handler;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public void &lt;/span&gt;ReleaseHandler(&lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;handler)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:green"&gt;// 不需要处理这个方法。&lt;br/&gt;    &lt;/span&gt;}&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;为了能让HttpHandlerFactory能在ASP.NET中运行，还需要在web.config中注册：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;add &lt;/span&gt;&lt;span style="color:red"&gt;path&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*.ashx&lt;/span&gt;" &lt;span style="color:red"&gt;verb&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*&lt;/span&gt;" &lt;span style="color:red"&gt;validate&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;false&lt;/span&gt;" &lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;ReusableAshxHandlerFactory&lt;/span&gt;"&lt;span style="color:blue"&gt;/&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;有了这个配置后，我们可以创建一个Handler2.ashx来测试效果：&lt;a href="javascript:void(0);" codeId="pre-Handler2"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;@ &lt;/span&gt;&lt;span style="color:#a31515"&gt;WebHandler &lt;/span&gt;&lt;span style="color:red"&gt;Language&lt;/span&gt;&lt;span style="color:blue"&gt;="C#" &lt;/span&gt;&lt;span style="color:red"&gt;Class&lt;/span&gt;&lt;span style="color:blue"&gt;="Handler2" &lt;/span&gt;&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;using &lt;/span&gt;System;&lt;br/&gt;&lt;span style="color:blue"&gt;using &lt;/span&gt;System&lt;span style="color:red"&gt;.&lt;/span&gt;Web;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Handler2 &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;{&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Counter &lt;/span&gt;_counter &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Counter&lt;/span&gt;();&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public bool &lt;/span&gt;IsReusable&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;get &lt;/span&gt;{ &lt;span style="color:blue"&gt;return true&lt;/span&gt;; }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public void &lt;/span&gt;ProcessRequest(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context)&lt;br/&gt;    {&lt;br/&gt;        _counter&lt;span style="color:red"&gt;.&lt;/span&gt;ShowCountAndRequestInfo(context);&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;在多次访问Handler2.ashx后，我们可以看到以下效果：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012012815461759.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;再来看看按照IDE默认生成的IsReusable会在运行时出现什么结果。示例代码：&lt;a href="javascript:void(0);" codeId="pre-Handler1"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;@ &lt;/span&gt;&lt;span style="color:#a31515"&gt;WebHandler &lt;/span&gt;&lt;span style="color:red"&gt;Language&lt;/span&gt;&lt;span style="color:blue"&gt;="C#" &lt;/span&gt;&lt;span style="color:red"&gt;Class&lt;/span&gt;&lt;span style="color:blue"&gt;="Handler1" &lt;/span&gt;&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;using &lt;/span&gt;System;&lt;br/&gt;&lt;span style="color:blue"&gt;using &lt;/span&gt;System&lt;span style="color:red"&gt;.&lt;/span&gt;Web;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Handler1 &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;{&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;private &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Counter &lt;/span&gt;_counter &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Counter&lt;/span&gt;();&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public bool &lt;/span&gt;IsReusable&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:blue"&gt;get &lt;/span&gt;{&lt;br/&gt;            &lt;span style="color:green"&gt;// 如果在配置文件中启用ReusableAshxHandlerFactory，那么这里将会被执行。&lt;br/&gt;            // 可以尝试切换下面二行代码测试效果。&lt;br/&gt;&lt;br/&gt;            //throw new Exception("这里不起作用。");&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:blue"&gt;return false&lt;/span&gt;;&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span style="color:blue"&gt;public void &lt;/span&gt;ProcessRequest(&lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context)&lt;br/&gt;    {&lt;br/&gt;        _counter&lt;span style="color:red"&gt;.&lt;/span&gt;ShowCountAndRequestInfo(context);&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;此时，无论我访问Handler1.ashx多少次，浏览器始终显示如下结果：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012012815463847.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;如果我启用代码行 &lt;b&gt;throw new Exception("这里不起作用。");&lt;/b&gt; 将会看到以下结果：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012012815465861.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;终于，我们期待的黄页出现了。&lt;br /&gt;此时，如果我在web.config中将ReusableAshxHandlerFactory的注册配置注释起来，发现Handler1.ashx还是可以访问的。&lt;/p&gt;&lt;p&gt;回想一下前面我们看到的IHttpHandlerFactory接口，它还定义了一个ReleaseHandler方法，这个方法又是做什么的呢？对于这个方法，MSDN也有一句简单的说明：&lt;/p&gt;&lt;p class="msdnRef"&gt;使工厂可以重用现有的处理程序实例。&lt;/p&gt;&lt;p&gt;对于这个说明，我认为并不恰当。如果按照HandlerFactoryWrapper的实现方式，那么这个解释是正确的。但我前面的示例中，我在实现这个方法时，没有任何代码，但一样可以达到重用HttpHandler的目的。因此，我认为重用的方式取决于具体的实现方式。&lt;/p&gt;&lt;p&gt;&lt;b&gt;小结：&lt;/b&gt;IHttpHandler.IsReusable并不能完全决定HttpHandler的实例是否能重用，它只起到一个指示作用。HttpHandler如何重用，关键还是要由HttpHandlerFactory来实现。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;是否需要IsReusable = true ？&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;经过前面文字讲解以及示例演示，有些人可能会想：我在实现IHttpHandler的IsReusable属性时，要不要返回true呢？（&lt;i&gt;千万别模仿我的示例代码抛异常哦。&lt;/i&gt;&lt;span class="icon_smile"&gt;&lt;/span&gt;）&lt;/p&gt;&lt;p&gt;如果返回true，则HttpHandler能得到重用，&lt;b&gt;或许某些场合下，&lt;/b&gt;是可以达到性能优化的目的。&lt;br /&gt;但是，它也可能会引发新的问题：&lt;b&gt;HttpHandler实例的一些状态会影响后续的请求。&lt;/b&gt;&lt;br /&gt;也正是由于这个原因，aspx, ashx 的实例在默认情况下，都是不重用的。&lt;/p&gt;&lt;p&gt;有些人还可能会担心：被重用的HttpHandler是否有线程安全问题？&lt;br /&gt;理论上，在ASP.NET中，只要使用static的数据成员都会有这个问题。不过，这里所说的&lt;b&gt;被重用的单个HttpHandler实例&lt;/b&gt;在处理请求过程中，只会被一个线程所调用，因此，它的实例成员还是线程安全的。但有一点需要注意：在HttpHandlerFactory中实现重用HttpHandler时，缓存HttpHandler的容器要保证是线程安全的。&lt;/p&gt;&lt;p&gt;如果您希望重用HttpHandler来提升程序性能，那么我建议应该考虑以下问题：&lt;br /&gt;HttpHandler的所有数据成员都能在处理请求前初始化。（通常会在后期维护时遗忘，尤其是多人维护时）&lt;/p&gt;&lt;p&gt;&lt;b&gt;小结：&lt;/b&gt;在通常情况下，当实现IsReusable时返回false，虽然性能上不是最优，但却是最安全的做法。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;HttpHandlerFactory的主要用途&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;前面示例演示了如何使用HttpHandlerFactory来重用HttpHandler，但设计HttpHandlerFactory并不是完全为了这个目的，它的主要用途还是如何创建HttpHandler，而且定义IHttpHandlerFactory的主要目的是为了扩展性。&lt;/p&gt;&lt;p&gt;我想很多人也许使用过 Web Service ，它运行在ASP.NET平台上，自然也有对应的HttpHandler，我们来看看asmx这个扩展名是如何映射的。&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;add &lt;/span&gt;&lt;span style="color:red"&gt;path&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*.asmx&lt;/span&gt;" &lt;span style="color:red"&gt;verb&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;*&lt;/span&gt;"  &lt;span style="color:red"&gt;validate&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;false&lt;/span&gt;"&lt;br/&gt;     &lt;span style="color:red"&gt;type&lt;/span&gt;&lt;span style="color:blue"&gt;=&lt;/span&gt;"&lt;span style="color:blue"&gt;System.Web.Services.Protocols.WebServiceHandlerFactory, &lt;br/&gt;     System.Web.Services, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a&lt;/span&gt;"&lt;span style="color:blue"&gt;/&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;接着找WebServiceHandlerFactory，最后发现是这样创建的HttpHandler :&lt;a href="javascript:void(0);" codeId="pre-WebServiceHandlerFactory"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal &lt;/span&gt;&lt;span style="color:#2b91af"&gt;IHttpHandler &lt;/span&gt;CoreGetHandler(&lt;span style="color:#2b91af"&gt;Type &lt;/span&gt;type, &lt;br/&gt;        &lt;span style="color:#2b91af"&gt;HttpContext &lt;/span&gt;context, &lt;span style="color:#2b91af"&gt;HttpRequest &lt;/span&gt;request, &lt;span style="color:#2b91af"&gt;HttpResponse &lt;/span&gt;response)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color:green"&gt;// ..... 已删除一些无关的代码&lt;br/&gt;&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;bool &lt;/span&gt;isAsync &lt;span style="color:red"&gt;= &lt;/span&gt;protocol&lt;span style="color:red"&gt;.&lt;/span&gt;MethodInfo&lt;span style="color:red"&gt;.&lt;/span&gt;IsAsync;&lt;br/&gt;    &lt;span style="color:blue"&gt;bool &lt;/span&gt;enableSession &lt;span style="color:red"&gt;= &lt;/span&gt;protocol&lt;span style="color:red"&gt;.&lt;/span&gt;MethodAttribute&lt;span style="color:red"&gt;.&lt;/span&gt;EnableSession;&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( isAsync ) {&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( enableSession ) {&lt;br/&gt;            &lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;AsyncSessionHandler&lt;/span&gt;(protocol);&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;AsyncSessionlessHandler&lt;/span&gt;(protocol);&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;if&lt;/span&gt;( enableSession ) {&lt;br/&gt;        &lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;SyncSessionHandler&lt;/span&gt;(protocol);&lt;br/&gt;    }&lt;br/&gt;    &lt;span style="color:blue"&gt;return new &lt;/span&gt;&lt;span style="color:#2b91af"&gt;SyncSessionlessHandler&lt;/span&gt;(protocol);&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;这才是Factory嘛！&lt;/p&gt;&lt;p&gt;老实说，看到这几句话，我是眼前一亮：用HttpHandlerFactory来动态处理【是否支持Session】实在是太合适了。&lt;/p&gt;&lt;p&gt;这里有必要补充一下：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;internal class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;SyncSessionHandler &lt;/span&gt;: &lt;span style="color:#2b91af"&gt;SyncSessionlessHandler&lt;/span&gt;, &lt;span style="color:#2b91af"&gt;IRequiresSessionState&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;&lt;b&gt;小结：&lt;/b&gt;HttpHandlerFactory用途并非是为了专门处理HttpHandler的重用，它只是一个Factory，WebServiceHandlerFactory从另一个角度向我们展示了HttpHandlerFactory在扩展性方面所体现的重要作用。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://files.cnblogs.com/fish-li/HttpHandlerMapping_20120127.cab.7z"&gt;点击此处下载示例代码&lt;/a&gt;&lt;/p&gt;&lt;div class="articleFooter"&gt;&lt;p&gt;如果，您认为阅读这篇博客让您有些收获，不妨点击一下右下角的&lt;a id="btnRecommendMyBlog" href="javascript:void(0);"&gt;【&lt;b&gt;推荐&lt;/b&gt;】&lt;/a&gt;按钮。&lt;br /&gt;如果，您希望更容易地发现我的新博客，不妨点击一下右下角的&lt;a id="btnFollowFishLi" href="javascript:void(0);"&gt;【&lt;b&gt;关注 Fish Li&lt;/b&gt;】&lt;/a&gt;。&lt;br /&gt;因为，我的写作热情也离不开您的肯定支持。&lt;/p&gt;&lt;p&gt;感谢您的阅读，如果您对我的博客所讲述的内容有兴趣，请继续关注我的后续博客，我是Fish Li 。&lt;span class="icon_smile"&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/fish-li/aggbug/2331477.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/01/29/2331477.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/fish-li/archive/2012/01/11/2320027.html</id><title type="text">细说 ASP.NET控制HTTP缓存</title><summary type="text">在上篇博客【细说 ASP.NET Cache 及其高级用法】中，我给大家介绍了ASP.NET Cache，这种服务端使用的缓存API 。在我们开发一个ASP.NET网站的过程中，其实有很多地方都是可以使用缓存的，只是由于ASP.NET是一种基于服务端的开发平台，自然我们也经常在服务端的代码中使用各类缓存技术，然而，由于WEB应用程序的服务对象是客户端的浏览器，通常来说，我们并不能直接控制浏览器的行为，但是，浏览器却可以根据后台网站的指示，采取一些优化的方式来更快地呈现页面。客户端浏览器也有自己的缓存机制，通常浏览器也使用缓存来优化一些页面的显示过程，不过，我们并不能直接使用C#代码控制浏览器的</summary><published>2012-01-11T15:55:00Z</published><updated>2012-01-11T15:55:00Z</updated><author><name>Fish Li</name><uri>http://www.cnblogs.com/fish-li/</uri></author><link rel="alternate" href="http://www.cnblogs.com/fish-li/archive/2012/01/11/2320027.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/fish-li/archive/2012/01/11/2320027.html"/><content type="html">&lt;p&gt;在上篇博客&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/12/27/2304063.html" target="_blank"&gt;【细说 ASP.NET Cache 及其高级用法】&lt;/a&gt;中，我给大家介绍了ASP.NET Cache，这种服务端使用的缓存API 。在我们开发一个ASP.NET网站的过程中，其实有很多地方都是可以使用缓存的，只是由于ASP.NET是一种基于服务端的开发平台，自然我们也经常在服务端的代码中使用各类缓存技术，然而，由于WEB应用程序的服务对象是客户端的浏览器，通常来说，我们并不能直接控制浏览器的行为，但是，浏览器却可以根据后台网站的指示，采取一些优化的方式来更快地呈现页面。客户端浏览器也有自己的缓存机制，通常浏览器也使用缓存来优化一些页面的显示过程，不过，我们并不能直接使用C#代码控制浏览器的缓存操作，但我们可以告诉浏览器如何使用缓存，从而达到优化网站性能的目的。&lt;/p&gt;&lt;p&gt;这次博客的主题是：用ASP.NET控制HTTP请求过程中浏览器缓存的一些方法。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;正常的HTTP请求过程&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在开始介绍浏览器在HTTP请求过程前，我想有必要先来看一下浏览器请求一个普通ASPX页面的过程。&lt;br /&gt;说明：本文在介绍HTTP请求过程时，会大量使用Fiddler来分析具体的请求过程。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012011123492026.gif" alt="" /&gt;&lt;/p&gt;&lt;p&gt;上图是一个普通的ASPX页面的请求过程，说它普通是因为：我在创建这个页面后，没对它做任何缓存方面的处理。&lt;br /&gt;图片中我们可以可以看到服务器的响应状态为：HTTP/1.1 200 OK，这是一个服务器成功响应的标志。&lt;br /&gt;另外，要注意图片中的Cache响应头部分，我之所以就红线框出来，是想提醒您注意这块的内容将在后面的小节中发生改变，到时候请注意对比它们。而这里所反映的情况其实也只是默认值而已，它并不表示此页面需要缓存。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;缓存页的请求过程&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;下面再来看一个缓存页面的请求过程：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012011123494331.gif" alt="" /&gt;&lt;/p&gt;&lt;p&gt;对比上一张图片中可以看出，现在多了【max-age】，【Expires】以及【Last-Modified】这三个响应头。&lt;/p&gt;&lt;p&gt;这三个头的含义如下：&lt;br /&gt;1. max-age，Expires：要表达的意思基本差不多。max-age表示某次HTTP的响应结果应该缓存多少秒。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;而Expires是说某次HTTP的响应结果应缓存到什么时候过期，此时间是一个UTC时间。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;另一个Date头表示HTPP响应的发出时间，我们可以发现 Date + max-age = Expires&lt;br /&gt;2. Last-Modified：服务端告诉客户端本次响应返回的HTTP文档的最后修改时间。这个头与304的实现有关，后面再来解释。&lt;/p&gt;&lt;p&gt;分析了HTTP请求过程后，我们再来看一下服务端的页面是什么样子的：&lt;a href="javascript:void(0);" codeId="pre-demo-1"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;@ &lt;/span&gt;&lt;span style="color:#a31515"&gt;Page &lt;/span&gt;&lt;span style="color:red"&gt;Language&lt;/span&gt;&lt;span style="color:blue"&gt;="C#" &lt;/span&gt;&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;@ &lt;/span&gt;&lt;span style="color:#a31515"&gt;OutputCache &lt;/span&gt;&lt;span style="color:red"&gt;Duration&lt;/span&gt;&lt;span style="color:blue"&gt;="10" &lt;/span&gt;&lt;span style="color:red"&gt;VaryByParam&lt;/span&gt;&lt;span style="color:blue"&gt;="None" &lt;/span&gt;&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;html &lt;/span&gt;&lt;span style="color:red"&gt;xmlns&lt;/span&gt;&lt;span style="color:blue"&gt;="http://www.w3.org/1999/xhtml"&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;head&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;title&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;http://www.cnblogs.com/fish-li/&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;title&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;head&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;body&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;页面生成时间：&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af"&gt;DateTime&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Now&lt;span style="color:red"&gt;.&lt;/span&gt;ToString() &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;a &lt;/span&gt;&lt;span style="color:red"&gt;href&lt;/span&gt;&lt;span style="color:blue"&gt;="Default.aspx"&amp;gt;&lt;/span&gt;回到首页&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;a&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515"&gt;a &lt;/span&gt;&lt;span style="color:red"&gt;href&lt;/span&gt;&lt;span style="color:blue"&gt;="&lt;/span&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;= Request.RawUrl &lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue"&gt;"&amp;gt;&lt;/span&gt;刷新本页&lt;span style="color:blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;a&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;p&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;body&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;br/&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515"&gt;html&lt;/span&gt;&lt;span style="color:blue"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;p&gt;注意：上面代码中最关键的一行代码为：&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="background:#ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue"&gt;@ &lt;/span&gt;&lt;span style="color:#a31515"&gt;OutputCache &lt;/span&gt;&lt;span style="color:red"&gt;Duration&lt;/span&gt;&lt;span style="color:blue"&gt;="10" &lt;/span&gt;&lt;span style="color:red"&gt;VaryByParam&lt;/span&gt;&lt;span style="color:blue"&gt;="None" &lt;/span&gt;&lt;span style="background:#ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;正是由于使用了这个OutputCache指令，最后才会输出上面那几个响应头，用来告诉浏览器此页面需要缓存10秒钟。&lt;/p&gt;&lt;p&gt;说到这里，可能有些人想有疑惑了：缓存页在什么时候会起到什么作用呢？&lt;br /&gt;为了演示缓存页所带来的现实意义，我将点击页面的这些链接并以截图的形式来说明：在一系列请求过程中页面的显示情况，并以页面的显示结果来分析缓存所起的作用。&lt;/p&gt;&lt;p&gt;先来看看这个页面的显示截图：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012011123500242.gif" alt="" /&gt;&lt;/p&gt;&lt;p&gt;页面很简单，主要是显示了页面的生成时间与一个刷新链接。从上面提供的页面代码，我们应该能知道这个页面如果是由服务端生成的，则会显示当前的时间。&lt;/p&gt;&lt;p&gt;&lt;b&gt;不过呢，当我一直（频繁）点击【刷新本页】那个链接时，页面的时间并没有发生改变，当我发现时间改变时，页面已显示成这个样子了：&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012011123501975.gif" alt="" /&gt;&lt;/p&gt;&lt;p&gt;由于测试过程中，我一直打开了Fiddler，正好我也把Fiddler监视到的请求结果截图下来了：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012011123503586.gif" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;从Fiddler中，我看到FireFox其实只发生了二次请求，但我点击那个【刷新本页】起码超过10次。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;以上的这一切，只说明一个事实：&lt;b class="redText"&gt;如果页面需要跳转到某个缓存页时，且那个缓存页还没过期，那么浏览器并不会发起到服务器的请求，而是使用缓存页。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;小结：页面缓存所带来的好处是：缓存页面在过期前，用户&lt;b&gt;通过点击跳转链接&lt;/b&gt;所引发的后续访问，并不会再次请求服务器。这对服务器来说可以减少许多访问次数，因此使用这个特性可以很好地改善程序性能。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;缓存页的服务端编程&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;前面演示了使用OutputCache指令所产生的缓存页的效果，由于那些指令需要在页面的设计阶段就写到页面上，因此显得不够灵活，不能在运行时调整，虽然ASP.NET也允许我们使用CacheProfile来引入定义在Web.config中的配置，但配置还是没有运行时的代码灵活。我们再来看看如何用代码来实现上面的效果。&lt;/p&gt;&lt;p&gt;其实用代码实现缓存页也很简单，只需要这样就可以了：&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;protected void &lt;/span&gt;Page_Load(&lt;span style="color:blue"&gt;object &lt;/span&gt;sender, &lt;span style="color:#2b91af"&gt;EventArgs &lt;/span&gt;e)&lt;br/&gt;{&lt;br/&gt;    Response&lt;span style="color:red"&gt;.&lt;/span&gt;Cache&lt;span style="color:red"&gt;.&lt;/span&gt;SetCacheability(&lt;span style="color:#2b91af"&gt;HttpCacheability&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Public);&lt;br/&gt;    Response&lt;span style="color:red"&gt;.&lt;/span&gt;Cache&lt;span style="color:red"&gt;.&lt;/span&gt;SetExpires(&lt;span style="color:#2b91af"&gt;DateTime&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Now&lt;span style="color:red"&gt;.&lt;/span&gt;AddSeconds(&lt;span style="color:purple"&gt;10.0&lt;/span&gt;));&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;其实关键也就是对Response.Cache的调用。&lt;br /&gt;注意：Response.Cache与我上篇&lt;a href="http://www.cnblogs.com/fish-li/archive/2011/12/27/2304063.html" target="_blank"&gt;【细说 ASP.NET Cache 及其高级用法】&lt;/a&gt;博客所讲的Cache不是一回事，二者完全不相干。&lt;br /&gt;Response.Cache提供：用于设置缓存特定的 HTTP 标头的方法和用于控制 ASP.NET 页输出缓存的方法。&lt;/p&gt;&lt;p&gt;我们还是来说前面的二段示例代码。可能有些人会想，它们最终的结果真的会是一致的吗？&lt;/p&gt;&lt;p&gt;要想回答这个问题，我想有必要看一下前面用OutputCache指令的那个页面最终运行的代码是个什么样子的。&lt;/p&gt;&lt;p&gt;在ASP.NET的临时编译目录中，我找到了前面那个文件的一个由ASP.NET处理后的版本：&lt;a href="javascript:void(0);" codeId="pre-demo-precompile"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;private static &lt;/span&gt;System&lt;span style="color:red"&gt;.&lt;/span&gt;Web&lt;span style="color:red"&gt;.&lt;/span&gt;UI&lt;span style="color:red"&gt;.&lt;/span&gt;OutputCacheParameters @__outputCacheSettings &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public &lt;/span&gt;demo1_aspx() {&lt;br/&gt;    &lt;span style="color:green"&gt;// ........ 删除掉一些与Cache无关的代码&lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;if &lt;/span&gt;((&lt;span style="color:blue"&gt;global&lt;/span&gt;&lt;span style="color:red"&gt;::&lt;/span&gt;ASP&lt;span style="color:red"&gt;.&lt;/span&gt;demo1_aspx&lt;span style="color:red"&gt;.&lt;/span&gt;@__outputCacheSettings &lt;span style="color:red"&gt;== &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;)) {&lt;br/&gt;        System&lt;span style="color:red"&gt;.&lt;/span&gt;Web&lt;span style="color:red"&gt;.&lt;/span&gt;UI&lt;span style="color:red"&gt;.&lt;/span&gt;OutputCacheParameters outputCacheSettings;&lt;br/&gt;        outputCacheSettings &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;new &lt;/span&gt;System&lt;span style="color:red"&gt;.&lt;/span&gt;Web&lt;span style="color:red"&gt;.&lt;/span&gt;UI&lt;span style="color:red"&gt;.&lt;/span&gt;OutputCacheParameters();&lt;br/&gt;        outputCacheSettings&lt;span style="color:red"&gt;.&lt;/span&gt;Duration &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;20&lt;/span&gt;;&lt;br/&gt;        outputCacheSettings&lt;span style="color:red"&gt;.&lt;/span&gt;VaryByParam &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:blue"&gt;null&lt;/span&gt;;&lt;br/&gt;        &lt;span style="color:blue"&gt;global&lt;/span&gt;&lt;span style="color:red"&gt;::&lt;/span&gt;ASP&lt;span style="color:red"&gt;.&lt;/span&gt;demo1_aspx&lt;span style="color:red"&gt;.&lt;/span&gt;@__outputCacheSettings &lt;span style="color:red"&gt;= &lt;/span&gt;outputCacheSettings;&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;span style="color:blue"&gt;protected override void &lt;/span&gt;FrameworkInitialize() {&lt;br/&gt;    &lt;span style="color:blue"&gt;base&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;FrameworkInitialize();&lt;br/&gt;    &lt;span style="color:green"&gt;// ........ &lt;br/&gt;    &lt;/span&gt;&lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;InitOutputCache(&lt;span style="color:blue"&gt;global&lt;/span&gt;&lt;span style="color:red"&gt;::&lt;/span&gt;ASP&lt;span style="color:red"&gt;.&lt;/span&gt;demo1_aspx&lt;span style="color:red"&gt;.&lt;/span&gt;@__outputCacheSettings);&lt;br/&gt;    &lt;span style="color:blue"&gt;this&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Request&lt;span style="color:red"&gt;.&lt;/span&gt;ValidateInput();&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;我们可以看到页面针对OutputCache指令的设置，最终会调用Page类定义一个方法中：&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;protected internal virtual void &lt;/span&gt;InitOutputCache(&lt;span style="color:#2b91af"&gt;OutputCacheParameters &lt;/span&gt;cacheSettings)&lt;br/&gt;&lt;br/&gt;&lt;p&gt;那个方法实在太长，最终的处理方式也还是在调用this.Response.Cache，有兴趣的可以自己去看看那个方法。至于这个方法的参数为什么是OutputCacheParameters，我想这个容易理解：方便将OutputCache指令的参数全部一起传入嘛。&lt;/p&gt;&lt;p&gt;所以，也正因为这个缘故，我们也可以直接在代码中调用Response.Cache的一些方法来实现相同的效果，由于代码可以在运行时根据各种参数调整缓存策略，因此会更加灵活，而且可以采用基类的继承方式来简化实现。&lt;/p&gt;&lt;p&gt;&lt;b&gt;注意：如果使用OutputCache指令再配合OutputCache Module的使用，可以实现304的效果。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;什么是304应答？&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;通过前面的示例，我们已经看到缓存带来的好处：那就是可以减少到服务器的访问，由于不访问服务器就能显示页面，这对于服务器来说，能减轻一定的访问压力。&lt;b&gt;但是，如果用户强制刷新浏览器，那么浏览器将会忽略缓存页，直接向服务器重新发起请求。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;也就是说：缓存页在用户强制刷新浏览器时会无效。&lt;br /&gt;但是，我们之所以使用缓存页，是因为我们希望告诉浏览器：这些数据在一定时间内，并不会发生变化，因此根本不需要再次请求服务器了。然而，我们不能阻止用户的行为。由于浏览器的重新访问，我们原来设想的缓存想法将会落空，最后的结果是：页面在服务器中重新执行，产生的HTML代码将重新发送到客户端。而这一重新刷新的结果可能也是无意义的，因为数据可能根本没有发生变化，因此得到的页面也是不可能有变化的。&lt;/p&gt;&lt;p&gt;再来举个简单的例子来说吧：客户端要浏览一张图片。当浏览器第一次要访问图片时，浏览器肯定是没有它的任何缓存记录的，此时它去访问服务器，服务器也返回图片的内容了。但由于图片可能会被多个页面所引用，而它被修改的可能性是很小的。因此没有必要为同一浏览器的多次请求都去读取图片并返回图片的内容，这样做既影响性能也学浪费带宽。于是，像IIS这样服务器软件针对这类静态文件的访问时，都会在响应头上输出一些标记，用来告之浏览器这个文件你可以缓存起来了。&lt;/p&gt;&lt;p&gt;还是回到前面所说的【用户强制刷新】问题，此时的IIS又会如何处理呢？请看下图：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012011123505066.gif" alt="" /&gt;&lt;/p&gt;&lt;p&gt;注意哦，此时除了HTTP状态码变成304之外，&lt;b class="redText"&gt;没有任何数据返回哦。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;为了让您对304应答有个深刻的印象，我截了一张状态码为200的图片响应结果：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012011123510970.gif" alt="" /&gt;&lt;/p&gt;&lt;p&gt;通过这二张图片的对比，现在看清楚了吧：&lt;b class="redText"&gt;304和200并不只是数字上的差别，最重要的差别在于有没有返回结果。&lt;/b&gt;&lt;/p&gt;&lt;p&gt;没有返回结果，浏览器该如何显示？&lt;br /&gt;您会有这样的疑虑吗？&lt;br /&gt;其实不用担心，此时浏览器会使用它缓存版本来显示。也就是说：不管用户如何强制刷，服务器就是不返回结果，但仍然可以正常显示。&lt;/p&gt;&lt;p&gt;显然，这个效果就是我们想要的。&lt;br /&gt;前面所说的缓存页遭用户强刷的问题，如果采用这种方法，就比较完美了。&lt;br /&gt;不过，有一点我要提醒您：Visual Studio自带的那个WebDev.WebServer.exe不支持304应答，所以您就不要拿它试验了，不会有结果的。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;如何编程实现304应答&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;前面我们看到了304应答的效果。不过，在ASP.NET中，我们开发的程序，是动态页面，而不是图片，我们更希望某个页面能以这种方式缓存一段时间，我想这个需求或许会更有意义。&lt;/p&gt;&lt;p&gt;下面，我就来演示如何通过编程的方式实现它。&lt;br /&gt;接下来的示例中，页面的显示还是那个样，显示页面在服务器上产生的时间，时间变化了，说明页面被重新执行了。&lt;/p&gt;&lt;p&gt;重新截一系列的图片，我认为意义也不大，我就截一张图片展现多次强刷而产生的过程&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012011123512588.gif" alt="" /&gt;&lt;/p&gt;&lt;p&gt;上图反映了我多次请求某个ASPX页面的过程，从图片中可以看出，只有第一次是200的响应，后面全是304，是您所期待的结果吧。&lt;/p&gt;&lt;p&gt;再来看看它的实现代码吧：&lt;a href="javascript:void(0);" codeId="pre-demo-304"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;span style="color:blue"&gt;public partial class &lt;/span&gt;&lt;span style="color:#2b91af"&gt;Demo304 &lt;/span&gt;: System&lt;span style="color:red"&gt;.&lt;/span&gt;Web&lt;span style="color:red"&gt;.&lt;/span&gt;UI&lt;span style="color:red"&gt;.&lt;/span&gt;&lt;span style="color:#2b91af"&gt;Page&lt;br/&gt;&lt;/span&gt;{&lt;br/&gt;    &lt;span style="color:blue"&gt;protected void &lt;/span&gt;Page_Load(&lt;span style="color:blue"&gt;object &lt;/span&gt;sender, &lt;span style="color:#2b91af"&gt;EventArgs &lt;/span&gt;e)&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color:#2b91af"&gt;DateTime &lt;/span&gt;dt;&lt;br/&gt;        &lt;span style="color:blue"&gt;if&lt;/span&gt;( &lt;span style="color:#2b91af"&gt;DateTime&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;TryParse(Request&lt;span style="color:red"&gt;.&lt;/span&gt;Headers[&lt;span style="color:#a31515"&gt;"If-Modified-Since"&lt;/span&gt;], &lt;span style="color:blue"&gt;out &lt;/span&gt;dt) ) {&lt;br/&gt;            &lt;span style="color:green"&gt;// 注意：如果是20秒内，我就以304的方式响应。&lt;br/&gt;            &lt;/span&gt;&lt;span style="color:blue"&gt;if&lt;/span&gt;( (&lt;span style="color:#2b91af"&gt;DateTime&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Now &lt;span style="color:red"&gt;- &lt;/span&gt;dt)&lt;span style="color:red"&gt;.&lt;/span&gt;TotalSeconds &lt;span style="color:red"&gt;&amp;lt; &lt;/span&gt;&lt;span style="color:purple"&gt;20.0 &lt;/span&gt;) {&lt;br/&gt;                Response&lt;span style="color:red"&gt;.&lt;/span&gt;StatusCode &lt;span style="color:red"&gt;= &lt;/span&gt;&lt;span style="color:purple"&gt;304&lt;/span&gt;;&lt;br/&gt;                Response&lt;span style="color:red"&gt;.&lt;/span&gt;End();&lt;br/&gt;                &lt;span style="color:blue"&gt;return&lt;/span&gt;;&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        &lt;span style="color:green"&gt;// 注意这个调用，它可以产生"Last-Modified"这个响应头，浏览器在收到这个头以后，&lt;br/&gt;        // 在后续对这个页面访问时，就会将时间以"If-Modified-Since"的形式发到服务器&lt;br/&gt;        // 这样，上面代码的判断就能生效。&lt;br/&gt;        &lt;/span&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Cache&lt;span style="color:red"&gt;.&lt;/span&gt;SetLastModified(&lt;span style="color:#2b91af"&gt;DateTime&lt;/span&gt;&lt;span style="color:red"&gt;.&lt;/span&gt;Now);&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;p&gt;虽然代码并不复杂，但我还是打算来解释一下：&lt;br /&gt;在浏览器第一次请求页面时，会执行SetLastModified的调用，它会在响应时输出一个"Last-Modified"这个响应头，然后，当浏览器再次访问这个页面时，会将上次请求所获取的"Last-Modified"头的&lt;b&gt;内容&lt;/b&gt; ，以"If-Modified-Since"这个请求头的形式发给服务端，此时服务器就可以根据具体逻辑来判断要不要使用304应答了。&lt;/p&gt;&lt;p&gt;在前面的请求图片的示例中，服务器以图片文件的最后修改时间做为"Last-Modified"发给浏览器，浏览器在后续请求那张图片时，又以"If-Modified-Since"的形式告之服务端，此时服务端只要再次检查一下这张图片就知道图片在上次访问后有没有发生修改，如果没有修改，当然就以304的形式告之浏览器：继续使用缓存版本。&lt;/p&gt;&lt;p&gt;还是前面的请求图片的示例，其实服务端还使用了另一对【请求/响应】头：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012011123514267.gif" alt="" /&gt;&lt;/p&gt;&lt;p&gt;这二个头的使用方式是：服务端输出一个ETag头，浏览器在接收后，以If-None-Match的形式在后续请求中发送到服务端，供服务端判断是否使用304应答。&lt;/p&gt;&lt;p&gt;"Last-Modified"与"ETag"这二者，事实上只需要使用一个就够了，关键还是看服务端如何处理它们，浏览器只是在接收后，下次再发出去而已。&lt;/p&gt;&lt;p&gt;不过，前面的示例代码并没有使用缓存头，事实上，也可以带上它，这样可以尽量减少对服务器的访问，毕竟用户不会一直强刷浏览器。这二种方式虽然有较大差别，但它们绝对是可以互补的。&lt;/p&gt;&lt;p&gt;为了能形象的描绘缓存页（或者其它文档）的请求过程，我画了张示意图供大家参考：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/281816/2012011123515661.gif" style="border: dashed 1px #99CCFF" /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;如何避开HTTP缓存&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;前面小节中，介绍了二种方法使用浏览器的缓存。但有些时候可能反而希望浏览器能放弃它缓存的结果。现在的浏览器都有缓存功能，尤其是对一些静态文件，比如：图片，JS，CSS, HTML文件，都能缓存。但有时候我们需要更新CSS, JS文件呢，浏览器如果还使用它的缓存版本，显然就有问题了。而且有些网站使用了URL重写，使原来的动态页面扩展名也变成静态的HTML文件了，因此，仍然希望浏览器在某些时候能够不要缓存这些伪静态页面。&lt;/p&gt;&lt;p&gt;此时，我们就希望浏览器放弃从HTTP请求所获得的结果了。一般说来，浏览器在处理（它认为的）静态文件时，会按照URL为kEY来保存那些缓存结果，因此，通常的解决办法也就是修改URL，比如：原来是请求abc.js的，要改成abc.js?t=23434，后面要跟上一个参数，让以前的缓存不起作用。至于参数t的取值可以根据文件的最后修改时间，也可以手工指定，总之只要改变它就可以了。&lt;/p&gt;&lt;p&gt;但是，对于伪静态的页面，我们不能再使用这种方法了，原因就不用解释了吧。&lt;br /&gt;那么，可以采用在服务端输出一个响应头，通过响应头的方式告之浏览器，不要缓存此文件。比如，可以调用这个方法：&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;Response&lt;span style="color:red"&gt;.&lt;/span&gt;Cache&lt;span style="color:red"&gt;.&lt;/span&gt;SetNoStore();&lt;br/&gt;&lt;br/&gt;&lt;p&gt;它会生成这样的响应头内容：&lt;/p&gt;&lt;br/&gt;&lt;br/&gt;Cache-Control: private, no-store&lt;br/&gt;&lt;br/&gt;&lt;p&gt;许多浏览器都能识别它。还有另一种方法是设置一个已过期的过期时间。&lt;/p&gt;&lt;p&gt;前面所说的在URL中加额外参数的做法，在JS中也比较常用，比如 JQuery就支持让某个Ajax请求不缓存，它的方式就是设置{cache: false}，最终它便会在生成的URL中加上一个临时参数，以保证后面的请求的地址是不重复的，最终达到避开缓存的目的。JQuery的使用太简单，我就不再给出示例代码了。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://files.cnblogs.com/fish-li/HttpCache_20120111.cab.7z"&gt;点击此处下载示例代码&lt;/a&gt;&lt;/p&gt;&lt;div class="articleFooter"&gt;&lt;p&gt;如果，您认为阅读这篇博客让您有些收获，不妨点击一下右下角的&lt;a id="btnRecommendMyBlog" href="javascript:void(0);"&gt;【&lt;b&gt;推荐&lt;/b&gt;】&lt;/a&gt;按钮。&lt;br /&gt;如果，您希望更容易地发现我的新博客，不妨点击一下右下角的&lt;a id="btnFollowFishLi" href="javascript:void(0);"&gt;【&lt;b&gt;关注 Fish Li&lt;/b&gt;】&lt;/a&gt;。&lt;br /&gt;因为，我的写作热情也离不开您的肯定支持。&lt;/p&gt;&lt;p&gt;感谢您的阅读，如果您对我的博客所讲述的内容有兴趣，请继续关注我的后续博客，我是Fish Li 。&lt;span class="icon_smile"&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/fish-li/aggbug/2320027.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/fish-li/archive/2012/01/11/2320027.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
