找回密码
 立即注册
首页 业界区 业界 写自己的ASP.NET MVC框架(下)

写自己的ASP.NET MVC框架(下)

方子楠 2025-5-29 16:06:08
上篇博客【写自己的ASP.NET MVC框架(上)】我给大家介绍我的MVC框架对于Ajax的支持与实现原理。今天的博客将介绍我的MVC框架对UI部分的支持。
注意:由于这篇博客是基于前篇博客的,因此有些已说过的内容将会直接跳过,也不会给出提示。
所以,如果要想理解这篇博客,那么阅读上篇博客【写自己的ASP.NET MVC框架(上)】则是必要的。
MyMVC的特点

在开发MyMVC的过程中,我吸取了一些ASP.NET WebForm的使用经验,也参考了ASP.NET MVC,也接受了Martin Fowler对于MVC思想的总结。在设计过程中,我只实现了一些必要的功能,而且没有引入其它的类库与组件,因此,它非常简单,且容易使用。
我们可以这样理解MyMVC:它是一个简单,容易使用,且符合MVC思想的框架。
在MyMVC框架中,View仍然采用了WebForm中的Page,毕竟Page已经使用了十年,能经得起时间的检验,它仍然是我们可信赖的技术。另一方面,Page也是ASP.NET中默认的HTML输出技术,使用它会比较方便。
MyMVC与微软的ASP.NET MVC不同的是:
1. 不依赖于URL路由组件。
2. 不提供任何HtmlHelper
3. Controller只是一个Action的容器,没有基类的要求。
4. Action处理的请求不区分POST, GET
5. URL可以直接对应一个网站目录中的aspx页面(View)。
6. View的使用是使用路径来指定,与Controller,Action的名字无关。
说明:URL虽然可以与网站中的页面对应,但这种对应并不是必须的,也可以不对应。
而且本质上与WebFrom中的页面执行过程并不相同。
下图反映了在MyMVC中,一个页面请求的执行过程:
1.png

介绍示例项目

为了让大家对MyMVC有兴趣,也为了检验MyMVC的设计,我在开发MyMVC的过程,还专门开发一个基于MyMVC的ASP.NET网站示例项目。网站提供了三种显示风格(也就是三种View),下面以“客户管理”页面为例来展示三种View的不同:
风格1
2.png

View对应的代码如下:
  1. <%@ Page Title="客户管理" Language="C#" MasterPageFile="MasterPage.master"
  2. <httpHandlers>
  3. <httpHandlers>
  4.    
  5. </httpHandlers>
  6. </httpHandlers><httpHandlers>
  7. <httpHandlers>
  8.    
  9. </httpHandlers>
  10. </httpHandlers>Inherits="MyPageView<CustomersPageModel>" %>
  11. <%= HtmlExtension.RefJsFileHtml("/js/MyPage/Customers.js")%>
  12. </asp:Content>
  13. <p>创建客户</p>
  14. <table class="GridView" cellspacing="0" cellpadding="4" border="0" style="border-collapse:collapse;">
  15. <httpHandlers>
  16. <httpHandlers>
  17.    
  18. </httpHandlers>
  19. </httpHandlers><tr align="left">
  20. <httpHandlers>
  21. <httpHandlers>
  22.    
  23. </httpHandlers>
  24. </httpHandlers><httpHandlers>
  25. <httpHandlers>
  26.    
  27. </httpHandlers>
  28. </httpHandlers><th style="width:20px;"> </th>
  29. <httpHandlers>
  30. <httpHandlers>
  31.    
  32. </httpHandlers>
  33. </httpHandlers><httpHandlers>
  34. <httpHandlers>
  35.    
  36. </httpHandlers>
  37. </httpHandlers><th style="width:260px;">客户名称</th>
  38. <httpHandlers>
  39. <httpHandlers>
  40.    
  41. </httpHandlers>
  42. </httpHandlers><httpHandlers>
  43. <httpHandlers>
  44.    
  45. </httpHandlers>
  46. </httpHandlers><th style="width:80px;">联系人</th>
  47. <httpHandlers>
  48. <httpHandlers>
  49.    
  50. </httpHandlers>
  51. </httpHandlers><httpHandlers>
  52. <httpHandlers>
  53.    
  54. </httpHandlers>
  55. </httpHandlers><th>地址</th>
  56. <httpHandlers>
  57. <httpHandlers>
  58.    
  59. </httpHandlers>
  60. </httpHandlers><httpHandlers>
  61. <httpHandlers>
  62.    
  63. </httpHandlers>
  64. </httpHandlers><th style="width:80px;">邮编</th>
  65. <httpHandlers>
  66. <httpHandlers>
  67.    
  68. </httpHandlers>
  69. </httpHandlers><httpHandlers>
  70. <httpHandlers>
  71.    
  72. </httpHandlers>
  73. </httpHandlers><th style="width:160px;">电话</th>
  74. <httpHandlers>
  75. <httpHandlers>
  76.    
  77. </httpHandlers>
  78. </httpHandlers></tr>
  79. <% foreach( Customer customer in Model.List ) { %>
  80. <httpHandlers>
  81. <httpHandlers>
  82.    
  83. </httpHandlers>
  84. </httpHandlers><tr>
  85. <httpHandlers>
  86. <httpHandlers>
  87.    
  88. </httpHandlers>
  89. </httpHandlers><httpHandlers>
  90. <httpHandlers>
  91.    
  92. </httpHandlers>
  93. </httpHandlers><td>&returnUrl=<%= RequestUrlEncodeRawUrl %>"
  94. <httpHandlers>
  95. <httpHandlers>
  96.    
  97. </httpHandlers>
  98. </httpHandlers><httpHandlers>
  99. <httpHandlers>
  100.    
  101. </httpHandlers>
  102. </httpHandlers><httpHandlers>
  103. <httpHandlers>
  104.    
  105. </httpHandlers>
  106. </httpHandlers><httpHandlers>
  107. <httpHandlers>
  108.    
  109. </httpHandlers>
  110. </httpHandlers><httpHandlers>
  111. <httpHandlers>
  112.    
  113. </httpHandlers>
  114. </httpHandlers>title="删除" class="easyui-linkbutton" plain="true">
  115. <httpHandlers>
  116. <httpHandlers>
  117.    
  118. </httpHandlers>
  119. </httpHandlers><httpHandlers>
  120. <httpHandlers>
  121.    
  122. </httpHandlers>
  123. </httpHandlers><httpHandlers>
  124. <httpHandlers>
  125.    
  126. </httpHandlers>
  127. </httpHandlers><img src="https://www.cnblogs.com/Images/delete.gif" alt="删除" /><httpHandlers>
  128. <httpHandlers>
  129.    
  130. </httpHandlers>
  131. </httpHandlers><httpHandlers>
  132. <httpHandlers>
  133.    
  134. </httpHandlers>
  135. </httpHandlers><httpHandlers>
  136. <httpHandlers>
  137.    
  138. </httpHandlers>
  139. </httpHandlers><httpHandlers>
  140. <httpHandlers>
  141.    
  142. </httpHandlers>
  143. </httpHandlers>
  144. <httpHandlers>
  145. <httpHandlers>
  146.    
  147. </httpHandlers>
  148. </httpHandlers><httpHandlers>
  149. <httpHandlers>
  150.    
  151. </httpHandlers>
  152. </httpHandlers></td>
  153. <httpHandlers>
  154. <httpHandlers>
  155.    
  156. </httpHandlers>
  157. </httpHandlers><httpHandlers>
  158. <httpHandlers>
  159.    
  160. </httpHandlers>
  161. </httpHandlers><td>" plain="true" iconCls="icon-open">
  162. <httpHandlers>
  163. <httpHandlers>
  164.    
  165. </httpHandlers>
  166. </httpHandlers><httpHandlers>
  167. <httpHandlers>
  168.    
  169. </httpHandlers>
  170. </httpHandlers><httpHandlers>
  171. <httpHandlers>
  172.    
  173. </httpHandlers>
  174. </httpHandlers><httpHandlers>
  175. <httpHandlers>
  176.    
  177. </httpHandlers>
  178. </httpHandlers><%= customer.CustomerName.HtmlEncode()%>
  179. <httpHandlers>
  180. <httpHandlers>
  181.    
  182. </httpHandlers>
  183. </httpHandlers><httpHandlers>
  184. <httpHandlers>
  185.    
  186. </httpHandlers>
  187. </httpHandlers></td>
  188. <httpHandlers>
  189. <httpHandlers>
  190.    
  191. </httpHandlers>
  192. </httpHandlers><httpHandlers>
  193. <httpHandlers>
  194.    
  195. </httpHandlers>
  196. </httpHandlers><td><span name="ContactName"><%= customer.ContactName.HtmlEncode() %></span>
  197. <httpHandlers>
  198. <httpHandlers>
  199.    
  200. </httpHandlers>
  201. </httpHandlers><httpHandlers>
  202. <httpHandlers>
  203.    
  204. </httpHandlers>
  205. </httpHandlers></td>
  206. <httpHandlers>
  207. <httpHandlers>
  208.    
  209. </httpHandlers>
  210. </httpHandlers><httpHandlers>
  211. <httpHandlers>
  212.    
  213. </httpHandlers>
  214. </httpHandlers><td><span name="Address"><%= customer.Address.HtmlEncode() %></span>
  215. <httpHandlers>
  216. <httpHandlers>
  217.    
  218. </httpHandlers>
  219. </httpHandlers><httpHandlers>
  220. <httpHandlers>
  221.    
  222. </httpHandlers>
  223. </httpHandlers></td>
  224. <httpHandlers>
  225. <httpHandlers>
  226.    
  227. </httpHandlers>
  228. </httpHandlers><httpHandlers>
  229. <httpHandlers>
  230.    
  231. </httpHandlers>
  232. </httpHandlers><td><span name="PostalCode"><%= customer.PostalCode.HtmlEncode() %></span>
  233. <httpHandlers>
  234. <httpHandlers>
  235.    
  236. </httpHandlers>
  237. </httpHandlers><httpHandlers>
  238. <httpHandlers>
  239.    
  240. </httpHandlers>
  241. </httpHandlers></td>
  242. <httpHandlers>
  243. <httpHandlers>
  244.    
  245. </httpHandlers>
  246. </httpHandlers><httpHandlers>
  247. <httpHandlers>
  248.    
  249. </httpHandlers>
  250. </httpHandlers><td><span name="Tel"><%= customer.Tel.HtmlEncode() %></span>
  251. <httpHandlers>
  252. <httpHandlers>
  253.    
  254. </httpHandlers>
  255. </httpHandlers><httpHandlers>
  256. <httpHandlers>
  257.    
  258. </httpHandlers>
  259. </httpHandlers></td>
  260. <httpHandlers>
  261. <httpHandlers>
  262.    
  263. </httpHandlers>
  264. </httpHandlers></tr>
  265. <% } %>
  266. <%= Model.PagingInfo.PaginationBar(6)%>
  267. </table>
  268. <%= UcExecutor.Render("/Controls/Style1/CustomerInfo.ascx", Model.Customer)%>
  269. </asp:Content>
复制代码
风格2
4.png

View对应的代码如下:
  1. <%@ Page Title="客户管理" Language="C#" MasterPageFile="MasterPage.master" %>
  2. <%= HtmlExtension.RefJsFileHtml("/js/MyPage2/Customers.js")%>
  3. </asp:Content>
  4. <table id="grid1"></table>
  5. <%= UcExecutor.Render("/Controls/Style2/CustomerInfo.ascx", null)%>
  6. </asp:Content>
复制代码
风格3
5.png

View对应的代码如下:
  1. <%@ Page Title="客户管理" Language="C#" MasterPageFile="MasterPage.master"
  2. <httpHandlers>
  3. <httpHandlers>
  4.    
  5. </httpHandlers>
  6. </httpHandlers><httpHandlers>
  7. <httpHandlers>
  8.    
  9. </httpHandlers>
  10. </httpHandlers>Inherits="MyPageView<CustomersPageModel>" %>
  11. </asp:Content>
  12. <ul class="itemList">
  13. <% foreach( Customer customer in Model.List ) { %>
  14. <li>
  15. <httpHandlers>
  16. <httpHandlers>
  17.    
  18. </httpHandlers>
  19. </httpHandlers><table class="GridView" cellspacing="0" cellpadding="4" border="0" style="border-collapse:collapse;">
  20. <httpHandlers>
  21. <httpHandlers>
  22.    
  23. </httpHandlers>
  24. </httpHandlers><httpHandlers>
  25. <httpHandlers>
  26.    
  27. </httpHandlers>
  28. </httpHandlers><tr><td><%= customer.CustomerName.HtmlEncode()%></td></tr>
  29. <httpHandlers>
  30. <httpHandlers>
  31.    
  32. </httpHandlers>
  33. </httpHandlers><httpHandlers>
  34. <httpHandlers>
  35.    
  36. </httpHandlers>
  37. </httpHandlers><tr><td><%= customer.ContactName.HtmlEncode() %></td></tr>
  38. <httpHandlers>
  39. <httpHandlers>
  40.    
  41. </httpHandlers>
  42. </httpHandlers><httpHandlers>
  43. <httpHandlers>
  44.    
  45. </httpHandlers>
  46. </httpHandlers><tr><td><%= customer.Address.HtmlEncode() %></td></tr>
  47. <httpHandlers>
  48. <httpHandlers>
  49.    
  50. </httpHandlers>
  51. </httpHandlers><httpHandlers>
  52. <httpHandlers>
  53.    
  54. </httpHandlers>
  55. </httpHandlers><tr><td><%= customer.PostalCode.HtmlEncode() %></td></tr>
  56. <httpHandlers>
  57. <httpHandlers>
  58.    
  59. </httpHandlers>
  60. </httpHandlers><httpHandlers>
  61. <httpHandlers>
  62.    
  63. </httpHandlers>
  64. </httpHandlers><tr><td><%= customer.Tel.HtmlEncode() %></td></tr>
  65. <httpHandlers>
  66. <httpHandlers>
  67.    
  68. </httpHandlers>
  69. </httpHandlers></table>
  70. </li>
  71. <% } %>
  72. </ul>
  73. <%= Model.PagingInfo.PaginationBar()%>
  74. </asp:Content>
复制代码
这是三种截然不同的风格,在服务端的代码也是完全不同的。
其中第二种风格,是采用了我上篇博客中总结的【纯AJAX网站】的风格来开发,因此在服务端页面的开发过程中,最为简单,它需要输出的HTML最少,UI部分由客户端的JS来实现。
对于第一种和第三种风格,它们的HTML结构是不同的,页面所能完成的功能也是不同的,除此之外,它们应该是比较类似的,都是从下面这个泛型类型继承而来:
  1. Inherits="MyPageView<CustomersPageModel>"
复制代码
从泛型类型继承的好处是:我可以在设计页面时,对于涉及Model的访问,都会有智能提示。比如:
6.png

由于有智能提示的支持,可以提高开发效率,并可以避免一些低级的拼写错误。
虽然前面我们可以从图片中看到访问【同一个URL地址】出现【三个不同的页面】,但它们背后的Controller却是同一个:
  1. public class CustomerController
  2. {
  3. <httpHandlers>
  4. <httpHandlers>
  5.    
  6. </httpHandlers>
  7. </httpHandlers>[Action]
  8. <httpHandlers>
  9. <httpHandlers>
  10.    
  11. </httpHandlers>
  12. </httpHandlers>[PageUrl(Url = "/mvc/Customers")]
  13. <httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers>[PageUrl(Url = "/mvc/Customers.html")]
  18. <httpHandlers>
  19. <httpHandlers>
  20.    
  21. </httpHandlers>
  22. </httpHandlers>[PageUrl(Url = "/mvc/CustomerList.aspx")]
  23. <httpHandlers>
  24. <httpHandlers>
  25.    
  26. </httpHandlers>
  27. </httpHandlers>[PageUrl(Url = "/Pages/Customers.aspx")]
  28. <httpHandlers>
  29. <httpHandlers>
  30.    
  31. </httpHandlers>
  32. </httpHandlers>public static object LoadModel(int? page)
  33. <httpHandlers>
  34. <httpHandlers>
  35.    
  36. </httpHandlers>
  37. </httpHandlers>{
  38. <httpHandlers>
  39. <httpHandlers>
  40.    
  41. </httpHandlers>
  42. </httpHandlers><httpHandlers>
  43. <httpHandlers>
  44.    
  45. </httpHandlers>
  46. </httpHandlers>// 说明:参数page表示分页数,方法名LoadModel其实可以【随便取】。
  47. <httpHandlers>
  48. <httpHandlers>
  49.    
  50. </httpHandlers>
  51. </httpHandlers><httpHandlers>
  52. <httpHandlers>
  53.    
  54. </httpHandlers>
  55. </httpHandlers>// 根据用户选择的界面风格,计算实现要呈现的页面路径。
  56. <httpHandlers>
  57. <httpHandlers>
  58.    
  59. </httpHandlers>
  60. </httpHandlers><httpHandlers>
  61. <httpHandlers>
  62.    
  63. </httpHandlers>
  64. </httpHandlers>string papeUrl = StyleHelper.GetTargetPageUrl("Customers.aspx");
  65. <httpHandlers>
  66. <httpHandlers>
  67.    
  68. </httpHandlers>
  69. </httpHandlers><httpHandlers>
  70. <httpHandlers>
  71.    
  72. </httpHandlers>
  73. </httpHandlers>if( StyleHelper.PageStyle == StyleHelper.StyleArray[1] )
  74. <httpHandlers>
  75. <httpHandlers>
  76.    
  77. </httpHandlers>
  78. </httpHandlers><httpHandlers>
  79. <httpHandlers>
  80.    
  81. </httpHandlers>
  82. </httpHandlers><httpHandlers>
  83. <httpHandlers>
  84.    
  85. </httpHandlers>
  86. </httpHandlers>// Style2 风格下,页面不需要绑定数据。数据由JS通过AJAX方式获取
  87. <httpHandlers>
  88. <httpHandlers>
  89.    
  90. </httpHandlers>
  91. </httpHandlers><httpHandlers>
  92. <httpHandlers>
  93.    
  94. </httpHandlers>
  95. </httpHandlers><httpHandlers>
  96. <httpHandlers>
  97.    
  98. </httpHandlers>
  99. </httpHandlers>return new PageResult(papeUrl, null);
  100. <httpHandlers>
  101. <httpHandlers>
  102.    
  103. </httpHandlers>
  104. </httpHandlers><httpHandlers>
  105. <httpHandlers>
  106.    
  107. </httpHandlers>
  108. </httpHandlers>// 为Style1 风格获取数据。
  109. <httpHandlers>
  110. <httpHandlers>
  111.    
  112. </httpHandlers>
  113. </httpHandlers><httpHandlers>
  114. <httpHandlers>
  115.    
  116. </httpHandlers>
  117. </httpHandlers>CustomerSearchInfo info = new CustomerSearchInfo();
  118. <httpHandlers>
  119. <httpHandlers>
  120.    
  121. </httpHandlers>
  122. </httpHandlers><httpHandlers>
  123. <httpHandlers>
  124.    
  125. </httpHandlers>
  126. </httpHandlers>info.SearchWord = string.Empty;
  127. <httpHandlers>
  128. <httpHandlers>
  129.    
  130. </httpHandlers>
  131. </httpHandlers><httpHandlers>
  132. <httpHandlers>
  133.    
  134. </httpHandlers>
  135. </httpHandlers>info.PageIndex = page.HasValue ? page.Value - 1 : 0;
  136. <httpHandlers>
  137. <httpHandlers>
  138.    
  139. </httpHandlers>
  140. </httpHandlers><httpHandlers>
  141. <httpHandlers>
  142.    
  143. </httpHandlers>
  144. </httpHandlers>info.PageSize = AppHelper.DefaultPageSize;
  145. <httpHandlers>
  146. <httpHandlers>
  147.    
  148. </httpHandlers>
  149. </httpHandlers><httpHandlers>
  150. <httpHandlers>
  151.    
  152. </httpHandlers>
  153. </httpHandlers>CustomersPageModel result = new CustomersPageModel();
  154. <httpHandlers>
  155. <httpHandlers>
  156.    
  157. </httpHandlers>
  158. </httpHandlers><httpHandlers>
  159. <httpHandlers>
  160.    
  161. </httpHandlers>
  162. </httpHandlers>result.PagingInfo = info;
  163. <httpHandlers>
  164. <httpHandlers>
  165.    
  166. </httpHandlers>
  167. </httpHandlers><httpHandlers>
  168. <httpHandlers>
  169.    
  170. </httpHandlers>
  171. </httpHandlers>result.List = BllFactory.GetCustomerBLL().GetList(info);
  172. <httpHandlers>
  173. <httpHandlers>
  174.    
  175. </httpHandlers>
  176. </httpHandlers><httpHandlers>
  177. <httpHandlers>
  178.    
  179. </httpHandlers>
  180. </httpHandlers>return new PageResult(papeUrl, result);
  181. <httpHandlers>
  182. <httpHandlers>
  183.    
  184. </httpHandlers>
  185. </httpHandlers>}
  186. }
复制代码
通过上面代码可以看到我用了4个[PageUrl],这意味着其实我可以使用4种不同的URL都能访问到这三个页面,而且每一个URL都会根据当前用户所选择的风格,呈现对应的页面。
事实上,我还可以为这个Action指定更多的[PageUrl],让它可以处理更多的URL。关于[PageUrl]的使用与设计目的,请继续往下阅读。
关于URL路由

随着 .net framewrok 3.5 的问世,微软发布了一个【ASP.NET 路由】组件,它的出现给当时的URL优化方法提供了另外一种选择,不仅如此,它还提供了一些URL重写组件没有的功能:生成URL 。
随着AP.NET MVC的出现,【ASP.NET 路由】成为此框架的直接依赖组件,我们很难有其它的选择,而且,想不用都不行。
有趣的是:【ASP.NET 路由】这个后生小子的出现,并没有很好地遵守ASP.NET制定的一些规则,其中最为明显的是:它跳过了【处理器的映射】阶段,导致ASP.NET MVC在支持Session时,很为难。直到最后ASP.NET 4.0,微软修改了Session的部分实现方式,这样ASP.NET MVC才能最终借此机会解决Session的完整支持问题。
ASP.NET 路由虽然可以生成URL,但它引入了RouteData的概念,要想支持它,需要在框架层面上做许多基础工作。
而且,我认为:
1. 并不是每个网站都需要这种技术,对于不需要URL优化的网站来说,URL路由的使用只是白白地浪费性能。
2. 另一方面,即使需要URL优化,我们还有众多的URL重写组件可供选择,这样可以不用改变现在构架。
因此,MyMVC虽然不支持URL路由,但并不表示不能实现URL优化。
在MVC思想中,Controller应该是处理请求的地方,也是最先运行的部分。然而在传统的WebForm编程模型中,aspx页面负责处理请求。因此,必须采取一种方式让最先处理请求的地方从aspx页面中转移,并能提前执行。
而且,将代码从页面移出还有另外二个好处:
1. 被移出的代码肯定是与UI部分无关的,因此,会比较容易测试。
2. 代码与UI的分享也意味着:可以根据运行条件,有选择地将结果交给不同的View来呈现。
考虑到Action可以选择将结果交给不同的View来呈现,而Session也需要支持的问题,最终我决定,在框架内部使用一个专门的HttpHandler来执行用户的Action,根据Action所要求的Session支持模式,HttpHandlerFactory创建不同的HttpHandler来支持。由于需要使用HttpHandlerFactory,所以必须在web.config中注册。
配置MyMVC框架

MyMVC在使用时,需要在web.config中简单的配置:
  1. <httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>
复制代码
如果使用IIS7,则参考以下配置:
  1. <httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers><httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers><httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers><httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers>
复制代码
我们可以把MvcPageHandlerFactory理解成MyMVC在ASP.NET管线的入口。
注意:
1. 上面的配置代码中,选择aspx这个扩展名并不是必须的,您也可以选择喜欢的扩展名。
2. 如果不喜欢扩展名的映射,可以使用HttpModule,MyMVC中提供的方法也能替代这个过程。

映射处理器(入口)

在web.config中注册MvcPageHandlerFactory后,所有符合条件的请求将会进入MvcPageHandlerFactory。
我们来看一下MvcPageHandlerFactory的实现代码:
  1. internal sealed class AspnetPageHandlerFactory : PageHandlerFactory { }public sealed class MvcPageHandlerFactory : IHttpHandlerFactory{<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>///<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers> /// 尝试根据当前请求,获取一个有效的Action,并返回ActionHandler<httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers>/// 此方法可以在HttpModule中使用,用于替代httpHandler的映射配置<httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers>///<httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers> ///<httpHandlers>
  22. <httpHandlers>
  23.    
  24. </httpHandlers>
  25. </httpHandlers> ///<httpHandlers>
  26. <httpHandlers>
  27.    
  28. </httpHandlers>
  29. </httpHandlers> public static IHttpHandler TryGetHandler(HttpContext context)<httpHandlers>
  30. <httpHandlers>
  31.    
  32. </httpHandlers>
  33. </httpHandlers>{<httpHandlers>
  34. <httpHandlers>
  35.    
  36. </httpHandlers>
  37. </httpHandlers><httpHandlers>
  38. <httpHandlers>
  39.    
  40. </httpHandlers>
  41. </httpHandlers>InvokeInfo vkInfo = ReflectionHelper.GetPageActionInvokeInfo(context.Request.FilePath);<httpHandlers>
  42. <httpHandlers>
  43.    
  44. </httpHandlers>
  45. </httpHandlers><httpHandlers>
  46. <httpHandlers>
  47.    
  48. </httpHandlers>
  49. </httpHandlers>if( vkInfo == null )<httpHandlers>
  50. <httpHandlers>
  51.    
  52. </httpHandlers>
  53. </httpHandlers><httpHandlers>
  54. <httpHandlers>
  55.    
  56. </httpHandlers>
  57. </httpHandlers><httpHandlers>
  58. <httpHandlers>
  59.    
  60. </httpHandlers>
  61. </httpHandlers> return null;<httpHandlers>
  62. <httpHandlers>
  63.    
  64. </httpHandlers>
  65. </httpHandlers><httpHandlers>
  66. <httpHandlers>
  67.    
  68. </httpHandlers>
  69. </httpHandlers>return ActionHandler.CreateHandler(vkInfo);<httpHandlers>
  70. <httpHandlers>
  71.    
  72. </httpHandlers>
  73. </httpHandlers>}<httpHandlers>
  74. <httpHandlers>
  75.    
  76. </httpHandlers>
  77. </httpHandlers>private AspnetPageHandlerFactory _msPageHandlerFactory;<httpHandlers>
  78. <httpHandlers>
  79.    
  80. </httpHandlers>
  81. </httpHandlers>IHttpHandler IHttpHandlerFactory.GetHandler(HttpContext context,<httpHandlers>
  82. <httpHandlers>
  83.    
  84. </httpHandlers>
  85. </httpHandlers><httpHandlers>
  86. <httpHandlers>
  87.    
  88. </httpHandlers>
  89. </httpHandlers><httpHandlers>
  90. <httpHandlers>
  91.    
  92. </httpHandlers>
  93. </httpHandlers><httpHandlers>
  94. <httpHandlers>
  95.    
  96. </httpHandlers>
  97. </httpHandlers><httpHandlers>
  98. <httpHandlers>
  99.    
  100. </httpHandlers>
  101. </httpHandlers><httpHandlers>
  102. <httpHandlers>
  103.    
  104. </httpHandlers>
  105. </httpHandlers> string requestType, string virtualPath, string physicalPath)<httpHandlers>
  106. <httpHandlers>
  107.    
  108. </httpHandlers>
  109. </httpHandlers>{<httpHandlers>
  110. <httpHandlers>
  111.    
  112. </httpHandlers>
  113. </httpHandlers><httpHandlers>
  114. <httpHandlers>
  115.    
  116. </httpHandlers>
  117. </httpHandlers>// 尝试根据请求路径获取Action<httpHandlers>
  118. <httpHandlers>
  119.    
  120. </httpHandlers>
  121. </httpHandlers><httpHandlers>
  122. <httpHandlers>
  123.    
  124. </httpHandlers>
  125. </httpHandlers>InvokeInfo vkInfo = ReflectionHelper.GetPageActionInvokeInfo(virtualPath);<httpHandlers>
  126. <httpHandlers>
  127.    
  128. </httpHandlers>
  129. </httpHandlers><httpHandlers>
  130. <httpHandlers>
  131.    
  132. </httpHandlers>
  133. </httpHandlers><httpHandlers>
  134. <httpHandlers>
  135.    
  136. </httpHandlers>
  137. </httpHandlers><httpHandlers>
  138. <httpHandlers>
  139.    
  140. </httpHandlers>
  141. </httpHandlers>// 如果没有找到合适的Action,并且请求的是一个ASPX页面,则按ASP.NET默认的方式来继续处理<httpHandlers>
  142. <httpHandlers>
  143.    
  144. </httpHandlers>
  145. </httpHandlers><httpHandlers>
  146. <httpHandlers>
  147.    
  148. </httpHandlers>
  149. </httpHandlers>if( vkInfo == null && virtualPath.EndsWith(".aspx", StringComparison.OrdinalIgnoreCase) ) {<httpHandlers>
  150. <httpHandlers>
  151.    
  152. </httpHandlers>
  153. </httpHandlers><httpHandlers>
  154. <httpHandlers>
  155.    
  156. </httpHandlers>
  157. </httpHandlers><httpHandlers>
  158. <httpHandlers>
  159.    
  160. </httpHandlers>
  161. </httpHandlers>if( _msPageHandlerFactory == null )<httpHandlers>
  162. <httpHandlers>
  163.    
  164. </httpHandlers>
  165. </httpHandlers><httpHandlers>
  166. <httpHandlers>
  167.    
  168. </httpHandlers>
  169. </httpHandlers><httpHandlers>
  170. <httpHandlers>
  171.    
  172. </httpHandlers>
  173. </httpHandlers><httpHandlers>
  174. <httpHandlers>
  175.    
  176. </httpHandlers>
  177. </httpHandlers>_msPageHandlerFactory = new AspnetPageHandlerFactory();<httpHandlers>
  178. <httpHandlers>
  179.    
  180. </httpHandlers>
  181. </httpHandlers><httpHandlers>
  182. <httpHandlers>
  183.    
  184. </httpHandlers>
  185. </httpHandlers><httpHandlers>
  186. <httpHandlers>
  187.    
  188. </httpHandlers>
  189. </httpHandlers>// 调用ASP.NET默认的Page处理器工厂来处理<httpHandlers>
  190. <httpHandlers>
  191.    
  192. </httpHandlers>
  193. </httpHandlers><httpHandlers>
  194. <httpHandlers>
  195.    
  196. </httpHandlers>
  197. </httpHandlers><httpHandlers>
  198. <httpHandlers>
  199.    
  200. </httpHandlers>
  201. </httpHandlers>return _msPageHandlerFactory.GetHandler(context, requestType, virtualPath, physicalPath);<httpHandlers>
  202. <httpHandlers>
  203.    
  204. </httpHandlers>
  205. </httpHandlers><httpHandlers>
  206. <httpHandlers>
  207.    
  208. </httpHandlers>
  209. </httpHandlers>}<httpHandlers>
  210. <httpHandlers>
  211.    
  212. </httpHandlers>
  213. </httpHandlers><httpHandlers>
  214. <httpHandlers>
  215.    
  216. </httpHandlers>
  217. </httpHandlers>return ActionHandler.CreateHandler(vkInfo);<httpHandlers>
  218. <httpHandlers>
  219.    
  220. </httpHandlers>
  221. </httpHandlers>}<httpHandlers>
  222. <httpHandlers>
  223.    
  224. </httpHandlers>
  225. </httpHandlers>void IHttpHandlerFactory.ReleaseHandler(IHttpHandler handler)<httpHandlers>
  226. <httpHandlers>
  227.    
  228. </httpHandlers>
  229. </httpHandlers>{<httpHandlers>
  230. <httpHandlers>
  231.    
  232. </httpHandlers>
  233. </httpHandlers><httpHandlers>
  234. <httpHandlers>
  235.    
  236. </httpHandlers>
  237. </httpHandlers><httpHandlers>
  238. <httpHandlers>
  239.    
  240. </httpHandlers>
  241. </httpHandlers><httpHandlers>
  242. <httpHandlers>
  243.    
  244. </httpHandlers>
  245. </httpHandlers>}}
复制代码
从代码中可以看到,MyMVC首先会根据当前的请求地址查找有没有一个Action可以处理它,如果没有,则采用ASP.NET默认的方式来处理。因此,把【*.aspx】交给MvcPageHandlerFactory是不会有问题的。
说明:创建一个空壳类型AspnetPageHandlerFactory的原因是:不能直接调用PageHandlerFactory的构造函数。
内部初始化

MyMVC在第一次处理请求时,要做一个初始化的过程,这个过程是由MvcPageHandlerFactory中的一个调用引发的:
  1. // 尝试根据请求路径获取Action
  2. InvokeInfo vkInfo = ReflectionHelper.GetPageActionInvokeInfo(virtualPath);
复制代码
ReflectionHelper有个静态构造函数,虽然上次我已贴出它的代码,但那只是部分代码,以下才是完整的初始化代码:
  1. internal static class ReflectionHelper{<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>// 保存PageAction的字典<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers>private static Dictionary s_PageActionDict;<httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers>// 保存AjaxController的列表<httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers>private static List s_AjaxControllerList;<httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers>// 保存AjaxAction的字典<httpHandlers>
  22. <httpHandlers>
  23.    
  24. </httpHandlers>
  25. </httpHandlers>private static Hashtable s_AjaxActionTable = Hashtable.Synchronized(<httpHandlers>
  26. <httpHandlers>
  27.    
  28. </httpHandlers>
  29. </httpHandlers><httpHandlers>
  30. <httpHandlers>
  31.    
  32. </httpHandlers>
  33. </httpHandlers><httpHandlers>
  34. <httpHandlers>
  35.    
  36. </httpHandlers>
  37. </httpHandlers><httpHandlers>
  38. <httpHandlers>
  39.    
  40. </httpHandlers>
  41. </httpHandlers><httpHandlers>
  42. <httpHandlers>
  43.    
  44. </httpHandlers>
  45. </httpHandlers><httpHandlers>
  46. <httpHandlers>
  47.    
  48. </httpHandlers>
  49. </httpHandlers><httpHandlers>
  50. <httpHandlers>
  51.    
  52. </httpHandlers>
  53. </httpHandlers><httpHandlers>
  54. <httpHandlers>
  55.    
  56. </httpHandlers>
  57. </httpHandlers><httpHandlers>
  58. <httpHandlers>
  59.    
  60. </httpHandlers>
  61. </httpHandlers><httpHandlers>
  62. <httpHandlers>
  63.    
  64. </httpHandlers>
  65. </httpHandlers>new Hashtable(4096, StringComparer.OrdinalIgnoreCase));<httpHandlers>
  66. <httpHandlers>
  67.    
  68. </httpHandlers>
  69. </httpHandlers>// 用于从类型查找Action的反射标记<httpHandlers>
  70. <httpHandlers>
  71.    
  72. </httpHandlers>
  73. </httpHandlers>private static readonly BindingFlags ActionBindingFlags =<httpHandlers>
  74. <httpHandlers>
  75.    
  76. </httpHandlers>
  77. </httpHandlers><httpHandlers>
  78. <httpHandlers>
  79.    
  80. </httpHandlers>
  81. </httpHandlers>BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase;<httpHandlers>
  82. <httpHandlers>
  83.    
  84. </httpHandlers>
  85. </httpHandlers>static ReflectionHelper()<httpHandlers>
  86. <httpHandlers>
  87.    
  88. </httpHandlers>
  89. </httpHandlers>{<httpHandlers>
  90. <httpHandlers>
  91.    
  92. </httpHandlers>
  93. </httpHandlers><httpHandlers>
  94. <httpHandlers>
  95.    
  96. </httpHandlers>
  97. </httpHandlers>InitControllers();<httpHandlers>
  98. <httpHandlers>
  99.    
  100. </httpHandlers>
  101. </httpHandlers>}<httpHandlers>
  102. <httpHandlers>
  103.    
  104. </httpHandlers>
  105. </httpHandlers>///<httpHandlers>
  106. <httpHandlers>
  107.    
  108. </httpHandlers>
  109. </httpHandlers> /// 加载所有的Controller<httpHandlers>
  110. <httpHandlers>
  111.    
  112. </httpHandlers>
  113. </httpHandlers>///<httpHandlers>
  114. <httpHandlers>
  115.    
  116. </httpHandlers>
  117. </httpHandlers> private static void InitControllers()<httpHandlers>
  118. <httpHandlers>
  119.    
  120. </httpHandlers>
  121. </httpHandlers>{<httpHandlers>
  122. <httpHandlers>
  123.    
  124. </httpHandlers>
  125. </httpHandlers><httpHandlers>
  126. <httpHandlers>
  127.    
  128. </httpHandlers>
  129. </httpHandlers>s_AjaxControllerList = new List(1024);<httpHandlers>
  130. <httpHandlers>
  131.    
  132. </httpHandlers>
  133. </httpHandlers><httpHandlers>
  134. <httpHandlers>
  135.    
  136. </httpHandlers>
  137. </httpHandlers>var pageControllerList = new List(1024);<httpHandlers>
  138. <httpHandlers>
  139.    
  140. </httpHandlers>
  141. </httpHandlers><httpHandlers>
  142. <httpHandlers>
  143.    
  144. </httpHandlers>
  145. </httpHandlers>ICollection assemblies = BuildManager.GetReferencedAssemblies();<httpHandlers>
  146. <httpHandlers>
  147.    
  148. </httpHandlers>
  149. </httpHandlers><httpHandlers>
  150. <httpHandlers>
  151.    
  152. </httpHandlers>
  153. </httpHandlers>foreach( Assembly assembly in assemblies ) {<httpHandlers>
  154. <httpHandlers>
  155.    
  156. </httpHandlers>
  157. </httpHandlers><httpHandlers>
  158. <httpHandlers>
  159.    
  160. </httpHandlers>
  161. </httpHandlers><httpHandlers>
  162. <httpHandlers>
  163.    
  164. </httpHandlers>
  165. </httpHandlers>// 过滤以【System.】开头的程序集,加快速度<httpHandlers>
  166. <httpHandlers>
  167.    
  168. </httpHandlers>
  169. </httpHandlers><httpHandlers>
  170. <httpHandlers>
  171.    
  172. </httpHandlers>
  173. </httpHandlers><httpHandlers>
  174. <httpHandlers>
  175.    
  176. </httpHandlers>
  177. </httpHandlers>if( assembly.FullName.StartsWith("System.", StringComparison.OrdinalIgnoreCase) )<httpHandlers>
  178. <httpHandlers>
  179.    
  180. </httpHandlers>
  181. </httpHandlers><httpHandlers>
  182. <httpHandlers>
  183.    
  184. </httpHandlers>
  185. </httpHandlers><httpHandlers>
  186. <httpHandlers>
  187.    
  188. </httpHandlers>
  189. </httpHandlers><httpHandlers>
  190. <httpHandlers>
  191.    
  192. </httpHandlers>
  193. </httpHandlers>continue;<httpHandlers>
  194. <httpHandlers>
  195.    
  196. </httpHandlers>
  197. </httpHandlers><httpHandlers>
  198. <httpHandlers>
  199.    
  200. </httpHandlers>
  201. </httpHandlers><httpHandlers>
  202. <httpHandlers>
  203.    
  204. </httpHandlers>
  205. </httpHandlers>try {<httpHandlers>
  206. <httpHandlers>
  207.    
  208. </httpHandlers>
  209. </httpHandlers><httpHandlers>
  210. <httpHandlers>
  211.    
  212. </httpHandlers>
  213. </httpHandlers><httpHandlers>
  214. <httpHandlers>
  215.    
  216. </httpHandlers>
  217. </httpHandlers><httpHandlers>
  218. <httpHandlers>
  219.    
  220. </httpHandlers>
  221. </httpHandlers>foreach( Type t in assembly.GetExportedTypes() ) {<httpHandlers>
  222. <httpHandlers>
  223.    
  224. </httpHandlers>
  225. </httpHandlers><httpHandlers>
  226. <httpHandlers>
  227.    
  228. </httpHandlers>
  229. </httpHandlers><httpHandlers>
  230. <httpHandlers>
  231.    
  232. </httpHandlers>
  233. </httpHandlers><httpHandlers>
  234. <httpHandlers>
  235.    
  236. </httpHandlers>
  237. </httpHandlers><httpHandlers>
  238. <httpHandlers>
  239.    
  240. </httpHandlers>
  241. </httpHandlers>if( t.Name.StartsWith("Ajax") )<httpHandlers>
  242. <httpHandlers>
  243.    
  244. </httpHandlers>
  245. </httpHandlers><httpHandlers>
  246. <httpHandlers>
  247.    
  248. </httpHandlers>
  249. </httpHandlers><httpHandlers>
  250. <httpHandlers>
  251.    
  252. </httpHandlers>
  253. </httpHandlers><httpHandlers>
  254. <httpHandlers>
  255.    
  256. </httpHandlers>
  257. </httpHandlers><httpHandlers>
  258. <httpHandlers>
  259.    
  260. </httpHandlers>
  261. </httpHandlers><httpHandlers>
  262. <httpHandlers>
  263.    
  264. </httpHandlers>
  265. </httpHandlers>s_AjaxControllerList.Add(new ControllerDescription(t));<httpHandlers>
  266. <httpHandlers>
  267.    
  268. </httpHandlers>
  269. </httpHandlers><httpHandlers>
  270. <httpHandlers>
  271.    
  272. </httpHandlers>
  273. </httpHandlers><httpHandlers>
  274. <httpHandlers>
  275.    
  276. </httpHandlers>
  277. </httpHandlers><httpHandlers>
  278. <httpHandlers>
  279.    
  280. </httpHandlers>
  281. </httpHandlers><httpHandlers>
  282. <httpHandlers>
  283.    
  284. </httpHandlers>
  285. </httpHandlers>else if( t.Name.EndsWith("Controller") )<httpHandlers>
  286. <httpHandlers>
  287.    
  288. </httpHandlers>
  289. </httpHandlers><httpHandlers>
  290. <httpHandlers>
  291.    
  292. </httpHandlers>
  293. </httpHandlers><httpHandlers>
  294. <httpHandlers>
  295.    
  296. </httpHandlers>
  297. </httpHandlers><httpHandlers>
  298. <httpHandlers>
  299.    
  300. </httpHandlers>
  301. </httpHandlers><httpHandlers>
  302. <httpHandlers>
  303.    
  304. </httpHandlers>
  305. </httpHandlers><httpHandlers>
  306. <httpHandlers>
  307.    
  308. </httpHandlers>
  309. </httpHandlers>pageControllerList.Add(new ControllerDescription(t));<httpHandlers>
  310. <httpHandlers>
  311.    
  312. </httpHandlers>
  313. </httpHandlers><httpHandlers>
  314. <httpHandlers>
  315.    
  316. </httpHandlers>
  317. </httpHandlers><httpHandlers>
  318. <httpHandlers>
  319.    
  320. </httpHandlers>
  321. </httpHandlers><httpHandlers>
  322. <httpHandlers>
  323.    
  324. </httpHandlers>
  325. </httpHandlers>}<httpHandlers>
  326. <httpHandlers>
  327.    
  328. </httpHandlers>
  329. </httpHandlers><httpHandlers>
  330. <httpHandlers>
  331.    
  332. </httpHandlers>
  333. </httpHandlers><httpHandlers>
  334. <httpHandlers>
  335.    
  336. </httpHandlers>
  337. </httpHandlers>}<httpHandlers>
  338. <httpHandlers>
  339.    
  340. </httpHandlers>
  341. </httpHandlers><httpHandlers>
  342. <httpHandlers>
  343.    
  344. </httpHandlers>
  345. </httpHandlers><httpHandlers>
  346. <httpHandlers>
  347.    
  348. </httpHandlers>
  349. </httpHandlers>catch { }<httpHandlers>
  350. <httpHandlers>
  351.    
  352. </httpHandlers>
  353. </httpHandlers><httpHandlers>
  354. <httpHandlers>
  355.    
  356. </httpHandlers>
  357. </httpHandlers>}<httpHandlers>
  358. <httpHandlers>
  359.    
  360. </httpHandlers>
  361. </httpHandlers><httpHandlers>
  362. <httpHandlers>
  363.    
  364. </httpHandlers>
  365. </httpHandlers><httpHandlers>
  366. <httpHandlers>
  367.    
  368. </httpHandlers>
  369. </httpHandlers><httpHandlers>
  370. <httpHandlers>
  371.    
  372. </httpHandlers>
  373. </httpHandlers><httpHandlers>
  374. <httpHandlers>
  375.    
  376. </httpHandlers>
  377. </httpHandlers><httpHandlers>
  378. <httpHandlers>
  379.    
  380. </httpHandlers>
  381. </httpHandlers><httpHandlers>
  382. <httpHandlers>
  383.    
  384. </httpHandlers>
  385. </httpHandlers>// 提前加载Page Controller中的所有Action方法<httpHandlers>
  386. <httpHandlers>
  387.    
  388. </httpHandlers>
  389. </httpHandlers><httpHandlers>
  390. <httpHandlers>
  391.    
  392. </httpHandlers>
  393. </httpHandlers>s_PageActionDict = new Dictionary(4096, StringComparer.OrdinalIgnoreCase);<httpHandlers>
  394. <httpHandlers>
  395.    
  396. </httpHandlers>
  397. </httpHandlers><httpHandlers>
  398. <httpHandlers>
  399.    
  400. </httpHandlers>
  401. </httpHandlers>foreach( ControllerDescription controller in pageControllerList ) {<httpHandlers>
  402. <httpHandlers>
  403.    
  404. </httpHandlers>
  405. </httpHandlers><httpHandlers>
  406. <httpHandlers>
  407.    
  408. </httpHandlers>
  409. </httpHandlers><httpHandlers>
  410. <httpHandlers>
  411.    
  412. </httpHandlers>
  413. </httpHandlers>foreach( MethodInfo m in controller.ControllerType.GetMethods(ActionBindingFlags) ) {<httpHandlers>
  414. <httpHandlers>
  415.    
  416. </httpHandlers>
  417. </httpHandlers><httpHandlers>
  418. <httpHandlers>
  419.    
  420. </httpHandlers>
  421. </httpHandlers><httpHandlers>
  422. <httpHandlers>
  423.    
  424. </httpHandlers>
  425. </httpHandlers><httpHandlers>
  426. <httpHandlers>
  427.    
  428. </httpHandlers>
  429. </httpHandlers>PageUrlAttribute[] pageUrlAttrs = m.GetMyAttributes();<httpHandlers>
  430. <httpHandlers>
  431.    
  432. </httpHandlers>
  433. </httpHandlers><httpHandlers>
  434. <httpHandlers>
  435.    
  436. </httpHandlers>
  437. </httpHandlers><httpHandlers>
  438. <httpHandlers>
  439.    
  440. </httpHandlers>
  441. </httpHandlers><httpHandlers>
  442. <httpHandlers>
  443.    
  444. </httpHandlers>
  445. </httpHandlers>ActionAttribute actionAttr = m.GetMyAttribute();<httpHandlers>
  446. <httpHandlers>
  447.    
  448. </httpHandlers>
  449. </httpHandlers><httpHandlers>
  450. <httpHandlers>
  451.    
  452. </httpHandlers>
  453. </httpHandlers><httpHandlers>
  454. <httpHandlers>
  455.    
  456. </httpHandlers>
  457. </httpHandlers><httpHandlers>
  458. <httpHandlers>
  459.    
  460. </httpHandlers>
  461. </httpHandlers>if( pageUrlAttrs.Length > 0 && actionAttr != null ) {<httpHandlers>
  462. <httpHandlers>
  463.    
  464. </httpHandlers>
  465. </httpHandlers><httpHandlers>
  466. <httpHandlers>
  467.    
  468. </httpHandlers>
  469. </httpHandlers><httpHandlers>
  470. <httpHandlers>
  471.    
  472. </httpHandlers>
  473. </httpHandlers><httpHandlers>
  474. <httpHandlers>
  475.    
  476. </httpHandlers>
  477. </httpHandlers><httpHandlers>
  478. <httpHandlers>
  479.    
  480. </httpHandlers>
  481. </httpHandlers>ActionDescription actionDescription =<httpHandlers>
  482. <httpHandlers>
  483.    
  484. </httpHandlers>
  485. </httpHandlers><httpHandlers>
  486. <httpHandlers>
  487.    
  488. </httpHandlers>
  489. </httpHandlers><httpHandlers>
  490. <httpHandlers>
  491.    
  492. </httpHandlers>
  493. </httpHandlers><httpHandlers>
  494. <httpHandlers>
  495.    
  496. </httpHandlers>
  497. </httpHandlers><httpHandlers>
  498. <httpHandlers>
  499.    
  500. </httpHandlers>
  501. </httpHandlers><httpHandlers>
  502. <httpHandlers>
  503.    
  504. </httpHandlers>
  505. </httpHandlers>new ActionDescription(m, actionAttr) { PageController = controller };<httpHandlers>
  506. <httpHandlers>
  507.    
  508. </httpHandlers>
  509. </httpHandlers><httpHandlers>
  510. <httpHandlers>
  511.    
  512. </httpHandlers>
  513. </httpHandlers><httpHandlers>
  514. <httpHandlers>
  515.    
  516. </httpHandlers>
  517. </httpHandlers><httpHandlers>
  518. <httpHandlers>
  519.    
  520. </httpHandlers>
  521. </httpHandlers><httpHandlers>
  522. <httpHandlers>
  523.    
  524. </httpHandlers>
  525. </httpHandlers>foreach( PageUrlAttribute attr in pageUrlAttrs ) {<httpHandlers>
  526. <httpHandlers>
  527.    
  528. </httpHandlers>
  529. </httpHandlers><httpHandlers>
  530. <httpHandlers>
  531.    
  532. </httpHandlers>
  533. </httpHandlers><httpHandlers>
  534. <httpHandlers>
  535.    
  536. </httpHandlers>
  537. </httpHandlers><httpHandlers>
  538. <httpHandlers>
  539.    
  540. </httpHandlers>
  541. </httpHandlers><httpHandlers>
  542. <httpHandlers>
  543.    
  544. </httpHandlers>
  545. </httpHandlers><httpHandlers>
  546. <httpHandlers>
  547.    
  548. </httpHandlers>
  549. </httpHandlers>if( string.IsNullOrEmpty(attr.Url) == false )<httpHandlers>
  550. <httpHandlers>
  551.    
  552. </httpHandlers>
  553. </httpHandlers><httpHandlers>
  554. <httpHandlers>
  555.    
  556. </httpHandlers>
  557. </httpHandlers><httpHandlers>
  558. <httpHandlers>
  559.    
  560. </httpHandlers>
  561. </httpHandlers><httpHandlers>
  562. <httpHandlers>
  563.    
  564. </httpHandlers>
  565. </httpHandlers><httpHandlers>
  566. <httpHandlers>
  567.    
  568. </httpHandlers>
  569. </httpHandlers><httpHandlers>
  570. <httpHandlers>
  571.    
  572. </httpHandlers>
  573. </httpHandlers><httpHandlers>
  574. <httpHandlers>
  575.    
  576. </httpHandlers>
  577. </httpHandlers>s_PageActionDict.Add(attr.Url, actionDescription);<httpHandlers>
  578. <httpHandlers>
  579.    
  580. </httpHandlers>
  581. </httpHandlers><httpHandlers>
  582. <httpHandlers>
  583.    
  584. </httpHandlers>
  585. </httpHandlers><httpHandlers>
  586. <httpHandlers>
  587.    
  588. </httpHandlers>
  589. </httpHandlers><httpHandlers>
  590. <httpHandlers>
  591.    
  592. </httpHandlers>
  593. </httpHandlers><httpHandlers>
  594. <httpHandlers>
  595.    
  596. </httpHandlers>
  597. </httpHandlers>}<httpHandlers>
  598. <httpHandlers>
  599.    
  600. </httpHandlers>
  601. </httpHandlers><httpHandlers>
  602. <httpHandlers>
  603.    
  604. </httpHandlers>
  605. </httpHandlers><httpHandlers>
  606. <httpHandlers>
  607.    
  608. </httpHandlers>
  609. </httpHandlers><httpHandlers>
  610. <httpHandlers>
  611.    
  612. </httpHandlers>
  613. </httpHandlers>}<httpHandlers>
  614. <httpHandlers>
  615.    
  616. </httpHandlers>
  617. </httpHandlers><httpHandlers>
  618. <httpHandlers>
  619.    
  620. </httpHandlers>
  621. </httpHandlers><httpHandlers>
  622. <httpHandlers>
  623.    
  624. </httpHandlers>
  625. </httpHandlers>}<httpHandlers>
  626. <httpHandlers>
  627.    
  628. </httpHandlers>
  629. </httpHandlers><httpHandlers>
  630. <httpHandlers>
  631.    
  632. </httpHandlers>
  633. </httpHandlers>}<httpHandlers>
  634. <httpHandlers>
  635.    
  636. </httpHandlers>
  637. </httpHandlers><httpHandlers>
  638. <httpHandlers>
  639.    
  640. </httpHandlers>
  641. </httpHandlers>// 用于Ajax调用的Action信息则采用延迟加载的方式。<httpHandlers>
  642. <httpHandlers>
  643.    
  644. </httpHandlers>
  645. </httpHandlers>}
复制代码
从以上代码可以看出,在初始化时,MyMVC加载了全部的PageAction ,而AjaxAction却没有采用这种方式来实现,为什么呢?请继续阅读。
从URL到Action的映射过程

前面我们看到了MyMVC的初始化过程,其实是在ReflectionHelper的构造函数中完成的。在这个初始化之后,MvcPageHandlerFactory调用ReflectionHelper.GetPageActionInvokeInfo(virtualPath)便可以得到要调用的Action的具体描述。我称这个过程为:从URL到Action的映射
GetPageActionInvokeInfo方法的实现代码如下:
  1. /// /// 根据一个页面请求路径,返回内部表示的调用信息。/// /// /// public static InvokeInfo GetPageActionInvokeInfo(string url){<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>if( string.IsNullOrEmpty(url) )<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers><httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers>throw new ArgumentNullException("url");<httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers>ActionDescription action = null;<httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers>if( s_PageActionDict.TryGetValue(url, out action) == false )<httpHandlers>
  22. <httpHandlers>
  23.    
  24. </httpHandlers>
  25. </httpHandlers><httpHandlers>
  26. <httpHandlers>
  27.    
  28. </httpHandlers>
  29. </httpHandlers>return null;<httpHandlers>
  30. <httpHandlers>
  31.    
  32. </httpHandlers>
  33. </httpHandlers>InvokeInfo vkInfo = new InvokeInfo();<httpHandlers>
  34. <httpHandlers>
  35.    
  36. </httpHandlers>
  37. </httpHandlers>vkInfo.Controller = action.PageController;<httpHandlers>
  38. <httpHandlers>
  39.    
  40. </httpHandlers>
  41. </httpHandlers>vkInfo.Action = action;<httpHandlers>
  42. <httpHandlers>
  43.    
  44. </httpHandlers>
  45. </httpHandlers>if( vkInfo.Action.MethodInfo.IsStatic == false )<httpHandlers>
  46. <httpHandlers>
  47.    
  48. </httpHandlers>
  49. </httpHandlers><httpHandlers>
  50. <httpHandlers>
  51.    
  52. </httpHandlers>
  53. </httpHandlers>vkInfo.Instance = Activator.CreateInstance(vkInfo.Controller.ControllerType);<httpHandlers>
  54. <httpHandlers>
  55.    
  56. </httpHandlers>
  57. </httpHandlers>return vkInfo;}
复制代码
在介绍这个映射过程之前,让我们再来回顾一下Action的声明代码:
  1. public class CustomerController{<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>[Action]<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers>[PageUrl(Url = "/mvc/Customers")]<httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers>[PageUrl(Url = "/mvc/Customers.html")]<httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers>[PageUrl(Url = "/mvc/CustomerList.aspx")]<httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers>[PageUrl(Url = "/Pages/Customers.aspx")]<httpHandlers>
  22. <httpHandlers>
  23.    
  24. </httpHandlers>
  25. </httpHandlers>public static object LoadModel(int? page)<httpHandlers>
  26. <httpHandlers>
  27.    
  28. </httpHandlers>
  29. </httpHandlers>{
复制代码
通过ReflectionHelper构造函数中所完成的初始化过程,每个Action的描述会根据[PageUrl]的数量而生成多个字典条目,因此,在GetPageActionInvokeInfo的实现过程中,也只是简单的查找了这个字典而已,就可以得到所需要的调用信息,从面完成映射的过程。整个过程可以用以下图形来表示:
7.png

在上面的示例中,我使用了"/mvc/Customers"这种URL,显然它并不符合我在web.config中为MvcPageHandlerFactory注册时所指定的URL模式要求。那么,又该如何处理呢?
虽然这种URL虽然没有扩展名,但我仍然可以通过配置httpHandler的方式来解决,下面的配置就是我们需要的:
  1. <httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>
复制代码
在介绍MvcPageHandlerFactory时,MyMVC提供了另一个方法TryGetHandler供外部使用。因此,在示例网站中,我还可以在Global.asax中调用这个方法来解决前面的那个问题:
  1. protected void Application_PostResolveRequestCache(object sender, EventArgs e){<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>// 这里只是一个演示。<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers>// 主要是将诸如:/mvc/Customers 这类请求映射到MyMVC框架的处理器<httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers>HttpApplication app = (HttpApplication)sender;<httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers>if( app.Request.FilePath.StartsWith("/mvc/") ) {<httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers><httpHandlers>
  22. <httpHandlers>
  23.    
  24. </httpHandlers>
  25. </httpHandlers>IHttpHandler myHandler = MyMVC.MvcPageHandlerFactory.TryGetHandler(app.Context);<httpHandlers>
  26. <httpHandlers>
  27.    
  28. </httpHandlers>
  29. </httpHandlers><httpHandlers>
  30. <httpHandlers>
  31.    
  32. </httpHandlers>
  33. </httpHandlers>if( myHandler != null )<httpHandlers>
  34. <httpHandlers>
  35.    
  36. </httpHandlers>
  37. </httpHandlers><httpHandlers>
  38. <httpHandlers>
  39.    
  40. </httpHandlers>
  41. </httpHandlers><httpHandlers>
  42. <httpHandlers>
  43.    
  44. </httpHandlers>
  45. </httpHandlers>app.Context.RemapHandler(myHandler);<httpHandlers>
  46. <httpHandlers>
  47.    
  48. </httpHandlers>
  49. </httpHandlers>}}
复制代码
对于切换HttpHandler的操作,我有以下建议:
1. 尽量放在HttpModule中去实现。因为可以通过修改配置来切换规则(启用或者禁止),所以会比较灵活。
2. 如果可以通过HttpHandler映射能实现的,尽量首选HttpHandler映射方式。原因:更快,更标准。
PageUrl的设计思想

在前面的示例代码中,我为一个Action添加多个[PageUrl],来标记这个Action可以处理多个URL,因此,一个Action能处理哪些URL是通过指定[PageUrl]来实现的。
为什么要叫【PageUrl】?
我想或许有些人会有这个疑问。
下面我就来回答这个问题,也可以让大家了解我设计PageUrl的原因:
1. 我们请求一个URL通常是为了得到一个页面显示,因此可以认为一个URL最终可以表示成一个页面。
2. 我也想过使用[Url]这种名称,但感觉太短了,而且Ajax请求也有URL,那么必须显式地加以区分。
所以,我最终决定使用[PageUrl]这个名字。
在Ajax部分,我认为通常只需要完成获取数据以及处理提交数据的功能就可以了。因此,绝大多数情况下是不要需View的,而且,一个功能与一个URL对应,这样还可以简化问题。所以,在Ajax部分,我提倡在URL中直接指出要调用哪个Controller中的哪个Action。
在Page部分,事实上也需要一个Action,本来也是可以继续使用这种做法的,不过,我并没有这种做,理由如下:
1. 我们创建View其实也是创建Page,使用Page的路径不是更好吗?而且WebForm的粉丝或许会更喜欢。
2. 多URL的匹配功能。后面会有详细说明。
由于以上种种原因,我将[PageUrl]设计成与[Action]是独立关系,并且[PageUrl]可以多次指定的。
注意:
1. Url参数中指定的字符串,可以对应一个aspx页面。也可以不对应aspx页面。
2. Url参数中,不要包含QueryString,否则根本不能匹配。
3. 如果您使用URL重写组件,那么此处应该是重写后的路径。
由于我在MvcPageHandlerFactory中使用ASP.NET框架传入的virtualPath并不包含查询参数,因此,把它理解成页面路径也是非常合适的。
多URL的匹配功能

或许有些人认为多URL匹配一个Action是没有意义的,比如下面的这个Action会更符合常理:
  1. public class CategoryController{<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>[Action]<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers>[PageUrl(Url = "/Pages/Categories.aspx")]<httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers>public object LoadModel()<httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers>{
复制代码
是的,通常情况下,一个Action处理一个URL也是较为常见。
但仍然有二种情况需要这个功能。首先来看下面的示例:
  1. [Action][PageUrl(Url = "/Pages/AddOrder.aspx")][PageUrl(Url = "/Pages/CodeExplorer.aspx")][PageUrl(Url = "/Pages/Default.aspx")][PageUrl(Url = "/Pages/Orders.aspx")]public object TransferRequest(){<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>// 这个Action要做的事较为简单,<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers>// 将请求 "/Pages/Orders.aspx" 用实际的页面 "/Pages/StyleX/Orders.aspx" 来响应。<httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers>// 因为用户选择的风格不同,但URL地址是一样的,所以在这里切换。<httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers>// 当然这样的处理也只适合页面不需要Model的情况下。<httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers>string filePath = HttpContextHelper.RequestFilePath;<httpHandlers>
  22. <httpHandlers>
  23.    
  24. </httpHandlers>
  25. </httpHandlers>int p = filePath.LastIndexOf('/');<httpHandlers>
  26. <httpHandlers>
  27.    
  28. </httpHandlers>
  29. </httpHandlers>string pageName = filePath.Substring(p + 1);<httpHandlers>
  30. <httpHandlers>
  31.    
  32. </httpHandlers>
  33. </httpHandlers>return new PageResult(StyleHelper.GetTargetPageUrl(pageName), null /*model*/);}
复制代码
代码所涉及的4个页面在呈现时,由于并不需要数据,但为了能够实现多样式的支持,它们可以共用一个Action,因此这里只是切换一个View的路径而已。
理解上面那句话,可能还需要知道StyleHelper的实现代码:
  1. public static class StyleHelper{<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>public static readonly string STR_PageStyle = "PageStyle";<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers>public static readonly string[] StyleArray = new string[] { "Style1", "Style2", "Style3" };<httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers>public static string PageStyle<httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers>{<httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers><httpHandlers>
  22. <httpHandlers>
  23.    
  24. </httpHandlers>
  25. </httpHandlers>get { return CookieHelper.GetCookieValue(STR_PageStyle) ?? StyleArray[1]; }<httpHandlers>
  26. <httpHandlers>
  27.    
  28. </httpHandlers>
  29. </httpHandlers>}<httpHandlers>
  30. <httpHandlers>
  31.    
  32. </httpHandlers>
  33. </httpHandlers>public static string GetTargetPageUrl(string pageName)<httpHandlers>
  34. <httpHandlers>
  35.    
  36. </httpHandlers>
  37. </httpHandlers>{<httpHandlers>
  38. <httpHandlers>
  39.    
  40. </httpHandlers>
  41. </httpHandlers><httpHandlers>
  42. <httpHandlers>
  43.    
  44. </httpHandlers>
  45. </httpHandlers>return string.Format("/Pages/{0}/" + pageName, PageStyle);<httpHandlers>
  46. <httpHandlers>
  47.    
  48. </httpHandlers>
  49. </httpHandlers>}}
复制代码
示例网站的目录结构如下图:
8.png

在示例网站中,由于三种风格的截然不同,尤其是在功能与HTML结构上就完全不同,因此根本不可能通过CSS或者SKIN的方式来解决,所以我为三种风格创建了三个目录,分别存放相应的页面文件。最终根据用户的选择(Cookie)来决定使用哪个目录下的页面来呈现。
用户设置风格的JS代码如下,
  1. $(function(){<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>$("a.btnSetStyle").click(function(){<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers><httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers>var style = $(this).attr("ps");<httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers><httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers><httpHandlers>
  22. <httpHandlers>
  23.    
  24. </httpHandlers>
  25. </httpHandlers><httpHandlers>
  26. <httpHandlers>
  27.    
  28. </httpHandlers>
  29. </httpHandlers>// 其实写cookie也可以直接使用JS去写的。<httpHandlers>
  30. <httpHandlers>
  31.    
  32. </httpHandlers>
  33. </httpHandlers><httpHandlers>
  34. <httpHandlers>
  35.    
  36. </httpHandlers>
  37. </httpHandlers>$.ajax({<httpHandlers>
  38. <httpHandlers>
  39.    
  40. </httpHandlers>
  41. </httpHandlers><httpHandlers>
  42. <httpHandlers>
  43.    
  44. </httpHandlers>
  45. </httpHandlers><httpHandlers>
  46. <httpHandlers>
  47.    
  48. </httpHandlers>
  49. </httpHandlers>url: "/AjaxStyle/SetStyle.cspx",<httpHandlers>
  50. <httpHandlers>
  51.    
  52. </httpHandlers>
  53. </httpHandlers><httpHandlers>
  54. <httpHandlers>
  55.    
  56. </httpHandlers>
  57. </httpHandlers><httpHandlers>
  58. <httpHandlers>
  59.    
  60. </httpHandlers>
  61. </httpHandlers>data: {style: style},<httpHandlers>
  62. <httpHandlers>
  63.    
  64. </httpHandlers>
  65. </httpHandlers><httpHandlers>
  66. <httpHandlers>
  67.    
  68. </httpHandlers>
  69. </httpHandlers><httpHandlers>
  70. <httpHandlers>
  71.    
  72. </httpHandlers>
  73. </httpHandlers>success: function(){<httpHandlers>
  74. <httpHandlers>
  75.    
  76. </httpHandlers>
  77. </httpHandlers><httpHandlers>
  78. <httpHandlers>
  79.    
  80. </httpHandlers>
  81. </httpHandlers><httpHandlers>
  82. <httpHandlers>
  83.    
  84. </httpHandlers>
  85. </httpHandlers><httpHandlers>
  86. <httpHandlers>
  87.    
  88. </httpHandlers>
  89. </httpHandlers>window.location = window.location;<httpHandlers>
  90. <httpHandlers>
  91.    
  92. </httpHandlers>
  93. </httpHandlers><httpHandlers>
  94. <httpHandlers>
  95.    
  96. </httpHandlers>
  97. </httpHandlers><httpHandlers>
  98. <httpHandlers>
  99.    
  100. </httpHandlers>
  101. </httpHandlers>}<httpHandlers>
  102. <httpHandlers>
  103.    
  104. </httpHandlers>
  105. </httpHandlers><httpHandlers>
  106. <httpHandlers>
  107.    
  108. </httpHandlers>
  109. </httpHandlers>});<httpHandlers>
  110. <httpHandlers>
  111.    
  112. </httpHandlers>
  113. </httpHandlers><httpHandlers>
  114. <httpHandlers>
  115.    
  116. </httpHandlers>
  117. </httpHandlers>return false;<httpHandlers>
  118. <httpHandlers>
  119.    
  120. </httpHandlers>
  121. </httpHandlers>});});
复制代码
服务端的C#代码如下:
  1. public class AjaxStyle{<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>[Action]<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers>public void SetStyle(string style)<httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers>{<httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers><httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers>if( Array.IndexOf(StyleHelper.StyleArray, style) >= 0 ) {<httpHandlers>
  22. <httpHandlers>
  23.    
  24. </httpHandlers>
  25. </httpHandlers><httpHandlers>
  26. <httpHandlers>
  27.    
  28. </httpHandlers>
  29. </httpHandlers><httpHandlers>
  30. <httpHandlers>
  31.    
  32. </httpHandlers>
  33. </httpHandlers>HttpCookie cookie = new HttpCookie(StyleHelper.STR_PageStyle, style);<httpHandlers>
  34. <httpHandlers>
  35.    
  36. </httpHandlers>
  37. </httpHandlers><httpHandlers>
  38. <httpHandlers>
  39.    
  40. </httpHandlers>
  41. </httpHandlers><httpHandlers>
  42. <httpHandlers>
  43.    
  44. </httpHandlers>
  45. </httpHandlers>cookie.Expires = DateTime.Now.AddYears(1);<httpHandlers>
  46. <httpHandlers>
  47.    
  48. </httpHandlers>
  49. </httpHandlers><httpHandlers>
  50. <httpHandlers>
  51.    
  52. </httpHandlers>
  53. </httpHandlers><httpHandlers>
  54. <httpHandlers>
  55.    
  56. </httpHandlers>
  57. </httpHandlers>CookieHelper.AddCookie(cookie);<httpHandlers>
  58. <httpHandlers>
  59.    
  60. </httpHandlers>
  61. </httpHandlers><httpHandlers>
  62. <httpHandlers>
  63.    
  64. </httpHandlers>
  65. </httpHandlers>}<httpHandlers>
  66. <httpHandlers>
  67.    
  68. </httpHandlers>
  69. </httpHandlers>}}
复制代码
说明:CookieHelper是设计成支持单元测试的,所以不要怀疑这里的代码不符合MVC,后面会专门谈它。
所以,在这种情况下,多个URL映射到一个Action是有意义的。这是【多URL的匹配功能】的第一个用途。
解决老的URL兼容问题

在一个网站的成长过程中,一般会有重构的过程。在重构过程中,或许会删除以前的某些页面,或许调整URL格式。然而,用户也可能会收藏这个网站的链接,但由于页面重构了,老的链接可能会因此而失效,造成404错误。此时就要解决URL的兼容问题。
在ASP.NET中,我们可以在web.config配置urlMappings节点来做这样的映射转换。还有另一种方法是,创建一个HttpModule专门判断是否在请求一些老的URL,如果是,则重定向到新的页面。总之,不管使用哪种方法,都需要为每个传入请求检查URL是否是老格式的URL,这个过程会根据一个列表来逐一检查,不过,可惜的是:绝大部分请求可能都是新的URL格式,而那些兼容方案无疑会浪费很多的CPU资源。
在MyMVC中,可以简单地处理这个问题,就像下面的这个示例一样:
  1. public class CustomerController{<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>[Action]<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers>[PageUrl(Url = "/mvc/Customers")]<httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers>[PageUrl(Url = "/mvc/Customers.html")]<httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers>[PageUrl(Url = "/mvc/CustomerList.aspx")]<httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers>[PageUrl(Url = "/Pages/Customers.aspx")]<httpHandlers>
  22. <httpHandlers>
  23.    
  24. </httpHandlers>
  25. </httpHandlers>public static object LoadModel(int? page)<httpHandlers>
  26. <httpHandlers>
  27.    
  28. </httpHandlers>
  29. </httpHandlers>{
复制代码
这个“客户管理”页面可能经过了多次重构,没关系,只要把各个版本的地址用[PageUrl]标识出来就可以了,完全不用前面所说的兼容方案,因此,在URL的兼容处理上没有任何负担,也不会影响性能。
说明:[PageUrl]的顺序并不重要,可以随意调整。
对身份认证的支持

MyMVC也支持一些基本的身份认证,可以通过在Action方法中添加[Authorize]修饰属性来指示。
AuthorizeAttribute的实现代码如下:
  1. ///<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers> /// 用于验证用户身份的修饰属性<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers>///<httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers> [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]<httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers>public class AuthorizeAttribute : Attribute<httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers>{<httpHandlers>
  22. <httpHandlers>
  23.    
  24. </httpHandlers>
  25. </httpHandlers><httpHandlers>
  26. <httpHandlers>
  27.    
  28. </httpHandlers>
  29. </httpHandlers>private string _user;<httpHandlers>
  30. <httpHandlers>
  31.    
  32. </httpHandlers>
  33. </httpHandlers><httpHandlers>
  34. <httpHandlers>
  35.    
  36. </httpHandlers>
  37. </httpHandlers>private string[] _users;<httpHandlers>
  38. <httpHandlers>
  39.    
  40. </httpHandlers>
  41. </httpHandlers><httpHandlers>
  42. <httpHandlers>
  43.    
  44. </httpHandlers>
  45. </httpHandlers>private string _role;<httpHandlers>
  46. <httpHandlers>
  47.    
  48. </httpHandlers>
  49. </httpHandlers><httpHandlers>
  50. <httpHandlers>
  51.    
  52. </httpHandlers>
  53. </httpHandlers>private string[] _roles;<httpHandlers>
  54. <httpHandlers>
  55.    
  56. </httpHandlers>
  57. </httpHandlers><httpHandlers>
  58. <httpHandlers>
  59.    
  60. </httpHandlers>
  61. </httpHandlers>private string[] SplitString(string value)<httpHandlers>
  62. <httpHandlers>
  63.    
  64. </httpHandlers>
  65. </httpHandlers><httpHandlers>
  66. <httpHandlers>
  67.    
  68. </httpHandlers>
  69. </httpHandlers>{<httpHandlers>
  70. <httpHandlers>
  71.    
  72. </httpHandlers>
  73. </httpHandlers><httpHandlers>
  74. <httpHandlers>
  75.    
  76. </httpHandlers>
  77. </httpHandlers><httpHandlers>
  78. <httpHandlers>
  79.    
  80. </httpHandlers>
  81. </httpHandlers>if( string.IsNullOrEmpty(value) )<httpHandlers>
  82. <httpHandlers>
  83.    
  84. </httpHandlers>
  85. </httpHandlers><httpHandlers>
  86. <httpHandlers>
  87.    
  88. </httpHandlers>
  89. </httpHandlers><httpHandlers>
  90. <httpHandlers>
  91.    
  92. </httpHandlers>
  93. </httpHandlers><httpHandlers>
  94. <httpHandlers>
  95.    
  96. </httpHandlers>
  97. </httpHandlers>return null;<httpHandlers>
  98. <httpHandlers>
  99.    
  100. </httpHandlers>
  101. </httpHandlers><httpHandlers>
  102. <httpHandlers>
  103.    
  104. </httpHandlers>
  105. </httpHandlers><httpHandlers>
  106. <httpHandlers>
  107.    
  108. </httpHandlers>
  109. </httpHandlers>else<httpHandlers>
  110. <httpHandlers>
  111.    
  112. </httpHandlers>
  113. </httpHandlers><httpHandlers>
  114. <httpHandlers>
  115.    
  116. </httpHandlers>
  117. </httpHandlers><httpHandlers>
  118. <httpHandlers>
  119.    
  120. </httpHandlers>
  121. </httpHandlers><httpHandlers>
  122. <httpHandlers>
  123.    
  124. </httpHandlers>
  125. </httpHandlers>return (from s in value.Split(',')<httpHandlers>
  126. <httpHandlers>
  127.    
  128. </httpHandlers>
  129. </httpHandlers><httpHandlers>
  130. <httpHandlers>
  131.    
  132. </httpHandlers>
  133. </httpHandlers><httpHandlers>
  134. <httpHandlers>
  135.    
  136. </httpHandlers>
  137. </httpHandlers><httpHandlers>
  138. <httpHandlers>
  139.    
  140. </httpHandlers>
  141. </httpHandlers><httpHandlers>
  142. <httpHandlers>
  143.    
  144. </httpHandlers>
  145. </httpHandlers><httpHandlers>
  146. <httpHandlers>
  147.    
  148. </httpHandlers>
  149. </httpHandlers>let u = s.Trim()<httpHandlers>
  150. <httpHandlers>
  151.    
  152. </httpHandlers>
  153. </httpHandlers><httpHandlers>
  154. <httpHandlers>
  155.    
  156. </httpHandlers>
  157. </httpHandlers><httpHandlers>
  158. <httpHandlers>
  159.    
  160. </httpHandlers>
  161. </httpHandlers><httpHandlers>
  162. <httpHandlers>
  163.    
  164. </httpHandlers>
  165. </httpHandlers><httpHandlers>
  166. <httpHandlers>
  167.    
  168. </httpHandlers>
  169. </httpHandlers><httpHandlers>
  170. <httpHandlers>
  171.    
  172. </httpHandlers>
  173. </httpHandlers>where u.Length > 0<httpHandlers>
  174. <httpHandlers>
  175.    
  176. </httpHandlers>
  177. </httpHandlers><httpHandlers>
  178. <httpHandlers>
  179.    
  180. </httpHandlers>
  181. </httpHandlers><httpHandlers>
  182. <httpHandlers>
  183.    
  184. </httpHandlers>
  185. </httpHandlers><httpHandlers>
  186. <httpHandlers>
  187.    
  188. </httpHandlers>
  189. </httpHandlers><httpHandlers>
  190. <httpHandlers>
  191.    
  192. </httpHandlers>
  193. </httpHandlers><httpHandlers>
  194. <httpHandlers>
  195.    
  196. </httpHandlers>
  197. </httpHandlers>select u).ToArray();<httpHandlers>
  198. <httpHandlers>
  199.    
  200. </httpHandlers>
  201. </httpHandlers><httpHandlers>
  202. <httpHandlers>
  203.    
  204. </httpHandlers>
  205. </httpHandlers>}<httpHandlers>
  206. <httpHandlers>
  207.    
  208. </httpHandlers>
  209. </httpHandlers><httpHandlers>
  210. <httpHandlers>
  211.    
  212. </httpHandlers>
  213. </httpHandlers>///<httpHandlers>
  214. <httpHandlers>
  215.    
  216. </httpHandlers>
  217. </httpHandlers><httpHandlers>
  218. <httpHandlers>
  219.    
  220. </httpHandlers>
  221. </httpHandlers> /// 允许访问的用户列表,用逗号分隔。<httpHandlers>
  222. <httpHandlers>
  223.    
  224. </httpHandlers>
  225. </httpHandlers><httpHandlers>
  226. <httpHandlers>
  227.    
  228. </httpHandlers>
  229. </httpHandlers>///<httpHandlers>
  230. <httpHandlers>
  231.    
  232. </httpHandlers>
  233. </httpHandlers><httpHandlers>
  234. <httpHandlers>
  235.    
  236. </httpHandlers>
  237. </httpHandlers> public string Users<httpHandlers>
  238. <httpHandlers>
  239.    
  240. </httpHandlers>
  241. </httpHandlers><httpHandlers>
  242. <httpHandlers>
  243.    
  244. </httpHandlers>
  245. </httpHandlers>{<httpHandlers>
  246. <httpHandlers>
  247.    
  248. </httpHandlers>
  249. </httpHandlers><httpHandlers>
  250. <httpHandlers>
  251.    
  252. </httpHandlers>
  253. </httpHandlers><httpHandlers>
  254. <httpHandlers>
  255.    
  256. </httpHandlers>
  257. </httpHandlers>get { return _user; }<httpHandlers>
  258. <httpHandlers>
  259.    
  260. </httpHandlers>
  261. </httpHandlers><httpHandlers>
  262. <httpHandlers>
  263.    
  264. </httpHandlers>
  265. </httpHandlers><httpHandlers>
  266. <httpHandlers>
  267.    
  268. </httpHandlers>
  269. </httpHandlers>set { _user = value; _users = SplitString(value); }<httpHandlers>
  270. <httpHandlers>
  271.    
  272. </httpHandlers>
  273. </httpHandlers><httpHandlers>
  274. <httpHandlers>
  275.    
  276. </httpHandlers>
  277. </httpHandlers>}<httpHandlers>
  278. <httpHandlers>
  279.    
  280. </httpHandlers>
  281. </httpHandlers><httpHandlers>
  282. <httpHandlers>
  283.    
  284. </httpHandlers>
  285. </httpHandlers>///<httpHandlers>
  286. <httpHandlers>
  287.    
  288. </httpHandlers>
  289. </httpHandlers><httpHandlers>
  290. <httpHandlers>
  291.    
  292. </httpHandlers>
  293. </httpHandlers> /// 允许访问的角色列表,用逗号分隔。<httpHandlers>
  294. <httpHandlers>
  295.    
  296. </httpHandlers>
  297. </httpHandlers><httpHandlers>
  298. <httpHandlers>
  299.    
  300. </httpHandlers>
  301. </httpHandlers>///<httpHandlers>
  302. <httpHandlers>
  303.    
  304. </httpHandlers>
  305. </httpHandlers><httpHandlers>
  306. <httpHandlers>
  307.    
  308. </httpHandlers>
  309. </httpHandlers> public string Roles<httpHandlers>
  310. <httpHandlers>
  311.    
  312. </httpHandlers>
  313. </httpHandlers><httpHandlers>
  314. <httpHandlers>
  315.    
  316. </httpHandlers>
  317. </httpHandlers>{<httpHandlers>
  318. <httpHandlers>
  319.    
  320. </httpHandlers>
  321. </httpHandlers><httpHandlers>
  322. <httpHandlers>
  323.    
  324. </httpHandlers>
  325. </httpHandlers><httpHandlers>
  326. <httpHandlers>
  327.    
  328. </httpHandlers>
  329. </httpHandlers>get { return _role; }<httpHandlers>
  330. <httpHandlers>
  331.    
  332. </httpHandlers>
  333. </httpHandlers><httpHandlers>
  334. <httpHandlers>
  335.    
  336. </httpHandlers>
  337. </httpHandlers><httpHandlers>
  338. <httpHandlers>
  339.    
  340. </httpHandlers>
  341. </httpHandlers>set { _role = value; _roles = SplitString(value); }<httpHandlers>
  342. <httpHandlers>
  343.    
  344. </httpHandlers>
  345. </httpHandlers><httpHandlers>
  346. <httpHandlers>
  347.    
  348. </httpHandlers>
  349. </httpHandlers>}<httpHandlers>
  350. <httpHandlers>
  351.    
  352. </httpHandlers>
  353. </httpHandlers><httpHandlers>
  354. <httpHandlers>
  355.    
  356. </httpHandlers>
  357. </httpHandlers>internal bool AuthenticateRequest(HttpContext context)<httpHandlers>
  358. <httpHandlers>
  359.    
  360. </httpHandlers>
  361. </httpHandlers><httpHandlers>
  362. <httpHandlers>
  363.    
  364. </httpHandlers>
  365. </httpHandlers>{<httpHandlers>
  366. <httpHandlers>
  367.    
  368. </httpHandlers>
  369. </httpHandlers><httpHandlers>
  370. <httpHandlers>
  371.    
  372. </httpHandlers>
  373. </httpHandlers><httpHandlers>
  374. <httpHandlers>
  375.    
  376. </httpHandlers>
  377. </httpHandlers>if( context.Request.IsAuthenticated == false )<httpHandlers>
  378. <httpHandlers>
  379.    
  380. </httpHandlers>
  381. </httpHandlers><httpHandlers>
  382. <httpHandlers>
  383.    
  384. </httpHandlers>
  385. </httpHandlers><httpHandlers>
  386. <httpHandlers>
  387.    
  388. </httpHandlers>
  389. </httpHandlers><httpHandlers>
  390. <httpHandlers>
  391.    
  392. </httpHandlers>
  393. </httpHandlers>return false;<httpHandlers>
  394. <httpHandlers>
  395.    
  396. </httpHandlers>
  397. </httpHandlers><httpHandlers>
  398. <httpHandlers>
  399.    
  400. </httpHandlers>
  401. </httpHandlers><httpHandlers>
  402. <httpHandlers>
  403.    
  404. </httpHandlers>
  405. </httpHandlers>if( _users != null &&<httpHandlers>
  406. <httpHandlers>
  407.    
  408. </httpHandlers>
  409. </httpHandlers><httpHandlers>
  410. <httpHandlers>
  411.    
  412. </httpHandlers>
  413. </httpHandlers><httpHandlers>
  414. <httpHandlers>
  415.    
  416. </httpHandlers>
  417. </httpHandlers><httpHandlers>
  418. <httpHandlers>
  419.    
  420. </httpHandlers>
  421. </httpHandlers> _users.Contains(context.User.Identity.Name, StringComparer.OrdinalIgnoreCase) == false )<httpHandlers>
  422. <httpHandlers>
  423.    
  424. </httpHandlers>
  425. </httpHandlers><httpHandlers>
  426. <httpHandlers>
  427.    
  428. </httpHandlers>
  429. </httpHandlers><httpHandlers>
  430. <httpHandlers>
  431.    
  432. </httpHandlers>
  433. </httpHandlers><httpHandlers>
  434. <httpHandlers>
  435.    
  436. </httpHandlers>
  437. </httpHandlers>return false;<httpHandlers>
  438. <httpHandlers>
  439.    
  440. </httpHandlers>
  441. </httpHandlers><httpHandlers>
  442. <httpHandlers>
  443.    
  444. </httpHandlers>
  445. </httpHandlers><httpHandlers>
  446. <httpHandlers>
  447.    
  448. </httpHandlers>
  449. </httpHandlers>if( _roles != null && _roles.Any(context.User.IsInRole) == false )<httpHandlers>
  450. <httpHandlers>
  451.    
  452. </httpHandlers>
  453. </httpHandlers><httpHandlers>
  454. <httpHandlers>
  455.    
  456. </httpHandlers>
  457. </httpHandlers><httpHandlers>
  458. <httpHandlers>
  459.    
  460. </httpHandlers>
  461. </httpHandlers><httpHandlers>
  462. <httpHandlers>
  463.    
  464. </httpHandlers>
  465. </httpHandlers>return false;<httpHandlers>
  466. <httpHandlers>
  467.    
  468. </httpHandlers>
  469. </httpHandlers><httpHandlers>
  470. <httpHandlers>
  471.    
  472. </httpHandlers>
  473. </httpHandlers><httpHandlers>
  474. <httpHandlers>
  475.    
  476. </httpHandlers>
  477. </httpHandlers>return true;<httpHandlers>
  478. <httpHandlers>
  479.    
  480. </httpHandlers>
  481. </httpHandlers><httpHandlers>
  482. <httpHandlers>
  483.    
  484. </httpHandlers>
  485. </httpHandlers>}<httpHandlers>
  486. <httpHandlers>
  487.    
  488. </httpHandlers>
  489. </httpHandlers>}
复制代码
认证检查发生在调用Action之前,代码如下:
  1. internal static void ExecuteAction(HttpContext context, InvokeInfo vkInfo){<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>if( context == null )<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers><httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers>throw new ArgumentNullException("context");<httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers>if( vkInfo == null )<httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers><httpHandlers>
  22. <httpHandlers>
  23.    
  24. </httpHandlers>
  25. </httpHandlers>throw new ArgumentNullException("vkInfo");<httpHandlers>
  26. <httpHandlers>
  27.    
  28. </httpHandlers>
  29. </httpHandlers>// 验证请求是否允许访问(身份验证)<httpHandlers>
  30. <httpHandlers>
  31.    
  32. </httpHandlers>
  33. </httpHandlers>AuthorizeAttribute authorize = vkInfo.GetAuthorize();<httpHandlers>
  34. <httpHandlers>
  35.    
  36. </httpHandlers>
  37. </httpHandlers>if( authorize != null ) {<httpHandlers>
  38. <httpHandlers>
  39.    
  40. </httpHandlers>
  41. </httpHandlers><httpHandlers>
  42. <httpHandlers>
  43.    
  44. </httpHandlers>
  45. </httpHandlers>if( authorize.AuthenticateRequest(context) == false )<httpHandlers>
  46. <httpHandlers>
  47.    
  48. </httpHandlers>
  49. </httpHandlers><httpHandlers>
  50. <httpHandlers>
  51.    
  52. </httpHandlers>
  53. </httpHandlers><httpHandlers>
  54. <httpHandlers>
  55.    
  56. </httpHandlers>
  57. </httpHandlers>ExceptionHelper.Throw403Exception(context);<httpHandlers>
  58. <httpHandlers>
  59.    
  60. </httpHandlers>
  61. </httpHandlers>}<httpHandlers>
  62. <httpHandlers>
  63.    
  64. </httpHandlers>
  65. </httpHandlers>// 调用方法<httpHandlers>
  66. <httpHandlers>
  67.    
  68. </httpHandlers>
  69. </httpHandlers>object result = ExecuteActionInternal(context, vkInfo);<httpHandlers>
  70. <httpHandlers>
  71.    
  72. </httpHandlers>
  73. </httpHandlers>// 设置OutputCache<httpHandlers>
  74. <httpHandlers>
  75.    
  76. </httpHandlers>
  77. </httpHandlers>OutputCacheAttribute outputCache = vkInfo.GetOutputCacheSetting();<httpHandlers>
  78. <httpHandlers>
  79.    
  80. </httpHandlers>
  81. </httpHandlers>if( outputCache != null )<httpHandlers>
  82. <httpHandlers>
  83.    
  84. </httpHandlers>
  85. </httpHandlers><httpHandlers>
  86. <httpHandlers>
  87.    
  88. </httpHandlers>
  89. </httpHandlers>outputCache.SetResponseCache(context);<httpHandlers>
  90. <httpHandlers>
  91.    
  92. </httpHandlers>
  93. </httpHandlers>// 处理方法的返回结果<httpHandlers>
  94. <httpHandlers>
  95.    
  96. </httpHandlers>
  97. </httpHandlers>IActionResult executeResult = result as IActionResult;<httpHandlers>
  98. <httpHandlers>
  99.    
  100. </httpHandlers>
  101. </httpHandlers>if( executeResult != null ) {<httpHandlers>
  102. <httpHandlers>
  103.    
  104. </httpHandlers>
  105. </httpHandlers><httpHandlers>
  106. <httpHandlers>
  107.    
  108. </httpHandlers>
  109. </httpHandlers>executeResult.Ouput(context);<httpHandlers>
  110. <httpHandlers>
  111.    
  112. </httpHandlers>
  113. </httpHandlers>}<httpHandlers>
  114. <httpHandlers>
  115.    
  116. </httpHandlers>
  117. </httpHandlers>else {<httpHandlers>
  118. <httpHandlers>
  119.    
  120. </httpHandlers>
  121. </httpHandlers><httpHandlers>
  122. <httpHandlers>
  123.    
  124. </httpHandlers>
  125. </httpHandlers>if( result != null ) {<httpHandlers>
  126. <httpHandlers>
  127.    
  128. </httpHandlers>
  129. </httpHandlers><httpHandlers>
  130. <httpHandlers>
  131.    
  132. </httpHandlers>
  133. </httpHandlers><httpHandlers>
  134. <httpHandlers>
  135.    
  136. </httpHandlers>
  137. </httpHandlers>// 普通类型结果<httpHandlers>
  138. <httpHandlers>
  139.    
  140. </httpHandlers>
  141. </httpHandlers><httpHandlers>
  142. <httpHandlers>
  143.    
  144. </httpHandlers>
  145. </httpHandlers><httpHandlers>
  146. <httpHandlers>
  147.    
  148. </httpHandlers>
  149. </httpHandlers>context.Response.ContentType = "text/plain";<httpHandlers>
  150. <httpHandlers>
  151.    
  152. </httpHandlers>
  153. </httpHandlers><httpHandlers>
  154. <httpHandlers>
  155.    
  156. </httpHandlers>
  157. </httpHandlers><httpHandlers>
  158. <httpHandlers>
  159.    
  160. </httpHandlers>
  161. </httpHandlers>context.Response.Write(result.ToString());<httpHandlers>
  162. <httpHandlers>
  163.    
  164. </httpHandlers>
  165. </httpHandlers><httpHandlers>
  166. <httpHandlers>
  167.    
  168. </httpHandlers>
  169. </httpHandlers>}<httpHandlers>
  170. <httpHandlers>
  171.    
  172. </httpHandlers>
  173. </httpHandlers>}}
复制代码
下面的示例代码演示了它的用法:
  1. [Action][Authorize(Users="fish")][PageUrl(Url = "/Pages/Demo/TestAuthorize/Fish.aspx")]public object ShowFishPage(){<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>// 仅当当前用户是 fish 时,才允许访问这个PageAction<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers>// 注意:第一参数为null,表示使用当前地址。<httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers>return new PageResult(null, null);}[Action][Authorize][PageUrl(Url = "/Pages/Demo/TestAuthorize/LoginUser.aspx")]public object ShowLoginUserPage(){<httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers>// 仅当当前用户是已登录用户时,才允许访问这个PageAction<httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers>// 注意:第一参数为null,表示使用当前地址。<httpHandlers>
  22. <httpHandlers>
  23.    
  24. </httpHandlers>
  25. </httpHandlers>return new PageResult(null, null);}
复制代码
注意:
1. 如果一个Action没有使用[Authorize],则表示允许任意用户访问(包括未登录用户)。
2. [Authorize]对于AjaxAction仍然有效。
View的设计方式

在MyMVC中,View采用了ASP.NET Page,不过,我并不建议使用CodeFile文件。不使用CodeFile文件,我想这是很多喜欢WebForm的人不能接受的。他们更愿意在CodeFile文件中获取数据,绑定数据,响应事件,处理用户的提交数据。也正是由于这个原因,才会让其它人认为WebForm是一种对单元测试极差的编程模型。
这里我要表达一下我的观点:代码是否可支持单元测试,这其中最主要的原因还是开发人员自身造成的,框架的选择只是起到促进或是部分限制的作用。就算让一些人使用ASP.NET MVC,他们所编写的代码未必就能支持单元测试,有些人实在太依赖于HttpContext.Current,甚至在ASP.NET MVC中还在写这种代码。
好吧,还是回到Page的设计这个话题上来。MyMVC所提倡的做法与ASP.NET MVC的做法类似,那就是直接在Page中采用内联的方式显示数据,而不是在CodeFile中绑定数据。许多人一看到ASP.NET MVC的这种内联写法,感觉又回到了ASP时代,认为是在倒退,其实这只是表面现象。表面的背后是:代码远离了UI。,也可以理解成:逻辑远离了UI。这也是正是ASP.NET MVC一直所提倡的:分离关注点。在新的开发理念中,原来的Page分解成View和Controller,在实现它们时,只关注自身那一部分就可以了,因此,如果单看Page时,可能是会有前面所说的那种感觉。另一方面,由于代码远离了UI,或许可以有更多的机会重构它们,使它们的重用性更高。
下面还是来回顾一下MyMVC中Page的代码:
  1. <%@ Page Title="客户管理" Language="C#" MasterPageFile="MasterPage.master"
  2. <httpHandlers>
  3. <httpHandlers>
  4.    
  5. </httpHandlers>
  6. </httpHandlers><httpHandlers>
  7. <httpHandlers>
  8.    
  9. </httpHandlers>
  10. </httpHandlers>Inherits="MyPageView<CustomersPageModel>" %>
  11. </asp:Content>
  12. <ul class="itemList">
  13. <% foreach( Customer customer in Model.List ) { %>
  14. <li>
  15. <httpHandlers>
  16. <httpHandlers>
  17.    
  18. </httpHandlers>
  19. </httpHandlers><table class="GridView" cellspacing="0" cellpadding="4" border="0" style="border-collapse:collapse;">
  20. <httpHandlers>
  21. <httpHandlers>
  22.    
  23. </httpHandlers>
  24. </httpHandlers><httpHandlers>
  25. <httpHandlers>
  26.    
  27. </httpHandlers>
  28. </httpHandlers><tr><td><%= customer.CustomerName.HtmlEncode()%></td></tr>
  29. <httpHandlers>
  30. <httpHandlers>
  31.    
  32. </httpHandlers>
  33. </httpHandlers><httpHandlers>
  34. <httpHandlers>
  35.    
  36. </httpHandlers>
  37. </httpHandlers><tr><td><%= customer.ContactName.HtmlEncode() %></td></tr>
  38. <httpHandlers>
  39. <httpHandlers>
  40.    
  41. </httpHandlers>
  42. </httpHandlers><httpHandlers>
  43. <httpHandlers>
  44.    
  45. </httpHandlers>
  46. </httpHandlers><tr><td><%= customer.Address.HtmlEncode() %></td></tr>
  47. <httpHandlers>
  48. <httpHandlers>
  49.    
  50. </httpHandlers>
  51. </httpHandlers><httpHandlers>
  52. <httpHandlers>
  53.    
  54. </httpHandlers>
  55. </httpHandlers><tr><td><%= customer.PostalCode.HtmlEncode() %></td></tr>
  56. <httpHandlers>
  57. <httpHandlers>
  58.    
  59. </httpHandlers>
  60. </httpHandlers><httpHandlers>
  61. <httpHandlers>
  62.    
  63. </httpHandlers>
  64. </httpHandlers><tr><td><%= customer.Tel.HtmlEncode() %></td></tr>
  65. <httpHandlers>
  66. <httpHandlers>
  67.    
  68. </httpHandlers>
  69. </httpHandlers></table>
  70. </li>
  71. <% } %>
  72. </ul>
  73. <%= Model.PagingInfo.PaginationBar()%>
  74. </asp:Content>
复制代码
此时,对于呈现所需的数据可以直接从Model对象中获取,但要求在Page指令中指出Model的类型,这样还可以有智能提示的优点。如果页面需要显示数据,请务必从MyPageView继承,它的实现代码如下:
  1. /// /// 页面视图的基类/// /// 传递给页面呈现时所需的数据实体对象类型public class MyPageView : MyBasePage{<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>///<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers> /// 用于页面呈现时所需的数据实体对象<httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers>///<httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers> public TModel Model { get; set; }<httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers>}
复制代码
其实也就是一个简单的类型,包含了Model这个属性而已。至于MyBasePage的实现代码,我们可以忽略它,它是直接从System.Web.UI.Page继承的。
再来一段用户控件的代码:
  1. [table][tr][td]客户名称[/td][td]<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers><httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers>[/td][/tr][tr][td]联系人[/td][td]<httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers><httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers>[/td][/tr][tr][td]地址[/td][td]<httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers><httpHandlers>
  22. <httpHandlers>
  23.    
  24. </httpHandlers>
  25. </httpHandlers>[/td][/tr][tr][td]邮编[/td][td]<httpHandlers>
  26. <httpHandlers>
  27.    
  28. </httpHandlers>
  29. </httpHandlers><httpHandlers>
  30. <httpHandlers>
  31.    
  32. </httpHandlers>
  33. </httpHandlers>[/td][/tr][tr][td]电话[/td][td]<httpHandlers>
  34. <httpHandlers>
  35.    
  36. </httpHandlers>
  37. </httpHandlers><httpHandlers>
  38. <httpHandlers>
  39.    
  40. </httpHandlers>
  41. </httpHandlers>[/td][/tr][/table]
复制代码
基本上,与Page的开发方式差不多,只是基类换成了MyUserControlView而已。
在这里我认为要补充一点的是:
与ASP.NET MVC不同,MyMVC不提供任何HtmlHelper。
我认为HtmlHelper与MVC思想完全没有关系,因此不提供这些方法。
另一方面,很多人希望更好地控制HTML代码,因此就更没必要提供这些方法了。
如果您认为需要一些必要的HtmlHelper方法,那么可以实现自己喜欢的HtmlHelper类库。
最后我想说的是:页面继承泛型类,还需要一些额外的处理。比如下面的代码:
  1. Inherits="MyPageView<CustomersPageModel>"
复制代码
要让这种设置能够通过编译,需要在web.config中做如下配置:
  1. [/code]ViewTypeParserFilter的实现代码较长,我就不在此贴出了,可以从本文结尾处下载。
  2. [size=6]Controller,Action的设计方式[/size]
  3. 在MyMVC中,Action分为二种:AjaxAction和PageAction。
  4. PageAction与AjaxActioin在方法的定义上并没有什么差异,只要是个public方法就可以了。
  5. 不过,PageAction与AjaxAction不同点在于:
  6. 1. Controller的容器名称不同,PageAction要求Controller的名字必须以Controller结尾。
  7. 2. 必须有一个有效的[PageUrl]的修饰属性指出可以处理的URL
  8. 3. Action的名字与URL无关,可以随意取名。
  9. 在MyMVC中,2种Action还有另一特点是:不区分GET,POST 。
  10. 原因是:我喜欢用JQuery,用它实现客户端的Ajax时,GET, POST,只是一个参数的差别而已。另一方面,对于HTML表单来说,GET, POST也只是一个参数的差别,[b]大部分[/b]表单也可以通过GET方式来提交,只要您愿意。所以,我想,既然客户端可以这样灵活地切换,服务端也就没有必要再去做那样限制。或许有些人认为区分二者会更安全,但我认为它们对安全性基本上不构成影响。反而,如果服务端忽略它们,只会让客户端更容易调用。
  11. 还有一种情况下可能需要区分二者:请求与提交是同一个地址。
  12. 这应该可以算得上是我在上篇总结的【以服务端为中心的网站】的开发方式。
  13. 事实上,在使用MyMVC的项目中,标签应该需要手写,可能更多的时候会提交到另一个地址,
  14. 因为,我更建议使用Ajax方式提交数据。
  15. 所以,最终我决定:[b]MyMVC的Action不区分GET, POST.[/b]
  16. 在设计MyMVC时,我一直没有忘记将View和Controller的分离,而且对于Controller,只有名字上的约束,Action的约束也较少,因此,我们在实现Action时,完全可以把它们独立到【类库项目】中,
  17. 就像示例项目这样:
  18. [align=center] 9.png [/align]
  19. 这样做的好处是:测试Actioin会更容易。
  20. 此时网站可能只是一堆aspx,js, css文件。我一直期待能将aspx也交给美工去维护,这样设计但愿能让可能性更大一些。
  21. [size=6]输出HTML的方式[/size]
  22. MyMVC提供二种方式在Action中返回HTML,分别是返回PageResult或者UcResult,表示需要呈现一个页面或者一个用户控件。当在Action返回这二种结果时,Action的部分就执行完毕了。剩下的处理是在MyMVC框架中进行的,MyMVC框架会对这二种结果,以IActionResult接口的方式调用Ouput方法输出结果给客户端。
  23. PageResult和UcResult的实现代码如下:
  24. [code]public interface IActionResult{<httpHandlers>
  25. <httpHandlers>
  26.    
  27. </httpHandlers>
  28. </httpHandlers>void Ouput(HttpContext context);}/// /// 表示一个用户控件结果(用户控件将由框架执行)/// public sealed class UcResult : IActionResult{<httpHandlers>
  29. <httpHandlers>
  30.    
  31. </httpHandlers>
  32. </httpHandlers>public string VirtualPath { get; private set; }<httpHandlers>
  33. <httpHandlers>
  34.    
  35. </httpHandlers>
  36. </httpHandlers>public object Model { get; private set; }<httpHandlers>
  37. <httpHandlers>
  38.    
  39. </httpHandlers>
  40. </httpHandlers>public UcResult(string virtualPath, object model)<httpHandlers>
  41. <httpHandlers>
  42.    
  43. </httpHandlers>
  44. </httpHandlers>{<httpHandlers>
  45. <httpHandlers>
  46.    
  47. </httpHandlers>
  48. </httpHandlers><httpHandlers>
  49. <httpHandlers>
  50.    
  51. </httpHandlers>
  52. </httpHandlers>if( string.IsNullOrEmpty(virtualPath) )<httpHandlers>
  53. <httpHandlers>
  54.    
  55. </httpHandlers>
  56. </httpHandlers><httpHandlers>
  57. <httpHandlers>
  58.    
  59. </httpHandlers>
  60. </httpHandlers><httpHandlers>
  61. <httpHandlers>
  62.    
  63. </httpHandlers>
  64. </httpHandlers>throw new ArgumentNullException("virtualPath");<httpHandlers>
  65. <httpHandlers>
  66.    
  67. </httpHandlers>
  68. </httpHandlers><httpHandlers>
  69. <httpHandlers>
  70.    
  71. </httpHandlers>
  72. </httpHandlers>this.VirtualPath = virtualPath;<httpHandlers>
  73. <httpHandlers>
  74.    
  75. </httpHandlers>
  76. </httpHandlers><httpHandlers>
  77. <httpHandlers>
  78.    
  79. </httpHandlers>
  80. </httpHandlers>this.Model = model;<httpHandlers>
  81. <httpHandlers>
  82.    
  83. </httpHandlers>
  84. </httpHandlers>}<httpHandlers>
  85. <httpHandlers>
  86.    
  87. </httpHandlers>
  88. </httpHandlers>void IActionResult.Ouput(HttpContext context)<httpHandlers>
  89. <httpHandlers>
  90.    
  91. </httpHandlers>
  92. </httpHandlers>{<httpHandlers>
  93. <httpHandlers>
  94.    
  95. </httpHandlers>
  96. </httpHandlers><httpHandlers>
  97. <httpHandlers>
  98.    
  99. </httpHandlers>
  100. </httpHandlers>context.Response.ContentType = "text/html";<httpHandlers>
  101. <httpHandlers>
  102.    
  103. </httpHandlers>
  104. </httpHandlers><httpHandlers>
  105. <httpHandlers>
  106.    
  107. </httpHandlers>
  108. </httpHandlers>string html = UcExecutor.Render(VirtualPath, Model);<httpHandlers>
  109. <httpHandlers>
  110.    
  111. </httpHandlers>
  112. </httpHandlers><httpHandlers>
  113. <httpHandlers>
  114.    
  115. </httpHandlers>
  116. </httpHandlers>context.Response.Write(html);<httpHandlers>
  117. <httpHandlers>
  118.    
  119. </httpHandlers>
  120. </httpHandlers>}}/// /// 表示一个页面结果(页面将由框架执行)/// public sealed class PageResult : IActionResult{<httpHandlers>
  121. <httpHandlers>
  122.    
  123. </httpHandlers>
  124. </httpHandlers>public string VirtualPath { get; private set; }<httpHandlers>
  125. <httpHandlers>
  126.    
  127. </httpHandlers>
  128. </httpHandlers>public object Model { get; private set; }<httpHandlers>
  129. <httpHandlers>
  130.    
  131. </httpHandlers>
  132. </httpHandlers>public PageResult(string virtualPath, object model)<httpHandlers>
  133. <httpHandlers>
  134.    
  135. </httpHandlers>
  136. </httpHandlers>{<httpHandlers>
  137. <httpHandlers>
  138.    
  139. </httpHandlers>
  140. </httpHandlers><httpHandlers>
  141. <httpHandlers>
  142.    
  143. </httpHandlers>
  144. </httpHandlers>this.VirtualPath = virtualPath;<httpHandlers>
  145. <httpHandlers>
  146.    
  147. </httpHandlers>
  148. </httpHandlers><httpHandlers>
  149. <httpHandlers>
  150.    
  151. </httpHandlers>
  152. </httpHandlers>this.Model = model;<httpHandlers>
  153. <httpHandlers>
  154.    
  155. </httpHandlers>
  156. </httpHandlers>}<httpHandlers>
  157. <httpHandlers>
  158.    
  159. </httpHandlers>
  160. </httpHandlers>void IActionResult.Ouput(HttpContext context)<httpHandlers>
  161. <httpHandlers>
  162.    
  163. </httpHandlers>
  164. </httpHandlers>{<httpHandlers>
  165. <httpHandlers>
  166.    
  167. </httpHandlers>
  168. </httpHandlers><httpHandlers>
  169. <httpHandlers>
  170.    
  171. </httpHandlers>
  172. </httpHandlers>if( string.IsNullOrEmpty(this.VirtualPath) )<httpHandlers>
  173. <httpHandlers>
  174.    
  175. </httpHandlers>
  176. </httpHandlers><httpHandlers>
  177. <httpHandlers>
  178.    
  179. </httpHandlers>
  180. </httpHandlers><httpHandlers>
  181. <httpHandlers>
  182.    
  183. </httpHandlers>
  184. </httpHandlers>this.VirtualPath = context.Request.FilePath;<httpHandlers>
  185. <httpHandlers>
  186.    
  187. </httpHandlers>
  188. </httpHandlers><httpHandlers>
  189. <httpHandlers>
  190.    
  191. </httpHandlers>
  192. </httpHandlers>context.Response.ContentType = "text/html";<httpHandlers>
  193. <httpHandlers>
  194.    
  195. </httpHandlers>
  196. </httpHandlers><httpHandlers>
  197. <httpHandlers>
  198.    
  199. </httpHandlers>
  200. </httpHandlers>string html = PageExecutor.Render(context, VirtualPath, Model);<httpHandlers>
  201. <httpHandlers>
  202.    
  203. </httpHandlers>
  204. </httpHandlers><httpHandlers>
  205. <httpHandlers>
  206.    
  207. </httpHandlers>
  208. </httpHandlers>context.Response.Write(html);<httpHandlers>
  209. <httpHandlers>
  210.    
  211. </httpHandlers>
  212. </httpHandlers>}}
复制代码
这二个类型的使用方式是一样的,都需要提供二个参数,第一个参数表示页面或者用户控件的存放路径,第二个参数表示给页面或者用户控件所需的显示数据。比如下面这个示例:
  1. [Action]public object ShowCustomerPicker(string searchWord, int? page){<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>CustomerSearchInfo info = new CustomerSearchInfo();<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers>info.SearchWord = searchWord ?? string.Empty;<httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers>info.PageIndex = page.HasValue ? page.Value - 1 : 0;<httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers>info.PageSize = AppHelper.DefaultPageSize;<httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers>CustomerPickerModel data = new CustomerPickerModel();<httpHandlers>
  22. <httpHandlers>
  23.    
  24. </httpHandlers>
  25. </httpHandlers>data.SearchInfo = info;<httpHandlers>
  26. <httpHandlers>
  27.    
  28. </httpHandlers>
  29. </httpHandlers>data.List = BllFactory.GetCustomerBLL().GetList(info);<httpHandlers>
  30. <httpHandlers>
  31.    
  32. </httpHandlers>
  33. </httpHandlers>return new UcResult("/Controls/Style1/CustomerPicker.ascx", data);}
复制代码
设计这二类结果,我的本意是:
1. UcResult给Ajax请求使用,因为有可能会要求服务端输出一段HTML
2. PageResult用于整页面的响应。
在MyMVC中,执行页面或者用户控件,需要指出页面或者用户控件的路径,而不是采用什么约定关系。
我认为约定会造成名字耦合,约定也会影响限制灵活,因此,必须明确指定(允许为null)。
PageResult多用于PageAction,而PageAction又有[PageUrl]来指示可以处理哪些URL,虽然一个PageAction可以处理多个URL,但通常情况下,还是以一个PageAction处理一个URL的情况居多。此时,MyMVC允许在返回PageResult时,第一个参数可以设置为null,表示使用当前请求地址。如果此时当前请求地址有一个aspx页面与之对应,自然就会方便很多。可以参考下面的示例:
  1. [Action][Authorize(Users="fish")][PageUrl(Url = "/Pages/Demo/TestAuthorize/Fish.aspx")]public object ShowFishPage(){<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>// 仅当当前用户是 fish 时,才允许访问这个PageAction<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers>// 注意:第一参数为null,表示使用当前地址。<httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers>return new PageResult(null, null);}
复制代码
在MyMVC框架中,PageResult最终会调用PageExecutor.Render()来获取页面的生成代码,具体过程如下:
  1. public static class PageExecutor{<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>internal static readonly Type MyPageViewOpenType = typeof(MyPageView);<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers>private static void SetPageModel(IHttpHandler handler, object model)<httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers>{<httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers><httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers>if( handler == null )<httpHandlers>
  22. <httpHandlers>
  23.    
  24. </httpHandlers>
  25. </httpHandlers><httpHandlers>
  26. <httpHandlers>
  27.    
  28. </httpHandlers>
  29. </httpHandlers><httpHandlers>
  30. <httpHandlers>
  31.    
  32. </httpHandlers>
  33. </httpHandlers>return;<httpHandlers>
  34. <httpHandlers>
  35.    
  36. </httpHandlers>
  37. </httpHandlers><httpHandlers>
  38. <httpHandlers>
  39.    
  40. </httpHandlers>
  41. </httpHandlers>if( model != null ) {<httpHandlers>
  42. <httpHandlers>
  43.    
  44. </httpHandlers>
  45. </httpHandlers><httpHandlers>
  46. <httpHandlers>
  47.    
  48. </httpHandlers>
  49. </httpHandlers><httpHandlers>
  50. <httpHandlers>
  51.    
  52. </httpHandlers>
  53. </httpHandlers>Type handlerType = handler.GetType().BaseType;<httpHandlers>
  54. <httpHandlers>
  55.    
  56. </httpHandlers>
  57. </httpHandlers><httpHandlers>
  58. <httpHandlers>
  59.    
  60. </httpHandlers>
  61. </httpHandlers><httpHandlers>
  62. <httpHandlers>
  63.    
  64. </httpHandlers>
  65. </httpHandlers>Type viewType = MyPageViewOpenType.MakeGenericType(model.GetType());<httpHandlers>
  66. <httpHandlers>
  67.    
  68. </httpHandlers>
  69. </httpHandlers><httpHandlers>
  70. <httpHandlers>
  71.    
  72. </httpHandlers>
  73. </httpHandlers><httpHandlers>
  74. <httpHandlers>
  75.    
  76. </httpHandlers>
  77. </httpHandlers>// 检查类型是否匹配<httpHandlers>
  78. <httpHandlers>
  79.    
  80. </httpHandlers>
  81. </httpHandlers><httpHandlers>
  82. <httpHandlers>
  83.    
  84. </httpHandlers>
  85. </httpHandlers><httpHandlers>
  86. <httpHandlers>
  87.    
  88. </httpHandlers>
  89. </httpHandlers>if( handlerType == viewType || handlerType.IsSubclassOf(viewType) ) {<httpHandlers>
  90. <httpHandlers>
  91.    
  92. </httpHandlers>
  93. </httpHandlers><httpHandlers>
  94. <httpHandlers>
  95.    
  96. </httpHandlers>
  97. </httpHandlers><httpHandlers>
  98. <httpHandlers>
  99.    
  100. </httpHandlers>
  101. </httpHandlers><httpHandlers>
  102. <httpHandlers>
  103.    
  104. </httpHandlers>
  105. </httpHandlers>DataMember member = ReflectionHelper.GetMemberByName(viewType, "Model", true);<httpHandlers>
  106. <httpHandlers>
  107.    
  108. </httpHandlers>
  109. </httpHandlers><httpHandlers>
  110. <httpHandlers>
  111.    
  112. </httpHandlers>
  113. </httpHandlers><httpHandlers>
  114. <httpHandlers>
  115.    
  116. </httpHandlers>
  117. </httpHandlers><httpHandlers>
  118. <httpHandlers>
  119.    
  120. </httpHandlers>
  121. </httpHandlers>member.SetValue(handler, model);<httpHandlers>
  122. <httpHandlers>
  123.    
  124. </httpHandlers>
  125. </httpHandlers><httpHandlers>
  126. <httpHandlers>
  127.    
  128. </httpHandlers>
  129. </httpHandlers><httpHandlers>
  130. <httpHandlers>
  131.    
  132. </httpHandlers>
  133. </httpHandlers>}<httpHandlers>
  134. <httpHandlers>
  135.    
  136. </httpHandlers>
  137. </httpHandlers><httpHandlers>
  138. <httpHandlers>
  139.    
  140. </httpHandlers>
  141. </httpHandlers><httpHandlers>
  142. <httpHandlers>
  143.    
  144. </httpHandlers>
  145. </httpHandlers>else<httpHandlers>
  146. <httpHandlers>
  147.    
  148. </httpHandlers>
  149. </httpHandlers><httpHandlers>
  150. <httpHandlers>
  151.    
  152. </httpHandlers>
  153. </httpHandlers><httpHandlers>
  154. <httpHandlers>
  155.    
  156. </httpHandlers>
  157. </httpHandlers><httpHandlers>
  158. <httpHandlers>
  159.    
  160. </httpHandlers>
  161. </httpHandlers>throw new ArgumentException("参数model的类型与页面的参数类型不一致。");<httpHandlers>
  162. <httpHandlers>
  163.    
  164. </httpHandlers>
  165. </httpHandlers><httpHandlers>
  166. <httpHandlers>
  167.    
  168. </httpHandlers>
  169. </httpHandlers>}<httpHandlers>
  170. <httpHandlers>
  171.    
  172. </httpHandlers>
  173. </httpHandlers>}<httpHandlers>
  174. <httpHandlers>
  175.    
  176. </httpHandlers>
  177. </httpHandlers>///<httpHandlers>
  178. <httpHandlers>
  179.    
  180. </httpHandlers>
  181. </httpHandlers> /// 用指定的页面路径以及视图数据呈现结果,最后返回生成的HTML代码。<httpHandlers>
  182. <httpHandlers>
  183.    
  184. </httpHandlers>
  185. </httpHandlers>/// 页面应从MyPageView<T>继承<httpHandlers>
  186. <httpHandlers>
  187.    
  188. </httpHandlers>
  189. </httpHandlers>///<httpHandlers>
  190. <httpHandlers>
  191.    
  192. </httpHandlers>
  193. </httpHandlers> /// HttpContext对象<httpHandlers>
  194. <httpHandlers>
  195.    
  196. </httpHandlers>
  197. </httpHandlers>/// Page的虚拟路径<httpHandlers>
  198. <httpHandlers>
  199.    
  200. </httpHandlers>
  201. </httpHandlers>/// 视图数据<httpHandlers>
  202. <httpHandlers>
  203.    
  204. </httpHandlers>
  205. </httpHandlers>/// 生成的HTML代码<httpHandlers>
  206. <httpHandlers>
  207.    
  208. </httpHandlers>
  209. </httpHandlers>public static string Render(HttpContext context, string pageVirtualPath, object model)<httpHandlers>
  210. <httpHandlers>
  211.    
  212. </httpHandlers>
  213. </httpHandlers>{<httpHandlers>
  214. <httpHandlers>
  215.    
  216. </httpHandlers>
  217. </httpHandlers><httpHandlers>
  218. <httpHandlers>
  219.    
  220. </httpHandlers>
  221. </httpHandlers>if( context == null )<httpHandlers>
  222. <httpHandlers>
  223.    
  224. </httpHandlers>
  225. </httpHandlers><httpHandlers>
  226. <httpHandlers>
  227.    
  228. </httpHandlers>
  229. </httpHandlers><httpHandlers>
  230. <httpHandlers>
  231.    
  232. </httpHandlers>
  233. </httpHandlers>throw new ArgumentNullException("context");<httpHandlers>
  234. <httpHandlers>
  235.    
  236. </httpHandlers>
  237. </httpHandlers><httpHandlers>
  238. <httpHandlers>
  239.    
  240. </httpHandlers>
  241. </httpHandlers>if( string.IsNullOrEmpty(pageVirtualPath) )<httpHandlers>
  242. <httpHandlers>
  243.    
  244. </httpHandlers>
  245. </httpHandlers><httpHandlers>
  246. <httpHandlers>
  247.    
  248. </httpHandlers>
  249. </httpHandlers><httpHandlers>
  250. <httpHandlers>
  251.    
  252. </httpHandlers>
  253. </httpHandlers>throw new ArgumentNullException("pageVirtualPath");<httpHandlers>
  254. <httpHandlers>
  255.    
  256. </httpHandlers>
  257. </httpHandlers><httpHandlers>
  258. <httpHandlers>
  259.    
  260. </httpHandlers>
  261. </httpHandlers>Page handler = BuildManager.CreateInstanceFromVirtualPath(<httpHandlers>
  262. <httpHandlers>
  263.    
  264. </httpHandlers>
  265. </httpHandlers><httpHandlers>
  266. <httpHandlers>
  267.    
  268. </httpHandlers>
  269. </httpHandlers><httpHandlers>
  270. <httpHandlers>
  271.    
  272. </httpHandlers>
  273. </httpHandlers><httpHandlers>
  274. <httpHandlers>
  275.    
  276. </httpHandlers>
  277. </httpHandlers><httpHandlers>
  278. <httpHandlers>
  279.    
  280. </httpHandlers>
  281. </httpHandlers><httpHandlers>
  282. <httpHandlers>
  283.    
  284. </httpHandlers>
  285. </httpHandlers><httpHandlers>
  286. <httpHandlers>
  287.    
  288. </httpHandlers>
  289. </httpHandlers><httpHandlers>
  290. <httpHandlers>
  291.    
  292. </httpHandlers>
  293. </httpHandlers><httpHandlers>
  294. <httpHandlers>
  295.    
  296. </httpHandlers>
  297. </httpHandlers><httpHandlers>
  298. <httpHandlers>
  299.    
  300. </httpHandlers>
  301. </httpHandlers>pageVirtualPath, typeof(object)) as Page;<httpHandlers>
  302. <httpHandlers>
  303.    
  304. </httpHandlers>
  305. </httpHandlers><httpHandlers>
  306. <httpHandlers>
  307.    
  308. </httpHandlers>
  309. </httpHandlers>if( handler == null )<httpHandlers>
  310. <httpHandlers>
  311.    
  312. </httpHandlers>
  313. </httpHandlers><httpHandlers>
  314. <httpHandlers>
  315.    
  316. </httpHandlers>
  317. </httpHandlers><httpHandlers>
  318. <httpHandlers>
  319.    
  320. </httpHandlers>
  321. </httpHandlers>throw new InvalidOperationException(<httpHandlers>
  322. <httpHandlers>
  323.    
  324. </httpHandlers>
  325. </httpHandlers><httpHandlers>
  326. <httpHandlers>
  327.    
  328. </httpHandlers>
  329. </httpHandlers><httpHandlers>
  330. <httpHandlers>
  331.    
  332. </httpHandlers>
  333. </httpHandlers><httpHandlers>
  334. <httpHandlers>
  335.    
  336. </httpHandlers>
  337. </httpHandlers>string.Format("指定的路径 {0} 不是一个有效的页面。", pageVirtualPath));<httpHandlers>
  338. <httpHandlers>
  339.    
  340. </httpHandlers>
  341. </httpHandlers><httpHandlers>
  342. <httpHandlers>
  343.    
  344. </httpHandlers>
  345. </httpHandlers>SetPageModel(handler, model);<httpHandlers>
  346. <httpHandlers>
  347.    
  348. </httpHandlers>
  349. </httpHandlers><httpHandlers>
  350. <httpHandlers>
  351.    
  352. </httpHandlers>
  353. </httpHandlers>StringWriter output = new StringWriter();<httpHandlers>
  354. <httpHandlers>
  355.    
  356. </httpHandlers>
  357. </httpHandlers><httpHandlers>
  358. <httpHandlers>
  359.    
  360. </httpHandlers>
  361. </httpHandlers>context.Server.Execute(handler, output, false);<httpHandlers>
  362. <httpHandlers>
  363.    
  364. </httpHandlers>
  365. </httpHandlers><httpHandlers>
  366. <httpHandlers>
  367.    
  368. </httpHandlers>
  369. </httpHandlers>return output.ToString();<httpHandlers>
  370. <httpHandlers>
  371.    
  372. </httpHandlers>
  373. </httpHandlers>}
复制代码
UcResult则会调用UcExecutor.Render()生成用户控件的输出代码,具体过程如下:
  1. public static class UcExecutor{<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>internal static readonly Type MyUserControlViewOpenType = typeof(MyUserControlView);<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers>///<httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers> /// 用指定的用户控件以及视图数据呈现结果,最后返回生成的HTML代码。<httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers>/// 用户控件应从MyUserControlView<T>继承<httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers>///<httpHandlers>
  22. <httpHandlers>
  23.    
  24. </httpHandlers>
  25. </httpHandlers> /// 用户控件的虚拟路径<httpHandlers>
  26. <httpHandlers>
  27.    
  28. </httpHandlers>
  29. </httpHandlers>/// 视图数据<httpHandlers>
  30. <httpHandlers>
  31.    
  32. </httpHandlers>
  33. </httpHandlers>/// 生成的HTML代码<httpHandlers>
  34. <httpHandlers>
  35.    
  36. </httpHandlers>
  37. </httpHandlers>public static string Render(string ucVirtualPath, object model)<httpHandlers>
  38. <httpHandlers>
  39.    
  40. </httpHandlers>
  41. </httpHandlers>{<httpHandlers>
  42. <httpHandlers>
  43.    
  44. </httpHandlers>
  45. </httpHandlers><httpHandlers>
  46. <httpHandlers>
  47.    
  48. </httpHandlers>
  49. </httpHandlers>if( string.IsNullOrEmpty(ucVirtualPath) )<httpHandlers>
  50. <httpHandlers>
  51.    
  52. </httpHandlers>
  53. </httpHandlers><httpHandlers>
  54. <httpHandlers>
  55.    
  56. </httpHandlers>
  57. </httpHandlers><httpHandlers>
  58. <httpHandlers>
  59.    
  60. </httpHandlers>
  61. </httpHandlers>throw new ArgumentNullException("ucVirtualPath");<httpHandlers>
  62. <httpHandlers>
  63.    
  64. </httpHandlers>
  65. </httpHandlers><httpHandlers>
  66. <httpHandlers>
  67.    
  68. </httpHandlers>
  69. </httpHandlers>Page page = new Page();<httpHandlers>
  70. <httpHandlers>
  71.    
  72. </httpHandlers>
  73. </httpHandlers><httpHandlers>
  74. <httpHandlers>
  75.    
  76. </httpHandlers>
  77. </httpHandlers>Control ctl = page.LoadControl(ucVirtualPath);<httpHandlers>
  78. <httpHandlers>
  79.    
  80. </httpHandlers>
  81. </httpHandlers><httpHandlers>
  82. <httpHandlers>
  83.    
  84. </httpHandlers>
  85. </httpHandlers>if( ctl == null )<httpHandlers>
  86. <httpHandlers>
  87.    
  88. </httpHandlers>
  89. </httpHandlers><httpHandlers>
  90. <httpHandlers>
  91.    
  92. </httpHandlers>
  93. </httpHandlers><httpHandlers>
  94. <httpHandlers>
  95.    
  96. </httpHandlers>
  97. </httpHandlers>throw new InvalidOperationException(<httpHandlers>
  98. <httpHandlers>
  99.    
  100. </httpHandlers>
  101. </httpHandlers><httpHandlers>
  102. <httpHandlers>
  103.    
  104. </httpHandlers>
  105. </httpHandlers><httpHandlers>
  106. <httpHandlers>
  107.    
  108. </httpHandlers>
  109. </httpHandlers><httpHandlers>
  110. <httpHandlers>
  111.    
  112. </httpHandlers>
  113. </httpHandlers>string.Format("指定的用户控件 {0} 没有找到。", ucVirtualPath));<httpHandlers>
  114. <httpHandlers>
  115.    
  116. </httpHandlers>
  117. </httpHandlers><httpHandlers>
  118. <httpHandlers>
  119.    
  120. </httpHandlers>
  121. </httpHandlers>MyBaseUserControl myctl = ctl as MyBaseUserControl;<httpHandlers>
  122. <httpHandlers>
  123.    
  124. </httpHandlers>
  125. </httpHandlers><httpHandlers>
  126. <httpHandlers>
  127.    
  128. </httpHandlers>
  129. </httpHandlers>if( myctl != null ) {<httpHandlers>
  130. <httpHandlers>
  131.    
  132. </httpHandlers>
  133. </httpHandlers><httpHandlers>
  134. <httpHandlers>
  135.    
  136. </httpHandlers>
  137. </httpHandlers><httpHandlers>
  138. <httpHandlers>
  139.    
  140. </httpHandlers>
  141. </httpHandlers>if( model != null ) {<httpHandlers>
  142. <httpHandlers>
  143.    
  144. </httpHandlers>
  145. </httpHandlers><httpHandlers>
  146. <httpHandlers>
  147.    
  148. </httpHandlers>
  149. </httpHandlers><httpHandlers>
  150. <httpHandlers>
  151.    
  152. </httpHandlers>
  153. </httpHandlers><httpHandlers>
  154. <httpHandlers>
  155.    
  156. </httpHandlers>
  157. </httpHandlers>Type viewType = MyUserControlViewOpenType.MakeGenericType(model.GetType());<httpHandlers>
  158. <httpHandlers>
  159.    
  160. </httpHandlers>
  161. </httpHandlers><httpHandlers>
  162. <httpHandlers>
  163.    
  164. </httpHandlers>
  165. </httpHandlers><httpHandlers>
  166. <httpHandlers>
  167.    
  168. </httpHandlers>
  169. </httpHandlers><httpHandlers>
  170. <httpHandlers>
  171.    
  172. </httpHandlers>
  173. </httpHandlers>Type ctrlType = myctl.GetType();<httpHandlers>
  174. <httpHandlers>
  175.    
  176. </httpHandlers>
  177. </httpHandlers><httpHandlers>
  178. <httpHandlers>
  179.    
  180. </httpHandlers>
  181. </httpHandlers><httpHandlers>
  182. <httpHandlers>
  183.    
  184. </httpHandlers>
  185. </httpHandlers><httpHandlers>
  186. <httpHandlers>
  187.    
  188. </httpHandlers>
  189. </httpHandlers>// 检查用户控件的类型是否匹配<httpHandlers>
  190. <httpHandlers>
  191.    
  192. </httpHandlers>
  193. </httpHandlers><httpHandlers>
  194. <httpHandlers>
  195.    
  196. </httpHandlers>
  197. </httpHandlers><httpHandlers>
  198. <httpHandlers>
  199.    
  200. </httpHandlers>
  201. </httpHandlers><httpHandlers>
  202. <httpHandlers>
  203.    
  204. </httpHandlers>
  205. </httpHandlers>if( ctrlType == viewType || ctrlType.IsSubclassOf(viewType) ) {<httpHandlers>
  206. <httpHandlers>
  207.    
  208. </httpHandlers>
  209. </httpHandlers><httpHandlers>
  210. <httpHandlers>
  211.    
  212. </httpHandlers>
  213. </httpHandlers><httpHandlers>
  214. <httpHandlers>
  215.    
  216. </httpHandlers>
  217. </httpHandlers><httpHandlers>
  218. <httpHandlers>
  219.    
  220. </httpHandlers>
  221. </httpHandlers><httpHandlers>
  222. <httpHandlers>
  223.    
  224. </httpHandlers>
  225. </httpHandlers>// 给用户控件的视图数据赋值。<httpHandlers>
  226. <httpHandlers>
  227.    
  228. </httpHandlers>
  229. </httpHandlers><httpHandlers>
  230. <httpHandlers>
  231.    
  232. </httpHandlers>
  233. </httpHandlers><httpHandlers>
  234. <httpHandlers>
  235.    
  236. </httpHandlers>
  237. </httpHandlers><httpHandlers>
  238. <httpHandlers>
  239.    
  240. </httpHandlers>
  241. </httpHandlers><httpHandlers>
  242. <httpHandlers>
  243.    
  244. </httpHandlers>
  245. </httpHandlers>DataMember member = ReflectionHelper.GetMemberByName(viewType, "Model", true);<httpHandlers>
  246. <httpHandlers>
  247.    
  248. </httpHandlers>
  249. </httpHandlers><httpHandlers>
  250. <httpHandlers>
  251.    
  252. </httpHandlers>
  253. </httpHandlers><httpHandlers>
  254. <httpHandlers>
  255.    
  256. </httpHandlers>
  257. </httpHandlers><httpHandlers>
  258. <httpHandlers>
  259.    
  260. </httpHandlers>
  261. </httpHandlers><httpHandlers>
  262. <httpHandlers>
  263.    
  264. </httpHandlers>
  265. </httpHandlers>member.SetValue(myctl, model);<httpHandlers>
  266. <httpHandlers>
  267.    
  268. </httpHandlers>
  269. </httpHandlers><httpHandlers>
  270. <httpHandlers>
  271.    
  272. </httpHandlers>
  273. </httpHandlers><httpHandlers>
  274. <httpHandlers>
  275.    
  276. </httpHandlers>
  277. </httpHandlers><httpHandlers>
  278. <httpHandlers>
  279.    
  280. </httpHandlers>
  281. </httpHandlers>}<httpHandlers>
  282. <httpHandlers>
  283.    
  284. </httpHandlers>
  285. </httpHandlers><httpHandlers>
  286. <httpHandlers>
  287.    
  288. </httpHandlers>
  289. </httpHandlers><httpHandlers>
  290. <httpHandlers>
  291.    
  292. </httpHandlers>
  293. </httpHandlers><httpHandlers>
  294. <httpHandlers>
  295.    
  296. </httpHandlers>
  297. </httpHandlers>else<httpHandlers>
  298. <httpHandlers>
  299.    
  300. </httpHandlers>
  301. </httpHandlers><httpHandlers>
  302. <httpHandlers>
  303.    
  304. </httpHandlers>
  305. </httpHandlers><httpHandlers>
  306. <httpHandlers>
  307.    
  308. </httpHandlers>
  309. </httpHandlers><httpHandlers>
  310. <httpHandlers>
  311.    
  312. </httpHandlers>
  313. </httpHandlers><httpHandlers>
  314. <httpHandlers>
  315.    
  316. </httpHandlers>
  317. </httpHandlers>throw new ArgumentException("参数model的类型与用户控件的参数类型不一致。");<httpHandlers>
  318. <httpHandlers>
  319.    
  320. </httpHandlers>
  321. </httpHandlers><httpHandlers>
  322. <httpHandlers>
  323.    
  324. </httpHandlers>
  325. </httpHandlers><httpHandlers>
  326. <httpHandlers>
  327.    
  328. </httpHandlers>
  329. </httpHandlers>}<httpHandlers>
  330. <httpHandlers>
  331.    
  332. </httpHandlers>
  333. </httpHandlers><httpHandlers>
  334. <httpHandlers>
  335.    
  336. </httpHandlers>
  337. </httpHandlers>}<httpHandlers>
  338. <httpHandlers>
  339.    
  340. </httpHandlers>
  341. </httpHandlers><httpHandlers>
  342. <httpHandlers>
  343.    
  344. </httpHandlers>
  345. </httpHandlers>// 将用户控件放在Page容器中。<httpHandlers>
  346. <httpHandlers>
  347.    
  348. </httpHandlers>
  349. </httpHandlers><httpHandlers>
  350. <httpHandlers>
  351.    
  352. </httpHandlers>
  353. </httpHandlers>page.Controls.Add(ctl);<httpHandlers>
  354. <httpHandlers>
  355.    
  356. </httpHandlers>
  357. </httpHandlers><httpHandlers>
  358. <httpHandlers>
  359.    
  360. </httpHandlers>
  361. </httpHandlers>StringWriter output = new StringWriter();<httpHandlers>
  362. <httpHandlers>
  363.    
  364. </httpHandlers>
  365. </httpHandlers><httpHandlers>
  366. <httpHandlers>
  367.    
  368. </httpHandlers>
  369. </httpHandlers>HtmlTextWriter write = new HtmlTextWriter(output, string.Empty);<httpHandlers>
  370. <httpHandlers>
  371.    
  372. </httpHandlers>
  373. </httpHandlers><httpHandlers>
  374. <httpHandlers>
  375.    
  376. </httpHandlers>
  377. </httpHandlers>page.RenderControl(write);<httpHandlers>
  378. <httpHandlers>
  379.    
  380. </httpHandlers>
  381. </httpHandlers><httpHandlers>
  382. <httpHandlers>
  383.    
  384. </httpHandlers>
  385. </httpHandlers>// 用下面的方法也可以的。<httpHandlers>
  386. <httpHandlers>
  387.    
  388. </httpHandlers>
  389. </httpHandlers><httpHandlers>
  390. <httpHandlers>
  391.    
  392. </httpHandlers>
  393. </httpHandlers>//HttpContext.Current.Server.Execute(page, output, false);<httpHandlers>
  394. <httpHandlers>
  395.    
  396. </httpHandlers>
  397. </httpHandlers><httpHandlers>
  398. <httpHandlers>
  399.    
  400. </httpHandlers>
  401. </httpHandlers>return output.ToString();<httpHandlers>
  402. <httpHandlers>
  403.    
  404. </httpHandlers>
  405. </httpHandlers>}
复制代码
HTML分块输出

注意哦,前面介绍的2个Render方法的可见性都是public,这样设计的想法是让框架提供对外生成HTML的能力,或许有些用户有这样的需求。另一方面,或许还有些用户打算在Action的执行过程中,将原来较大的HTML页面分块输出给客户端。BigPipe就使用了这种想法:整个请求不用等到全部数据获取成功后一次性输出,而是将页面按业务逻辑拆分,并在获取到相应的数据后,立即向客户端输出部分片段。
其实HTML分块输出在ASP.NET中并不是什么新的技术,而是在ASP.NET一出现时就已经存在了,那就是在输出的过程中不断调用Response.Flush();
由于MyMVC将生成HTML做为一种基础功能,因此在MyMVC中,只要您调用Response.Flush();便可以方便地实现分块输出。不过,为了让调用更简单,我提供了二个辅助方法来简化这个过程。
在PageExecutor类型中的ResponseWrite方法:
  1. /// /// 用指定的Page以及视图数据呈现结果,/// 然后将产生的HTML代码写入HttpContext.Current.Response/// 用户控件应从MyPageView<T>继承/// /// Page的虚拟路径/// 视图数据/// 是否需要在输出html后调用Response.Flush()public static void ResponseWrite(string pageVirtualPath, object model, bool flush){<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>HttpContext context = HttpContext.Current;<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers>if( context == null )<httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers><httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers>return;<httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers>if( string.IsNullOrEmpty(context.Response.ContentType) )<httpHandlers>
  22. <httpHandlers>
  23.    
  24. </httpHandlers>
  25. </httpHandlers><httpHandlers>
  26. <httpHandlers>
  27.    
  28. </httpHandlers>
  29. </httpHandlers>context.Response.ContentType = "text/html";<httpHandlers>
  30. <httpHandlers>
  31.    
  32. </httpHandlers>
  33. </httpHandlers>string html = Render(context, pageVirtualPath, model);<httpHandlers>
  34. <httpHandlers>
  35.    
  36. </httpHandlers>
  37. </httpHandlers>context.Response.Write(html);<httpHandlers>
  38. <httpHandlers>
  39.    
  40. </httpHandlers>
  41. </httpHandlers>if( flush )<httpHandlers>
  42. <httpHandlers>
  43.    
  44. </httpHandlers>
  45. </httpHandlers><httpHandlers>
  46. <httpHandlers>
  47.    
  48. </httpHandlers>
  49. </httpHandlers>context.Response.Flush();}
复制代码
在UcExecutor类型中的ResponseWrite方法:
  1. /// /// 用指定的用户控件以及视图数据呈现结果,/// 然后将产生的HTML代码写入HttpContext.Current.Response/// 用户控件应从MyUserControlView<T>继承/// /// 用户控件的虚拟路径/// 视图数据/// 是否需要在输出html后调用Response.Flush()public static void ResponseWrite(string ucVirtualPath, object model, bool flush){<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>HttpContext context = HttpContext.Current;<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers>if( context == null )<httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers><httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers>return;<httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers>if( string.IsNullOrEmpty(context.Response.ContentType) )<httpHandlers>
  22. <httpHandlers>
  23.    
  24. </httpHandlers>
  25. </httpHandlers><httpHandlers>
  26. <httpHandlers>
  27.    
  28. </httpHandlers>
  29. </httpHandlers>context.Response.ContentType = "text/html";<httpHandlers>
  30. <httpHandlers>
  31.    
  32. </httpHandlers>
  33. </httpHandlers>string html = Render(ucVirtualPath, model);<httpHandlers>
  34. <httpHandlers>
  35.    
  36. </httpHandlers>
  37. </httpHandlers>context.Response.Write(html);<httpHandlers>
  38. <httpHandlers>
  39.    
  40. </httpHandlers>
  41. </httpHandlers>if( flush )<httpHandlers>
  42. <httpHandlers>
  43.    
  44. </httpHandlers>
  45. </httpHandlers><httpHandlers>
  46. <httpHandlers>
  47.    
  48. </httpHandlers>
  49. </httpHandlers>context.Response.Flush();}
复制代码
注意:由于这二个方法在内部使用了HttpContext.Current,因此如果在Action中调用它们,会造成Action不能支持单元测试。
关于单元测试的支持

提到MVC思想,我想就不得不谈单元测试了。
因为MVC的主要思想还是想把这三个字目对应的事物分开,以方便开发与测试。这里面,我认为尤其是View与Controller的分离最为重要,因为有UI的地方比较难测试,反过来,如果没有UI的东西就比较容易测试了。
不过,在ASP.NET中,影响单元测试的不仅仅只是UI元素,还有HttpContxt, HttpRequest, HttpResponse这之类的核心对象。比如:即使我们将Controller放在类库项目中实现,但在Action中还在访问QueryString,Form,甚至发起重定向的请求,你说这样的代码如何测试。
我认为判断一个方法是否可支持单元测试有一个简单的办法:写个控制台的程序去调用它,看它能否正常运行。
通常,用户的输入数据主要有三个来源:QueryString, Form, Cookie。而且前二者居多,Cookie则多用于保存用户偏好设置。因此,在MyMVC中,可以让Action不再去直接访问QueryString, Form,替代的方式是:将要读取的名字做为C#方法的参数名明确指出。这样,Actioin中的代码就远离了QueryString, Form。至于Cookie的访问,MyMVC则提供一个辅助类来支持访问:
  1. /// /// 读写Cookie的辅助工具类。这个类对测试环境仍然有效。/// public static class CookieHelper{<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>[ThreadStatic]<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers>private static HttpCookieCollection s_cookies;<httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers>private static HttpCookieCollection TestCookies<httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers>{<httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers><httpHandlers>
  22. <httpHandlers>
  23.    
  24. </httpHandlers>
  25. </httpHandlers>get<httpHandlers>
  26. <httpHandlers>
  27.    
  28. </httpHandlers>
  29. </httpHandlers><httpHandlers>
  30. <httpHandlers>
  31.    
  32. </httpHandlers>
  33. </httpHandlers>{<httpHandlers>
  34. <httpHandlers>
  35.    
  36. </httpHandlers>
  37. </httpHandlers><httpHandlers>
  38. <httpHandlers>
  39.    
  40. </httpHandlers>
  41. </httpHandlers><httpHandlers>
  42. <httpHandlers>
  43.    
  44. </httpHandlers>
  45. </httpHandlers>if( TestEnvironment.IsTestEnvironment == false )<httpHandlers>
  46. <httpHandlers>
  47.    
  48. </httpHandlers>
  49. </httpHandlers><httpHandlers>
  50. <httpHandlers>
  51.    
  52. </httpHandlers>
  53. </httpHandlers><httpHandlers>
  54. <httpHandlers>
  55.    
  56. </httpHandlers>
  57. </httpHandlers><httpHandlers>
  58. <httpHandlers>
  59.    
  60. </httpHandlers>
  61. </httpHandlers>throw new InvalidOperationException();<httpHandlers>
  62. <httpHandlers>
  63.    
  64. </httpHandlers>
  65. </httpHandlers><httpHandlers>
  66. <httpHandlers>
  67.    
  68. </httpHandlers>
  69. </httpHandlers><httpHandlers>
  70. <httpHandlers>
  71.    
  72. </httpHandlers>
  73. </httpHandlers>if( s_cookies == null )<httpHandlers>
  74. <httpHandlers>
  75.    
  76. </httpHandlers>
  77. </httpHandlers>// 测试环境不考虑线程安全问题。<httpHandlers>
  78. <httpHandlers>
  79.    
  80. </httpHandlers>
  81. </httpHandlers><httpHandlers>
  82. <httpHandlers>
  83.    
  84. </httpHandlers>
  85. </httpHandlers><httpHandlers>
  86. <httpHandlers>
  87.    
  88. </httpHandlers>
  89. </httpHandlers><httpHandlers>
  90. <httpHandlers>
  91.    
  92. </httpHandlers>
  93. </httpHandlers>s_cookies = new HttpCookieCollection();<httpHandlers>
  94. <httpHandlers>
  95.    
  96. </httpHandlers>
  97. </httpHandlers><httpHandlers>
  98. <httpHandlers>
  99.    
  100. </httpHandlers>
  101. </httpHandlers><httpHandlers>
  102. <httpHandlers>
  103.    
  104. </httpHandlers>
  105. </httpHandlers>return s_cookies;<httpHandlers>
  106. <httpHandlers>
  107.    
  108. </httpHandlers>
  109. </httpHandlers><httpHandlers>
  110. <httpHandlers>
  111.    
  112. </httpHandlers>
  113. </httpHandlers>}<httpHandlers>
  114. <httpHandlers>
  115.    
  116. </httpHandlers>
  117. </httpHandlers>}<httpHandlers>
  118. <httpHandlers>
  119.    
  120. </httpHandlers>
  121. </httpHandlers><httpHandlers>
  122. <httpHandlers>
  123.    
  124. </httpHandlers>
  125. </httpHandlers>///<httpHandlers>
  126. <httpHandlers>
  127.    
  128. </httpHandlers>
  129. </httpHandlers> /// 从Request中获取一个Cookie对象<httpHandlers>
  130. <httpHandlers>
  131.    
  132. </httpHandlers>
  133. </httpHandlers>///<httpHandlers>
  134. <httpHandlers>
  135.    
  136. </httpHandlers>
  137. </httpHandlers> ///<httpHandlers>
  138. <httpHandlers>
  139.    
  140. </httpHandlers>
  141. </httpHandlers> ///<httpHandlers>
  142. <httpHandlers>
  143.    
  144. </httpHandlers>
  145. </httpHandlers> public static HttpCookie GetCookie(string key)<httpHandlers>
  146. <httpHandlers>
  147.    
  148. </httpHandlers>
  149. </httpHandlers>{<httpHandlers>
  150. <httpHandlers>
  151.    
  152. </httpHandlers>
  153. </httpHandlers><httpHandlers>
  154. <httpHandlers>
  155.    
  156. </httpHandlers>
  157. </httpHandlers>if( TestEnvironment.IsTestEnvironment )<httpHandlers>
  158. <httpHandlers>
  159.    
  160. </httpHandlers>
  161. </httpHandlers><httpHandlers>
  162. <httpHandlers>
  163.    
  164. </httpHandlers>
  165. </httpHandlers><httpHandlers>
  166. <httpHandlers>
  167.    
  168. </httpHandlers>
  169. </httpHandlers> return TestCookies[key];<httpHandlers>
  170. <httpHandlers>
  171.    
  172. </httpHandlers>
  173. </httpHandlers><httpHandlers>
  174. <httpHandlers>
  175.    
  176. </httpHandlers>
  177. </httpHandlers><httpHandlers>
  178. <httpHandlers>
  179.    
  180. </httpHandlers>
  181. </httpHandlers><httpHandlers>
  182. <httpHandlers>
  183.    
  184. </httpHandlers>
  185. </httpHandlers>return HttpContext.Current.Request.Cookies[key];<httpHandlers>
  186. <httpHandlers>
  187.    
  188. </httpHandlers>
  189. </httpHandlers>}<httpHandlers>
  190. <httpHandlers>
  191.    
  192. </httpHandlers>
  193. </httpHandlers>///<httpHandlers>
  194. <httpHandlers>
  195.    
  196. </httpHandlers>
  197. </httpHandlers> /// 从Request中获取一个Cookie对象的值,如果不存在,则返回null<httpHandlers>
  198. <httpHandlers>
  199.    
  200. </httpHandlers>
  201. </httpHandlers>///<httpHandlers>
  202. <httpHandlers>
  203.    
  204. </httpHandlers>
  205. </httpHandlers> ///<httpHandlers>
  206. <httpHandlers>
  207.    
  208. </httpHandlers>
  209. </httpHandlers> ///<httpHandlers>
  210. <httpHandlers>
  211.    
  212. </httpHandlers>
  213. </httpHandlers> public static string GetCookieValue(string key)<httpHandlers>
  214. <httpHandlers>
  215.    
  216. </httpHandlers>
  217. </httpHandlers>{<httpHandlers>
  218. <httpHandlers>
  219.    
  220. </httpHandlers>
  221. </httpHandlers><httpHandlers>
  222. <httpHandlers>
  223.    
  224. </httpHandlers>
  225. </httpHandlers>HttpCookie cookie = GetCookie(key);<httpHandlers>
  226. <httpHandlers>
  227.    
  228. </httpHandlers>
  229. </httpHandlers><httpHandlers>
  230. <httpHandlers>
  231.    
  232. </httpHandlers>
  233. </httpHandlers>if( cookie == null )<httpHandlers>
  234. <httpHandlers>
  235.    
  236. </httpHandlers>
  237. </httpHandlers><httpHandlers>
  238. <httpHandlers>
  239.    
  240. </httpHandlers>
  241. </httpHandlers><httpHandlers>
  242. <httpHandlers>
  243.    
  244. </httpHandlers>
  245. </httpHandlers>return null;<httpHandlers>
  246. <httpHandlers>
  247.    
  248. </httpHandlers>
  249. </httpHandlers><httpHandlers>
  250. <httpHandlers>
  251.    
  252. </httpHandlers>
  253. </httpHandlers>else<httpHandlers>
  254. <httpHandlers>
  255.    
  256. </httpHandlers>
  257. </httpHandlers><httpHandlers>
  258. <httpHandlers>
  259.    
  260. </httpHandlers>
  261. </httpHandlers><httpHandlers>
  262. <httpHandlers>
  263.    
  264. </httpHandlers>
  265. </httpHandlers>return cookie.Value;<httpHandlers>
  266. <httpHandlers>
  267.    
  268. </httpHandlers>
  269. </httpHandlers>}<httpHandlers>
  270. <httpHandlers>
  271.    
  272. </httpHandlers>
  273. </httpHandlers>///<httpHandlers>
  274. <httpHandlers>
  275.    
  276. </httpHandlers>
  277. </httpHandlers> /// 将一个Cookie对应写入到Response中<httpHandlers>
  278. <httpHandlers>
  279.    
  280. </httpHandlers>
  281. </httpHandlers>///<httpHandlers>
  282. <httpHandlers>
  283.    
  284. </httpHandlers>
  285. </httpHandlers> ///<httpHandlers>
  286. <httpHandlers>
  287.    
  288. </httpHandlers>
  289. </httpHandlers> public static void SetCookie(HttpCookie cookie)<httpHandlers>
  290. <httpHandlers>
  291.    
  292. </httpHandlers>
  293. </httpHandlers>{<httpHandlers>
  294. <httpHandlers>
  295.    
  296. </httpHandlers>
  297. </httpHandlers><httpHandlers>
  298. <httpHandlers>
  299.    
  300. </httpHandlers>
  301. </httpHandlers>if( TestEnvironment.IsTestEnvironment )<httpHandlers>
  302. <httpHandlers>
  303.    
  304. </httpHandlers>
  305. </httpHandlers><httpHandlers>
  306. <httpHandlers>
  307.    
  308. </httpHandlers>
  309. </httpHandlers><httpHandlers>
  310. <httpHandlers>
  311.    
  312. </httpHandlers>
  313. </httpHandlers> TestCookies.Set(cookie);<httpHandlers>
  314. <httpHandlers>
  315.    
  316. </httpHandlers>
  317. </httpHandlers><httpHandlers>
  318. <httpHandlers>
  319.    
  320. </httpHandlers>
  321. </httpHandlers><httpHandlers>
  322. <httpHandlers>
  323.    
  324. </httpHandlers>
  325. </httpHandlers><httpHandlers>
  326. <httpHandlers>
  327.    
  328. </httpHandlers>
  329. </httpHandlers><httpHandlers>
  330. <httpHandlers>
  331.    
  332. </httpHandlers>
  333. </httpHandlers>else<httpHandlers>
  334. <httpHandlers>
  335.    
  336. </httpHandlers>
  337. </httpHandlers><httpHandlers>
  338. <httpHandlers>
  339.    
  340. </httpHandlers>
  341. </httpHandlers><httpHandlers>
  342. <httpHandlers>
  343.    
  344. </httpHandlers>
  345. </httpHandlers>HttpContext.Current.Response.Cookies.Set(cookie);<httpHandlers>
  346. <httpHandlers>
  347.    
  348. </httpHandlers>
  349. </httpHandlers>}<httpHandlers>
  350. <httpHandlers>
  351.    
  352. </httpHandlers>
  353. </httpHandlers>///<httpHandlers>
  354. <httpHandlers>
  355.    
  356. </httpHandlers>
  357. </httpHandlers> /// 将一个Cookie对应写入到Response中<httpHandlers>
  358. <httpHandlers>
  359.    
  360. </httpHandlers>
  361. </httpHandlers>///<httpHandlers>
  362. <httpHandlers>
  363.    
  364. </httpHandlers>
  365. </httpHandlers> ///<httpHandlers>
  366. <httpHandlers>
  367.    
  368. </httpHandlers>
  369. </httpHandlers> public static void AddCookie(HttpCookie cookie)<httpHandlers>
  370. <httpHandlers>
  371.    
  372. </httpHandlers>
  373. </httpHandlers>{<httpHandlers>
  374. <httpHandlers>
  375.    
  376. </httpHandlers>
  377. </httpHandlers><httpHandlers>
  378. <httpHandlers>
  379.    
  380. </httpHandlers>
  381. </httpHandlers>if( TestEnvironment.IsTestEnvironment )<httpHandlers>
  382. <httpHandlers>
  383.    
  384. </httpHandlers>
  385. </httpHandlers><httpHandlers>
  386. <httpHandlers>
  387.    
  388. </httpHandlers>
  389. </httpHandlers><httpHandlers>
  390. <httpHandlers>
  391.    
  392. </httpHandlers>
  393. </httpHandlers> TestCookies.Add(cookie);<httpHandlers>
  394. <httpHandlers>
  395.    
  396. </httpHandlers>
  397. </httpHandlers><httpHandlers>
  398. <httpHandlers>
  399.    
  400. </httpHandlers>
  401. </httpHandlers>else<httpHandlers>
  402. <httpHandlers>
  403.    
  404. </httpHandlers>
  405. </httpHandlers><httpHandlers>
  406. <httpHandlers>
  407.    
  408. </httpHandlers>
  409. </httpHandlers><httpHandlers>
  410. <httpHandlers>
  411.    
  412. </httpHandlers>
  413. </httpHandlers>HttpContext.Current.Response.Cookies.Add(cookie);<httpHandlers>
  414. <httpHandlers>
  415.    
  416. </httpHandlers>
  417. </httpHandlers>}<httpHandlers>
  418. <httpHandlers>
  419.    
  420. </httpHandlers>
  421. </httpHandlers>///<httpHandlers>
  422. <httpHandlers>
  423.    
  424. </httpHandlers>
  425. </httpHandlers> /// 清除所有写入的Cookie<httpHandlers>
  426. <httpHandlers>
  427.    
  428. </httpHandlers>
  429. </httpHandlers> ///<httpHandlers>
  430. <httpHandlers>
  431.    
  432. </httpHandlers>
  433. </httpHandlers> public static void ClearCookie()<httpHandlers>
  434. <httpHandlers>
  435.    
  436. </httpHandlers>
  437. </httpHandlers>{<httpHandlers>
  438. <httpHandlers>
  439.    
  440. </httpHandlers>
  441. </httpHandlers><httpHandlers>
  442. <httpHandlers>
  443.    
  444. </httpHandlers>
  445. </httpHandlers>if( TestEnvironment.IsTestEnvironment )<httpHandlers>
  446. <httpHandlers>
  447.    
  448. </httpHandlers>
  449. </httpHandlers><httpHandlers>
  450. <httpHandlers>
  451.    
  452. </httpHandlers>
  453. </httpHandlers><httpHandlers>
  454. <httpHandlers>
  455.    
  456. </httpHandlers>
  457. </httpHandlers>TestCookies.Clear();<httpHandlers>
  458. <httpHandlers>
  459.    
  460. </httpHandlers>
  461. </httpHandlers><httpHandlers>
  462. <httpHandlers>
  463.    
  464. </httpHandlers>
  465. </httpHandlers>else<httpHandlers>
  466. <httpHandlers>
  467.    
  468. </httpHandlers>
  469. </httpHandlers><httpHandlers>
  470. <httpHandlers>
  471.    
  472. </httpHandlers>
  473. </httpHandlers><httpHandlers>
  474. <httpHandlers>
  475.    
  476. </httpHandlers>
  477. </httpHandlers>HttpContext.Current.Response.Cookies.Clear();<httpHandlers>
  478. <httpHandlers>
  479.    
  480. </httpHandlers>
  481. </httpHandlers>}<httpHandlers>
  482. <httpHandlers>
  483.    
  484. </httpHandlers>
  485. </httpHandlers>///<httpHandlers>
  486. <httpHandlers>
  487.    
  488. </httpHandlers>
  489. </httpHandlers> /// 删除指定名称的Cookie<httpHandlers>
  490. <httpHandlers>
  491.    
  492. </httpHandlers>
  493. </httpHandlers>///<httpHandlers>
  494. <httpHandlers>
  495.    
  496. </httpHandlers>
  497. </httpHandlers> ///<httpHandlers>
  498. <httpHandlers>
  499.    
  500. </httpHandlers>
  501. </httpHandlers> public static void RemoveCookie(string key)<httpHandlers>
  502. <httpHandlers>
  503.    
  504. </httpHandlers>
  505. </httpHandlers>{<httpHandlers>
  506. <httpHandlers>
  507.    
  508. </httpHandlers>
  509. </httpHandlers><httpHandlers>
  510. <httpHandlers>
  511.    
  512. </httpHandlers>
  513. </httpHandlers>if( TestEnvironment.IsTestEnvironment )<httpHandlers>
  514. <httpHandlers>
  515.    
  516. </httpHandlers>
  517. </httpHandlers><httpHandlers>
  518. <httpHandlers>
  519.    
  520. </httpHandlers>
  521. </httpHandlers><httpHandlers>
  522. <httpHandlers>
  523.    
  524. </httpHandlers>
  525. </httpHandlers> TestCookies.Remove(key);<httpHandlers>
  526. <httpHandlers>
  527.    
  528. </httpHandlers>
  529. </httpHandlers><httpHandlers>
  530. <httpHandlers>
  531.    
  532. </httpHandlers>
  533. </httpHandlers>else<httpHandlers>
  534. <httpHandlers>
  535.    
  536. </httpHandlers>
  537. </httpHandlers><httpHandlers>
  538. <httpHandlers>
  539.    
  540. </httpHandlers>
  541. </httpHandlers><httpHandlers>
  542. <httpHandlers>
  543.    
  544. </httpHandlers>
  545. </httpHandlers>HttpContext.Current.Response.Cookies.Remove(key);<httpHandlers>
  546. <httpHandlers>
  547.    
  548. </httpHandlers>
  549. </httpHandlers>}}
复制代码
重定向也是常见的需求。MyMVC则是通过提供RedirectResult来支持的:
  1. /// /// 表示一个重定向的结果/// public sealed class RedirectResult : IActionResult{<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>public string Url { get; private set; }<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers>public RedirectResult(string url)<httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers>{<httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers><httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers>if( string.IsNullOrEmpty(url) )<httpHandlers>
  22. <httpHandlers>
  23.    
  24. </httpHandlers>
  25. </httpHandlers><httpHandlers>
  26. <httpHandlers>
  27.    
  28. </httpHandlers>
  29. </httpHandlers><httpHandlers>
  30. <httpHandlers>
  31.    
  32. </httpHandlers>
  33. </httpHandlers>throw new ArgumentNullException("url");<httpHandlers>
  34. <httpHandlers>
  35.    
  36. </httpHandlers>
  37. </httpHandlers><httpHandlers>
  38. <httpHandlers>
  39.    
  40. </httpHandlers>
  41. </httpHandlers>Url = url;<httpHandlers>
  42. <httpHandlers>
  43.    
  44. </httpHandlers>
  45. </httpHandlers>}<httpHandlers>
  46. <httpHandlers>
  47.    
  48. </httpHandlers>
  49. </httpHandlers>void IActionResult.Ouput(HttpContext context)<httpHandlers>
  50. <httpHandlers>
  51.    
  52. </httpHandlers>
  53. </httpHandlers>{<httpHandlers>
  54. <httpHandlers>
  55.    
  56. </httpHandlers>
  57. </httpHandlers><httpHandlers>
  58. <httpHandlers>
  59.    
  60. </httpHandlers>
  61. </httpHandlers>context.Response.Redirect(Url, true);<httpHandlers>
  62. <httpHandlers>
  63.    
  64. </httpHandlers>
  65. </httpHandlers>}}
复制代码
说明:Ouput方法由框架调用,不影响Action的单元测试。
示例代码:
  1. [Action]public object Delete(int id){<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>BllFactory.GetCategoryBLL().Delete(id);<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers>return new RedirectResult("/Pages/Categories.aspx");}
复制代码
在ASP.NET项目开发过程中,还有一类需求较为常见,那就是:访问一些当前环境变量。
MyMVC则是通过以下二个类型来处理的。
  1. public static class TestEnvironment{<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>///<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers> /// 当前运行环境是否为测试环境(非ASP.NET环境)<httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers>///<httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers> internal static readonly bool IsTestEnvironment = (HttpRuntime.AppDomainAppId == null);<httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers>[ThreadStatic]<httpHandlers>
  22. <httpHandlers>
  23.    
  24. </httpHandlers>
  25. </httpHandlers>private static Hashtable s_ContextInfo;<httpHandlers>
  26. <httpHandlers>
  27.    
  28. </httpHandlers>
  29. </httpHandlers>private static Hashtable ContextInfo<httpHandlers>
  30. <httpHandlers>
  31.    
  32. </httpHandlers>
  33. </httpHandlers>{<httpHandlers>
  34. <httpHandlers>
  35.    
  36. </httpHandlers>
  37. </httpHandlers><httpHandlers>
  38. <httpHandlers>
  39.    
  40. </httpHandlers>
  41. </httpHandlers>get<httpHandlers>
  42. <httpHandlers>
  43.    
  44. </httpHandlers>
  45. </httpHandlers><httpHandlers>
  46. <httpHandlers>
  47.    
  48. </httpHandlers>
  49. </httpHandlers>{<httpHandlers>
  50. <httpHandlers>
  51.    
  52. </httpHandlers>
  53. </httpHandlers><httpHandlers>
  54. <httpHandlers>
  55.    
  56. </httpHandlers>
  57. </httpHandlers><httpHandlers>
  58. <httpHandlers>
  59.    
  60. </httpHandlers>
  61. </httpHandlers>if( TestEnvironment.IsTestEnvironment == false )<httpHandlers>
  62. <httpHandlers>
  63.    
  64. </httpHandlers>
  65. </httpHandlers><httpHandlers>
  66. <httpHandlers>
  67.    
  68. </httpHandlers>
  69. </httpHandlers><httpHandlers>
  70. <httpHandlers>
  71.    
  72. </httpHandlers>
  73. </httpHandlers><httpHandlers>
  74. <httpHandlers>
  75.    
  76. </httpHandlers>
  77. </httpHandlers>throw new InvalidOperationException("只有测试代码才允许执行这个调用。");<httpHandlers>
  78. <httpHandlers>
  79.    
  80. </httpHandlers>
  81. </httpHandlers><httpHandlers>
  82. <httpHandlers>
  83.    
  84. </httpHandlers>
  85. </httpHandlers><httpHandlers>
  86. <httpHandlers>
  87.    
  88. </httpHandlers>
  89. </httpHandlers>if( s_ContextInfo == null )<httpHandlers>
  90. <httpHandlers>
  91.    
  92. </httpHandlers>
  93. </httpHandlers>// 测试环境不考虑线程安全问题。<httpHandlers>
  94. <httpHandlers>
  95.    
  96. </httpHandlers>
  97. </httpHandlers><httpHandlers>
  98. <httpHandlers>
  99.    
  100. </httpHandlers>
  101. </httpHandlers><httpHandlers>
  102. <httpHandlers>
  103.    
  104. </httpHandlers>
  105. </httpHandlers><httpHandlers>
  106. <httpHandlers>
  107.    
  108. </httpHandlers>
  109. </httpHandlers>s_ContextInfo = new Hashtable(100, StringComparer.Ordinal);<httpHandlers>
  110. <httpHandlers>
  111.    
  112. </httpHandlers>
  113. </httpHandlers><httpHandlers>
  114. <httpHandlers>
  115.    
  116. </httpHandlers>
  117. </httpHandlers><httpHandlers>
  118. <httpHandlers>
  119.    
  120. </httpHandlers>
  121. </httpHandlers>return s_ContextInfo;<httpHandlers>
  122. <httpHandlers>
  123.    
  124. </httpHandlers>
  125. </httpHandlers><httpHandlers>
  126. <httpHandlers>
  127.    
  128. </httpHandlers>
  129. </httpHandlers>}<httpHandlers>
  130. <httpHandlers>
  131.    
  132. </httpHandlers>
  133. </httpHandlers>}<httpHandlers>
  134. <httpHandlers>
  135.    
  136. </httpHandlers>
  137. </httpHandlers>public static object GetValue(string key)<httpHandlers>
  138. <httpHandlers>
  139.    
  140. </httpHandlers>
  141. </httpHandlers>{<httpHandlers>
  142. <httpHandlers>
  143.    
  144. </httpHandlers>
  145. </httpHandlers><httpHandlers>
  146. <httpHandlers>
  147.    
  148. </httpHandlers>
  149. </httpHandlers>object val = ContextInfo[key];<httpHandlers>
  150. <httpHandlers>
  151.    
  152. </httpHandlers>
  153. </httpHandlers><httpHandlers>
  154. <httpHandlers>
  155.    
  156. </httpHandlers>
  157. </httpHandlers>if( val == null )<httpHandlers>
  158. <httpHandlers>
  159.    
  160. </httpHandlers>
  161. </httpHandlers><httpHandlers>
  162. <httpHandlers>
  163.    
  164. </httpHandlers>
  165. </httpHandlers><httpHandlers>
  166. <httpHandlers>
  167.    
  168. </httpHandlers>
  169. </httpHandlers>throw new InvalidOperationException("您忘记了给测试环境赋值了。参数名:" + key);<httpHandlers>
  170. <httpHandlers>
  171.    
  172. </httpHandlers>
  173. </httpHandlers><httpHandlers>
  174. <httpHandlers>
  175.    
  176. </httpHandlers>
  177. </httpHandlers>return val;<httpHandlers>
  178. <httpHandlers>
  179.    
  180. </httpHandlers>
  181. </httpHandlers>}<httpHandlers>
  182. <httpHandlers>
  183.    
  184. </httpHandlers>
  185. </httpHandlers>public static void SetValue(string key, object val)<httpHandlers>
  186. <httpHandlers>
  187.    
  188. </httpHandlers>
  189. </httpHandlers>{<httpHandlers>
  190. <httpHandlers>
  191.    
  192. </httpHandlers>
  193. </httpHandlers><httpHandlers>
  194. <httpHandlers>
  195.    
  196. </httpHandlers>
  197. </httpHandlers>ContextInfo[key] = val;<httpHandlers>
  198. <httpHandlers>
  199.    
  200. </httpHandlers>
  201. </httpHandlers>}<httpHandlers>
  202. <httpHandlers>
  203.    
  204. </httpHandlers>
  205. </httpHandlers>public static void ClearTestEnvironmentInfo()<httpHandlers>
  206. <httpHandlers>
  207.    
  208. </httpHandlers>
  209. </httpHandlers>{<httpHandlers>
  210. <httpHandlers>
  211.    
  212. </httpHandlers>
  213. </httpHandlers><httpHandlers>
  214. <httpHandlers>
  215.    
  216. </httpHandlers>
  217. </httpHandlers>ContextInfo.Clear();<httpHandlers>
  218. <httpHandlers>
  219.    
  220. </httpHandlers>
  221. </httpHandlers><httpHandlers>
  222. <httpHandlers>
  223.    
  224. </httpHandlers>
  225. </httpHandlers>CookieHelper.ClearCookie();<httpHandlers>
  226. <httpHandlers>
  227.    
  228. </httpHandlers>
  229. </httpHandlers>}}/// /// 用于访问当前请求上下文的工具类。这个类对测试环境仍然有效。/// public static class HttpContextHelper{<httpHandlers>
  230. <httpHandlers>
  231.    
  232. </httpHandlers>
  233. </httpHandlers>// 为了能让代码支持测试环境<httpHandlers>
  234. <httpHandlers>
  235.    
  236. </httpHandlers>
  237. </httpHandlers>// 会判断 TestEnvironment.IsTestEnvironment<httpHandlers>
  238. <httpHandlers>
  239.    
  240. </httpHandlers>
  241. </httpHandlers>// 如果在ASP.NET环境中运行,则直接返回HttpRuntime或者HttpContext.Current中的参数值<httpHandlers>
  242. <httpHandlers>
  243.    
  244. </httpHandlers>
  245. </httpHandlers>// 如果是在测试环境中运行,则使用另一个静态变量来维护所有需要访问的状态。<httpHandlers>
  246. <httpHandlers>
  247.    
  248. </httpHandlers>
  249. </httpHandlers><httpHandlers>
  250. <httpHandlers>
  251.    
  252. </httpHandlers>
  253. </httpHandlers>// 在测试前,需要先给相应的参数赋值。<httpHandlers>
  254. <httpHandlers>
  255.    
  256. </httpHandlers>
  257. </httpHandlers>// 测试完成后可调用TestEnvironment.ClearTestEnvironmentInfo()清除临时环境。<httpHandlers>
  258. <httpHandlers>
  259.    
  260. </httpHandlers>
  261. </httpHandlers>///<httpHandlers>
  262. <httpHandlers>
  263.    
  264. </httpHandlers>
  265. </httpHandlers> /// return HttpRuntime.AppDomainAppPath;<httpHandlers>
  266. <httpHandlers>
  267.    
  268. </httpHandlers>
  269. </httpHandlers>///<httpHandlers>
  270. <httpHandlers>
  271.    
  272. </httpHandlers>
  273. </httpHandlers> public static string AppRootPath<httpHandlers>
  274. <httpHandlers>
  275.    
  276. </httpHandlers>
  277. </httpHandlers>{<httpHandlers>
  278. <httpHandlers>
  279.    
  280. </httpHandlers>
  281. </httpHandlers><httpHandlers>
  282. <httpHandlers>
  283.    
  284. </httpHandlers>
  285. </httpHandlers>get<httpHandlers>
  286. <httpHandlers>
  287.    
  288. </httpHandlers>
  289. </httpHandlers><httpHandlers>
  290. <httpHandlers>
  291.    
  292. </httpHandlers>
  293. </httpHandlers>{<httpHandlers>
  294. <httpHandlers>
  295.    
  296. </httpHandlers>
  297. </httpHandlers><httpHandlers>
  298. <httpHandlers>
  299.    
  300. </httpHandlers>
  301. </httpHandlers><httpHandlers>
  302. <httpHandlers>
  303.    
  304. </httpHandlers>
  305. </httpHandlers>if( TestEnvironment.IsTestEnvironment )<httpHandlers>
  306. <httpHandlers>
  307.    
  308. </httpHandlers>
  309. </httpHandlers><httpHandlers>
  310. <httpHandlers>
  311.    
  312. </httpHandlers>
  313. </httpHandlers><httpHandlers>
  314. <httpHandlers>
  315.    
  316. </httpHandlers>
  317. </httpHandlers><httpHandlers>
  318. <httpHandlers>
  319.    
  320. </httpHandlers>
  321. </httpHandlers>return TestEnvironment.GetValue("AppDomainAppPath") as string;<httpHandlers>
  322. <httpHandlers>
  323.    
  324. </httpHandlers>
  325. </httpHandlers><httpHandlers>
  326. <httpHandlers>
  327.    
  328. </httpHandlers>
  329. </httpHandlers><httpHandlers>
  330. <httpHandlers>
  331.    
  332. </httpHandlers>
  333. </httpHandlers>return HttpRuntime.AppDomainAppPath;<httpHandlers>
  334. <httpHandlers>
  335.    
  336. </httpHandlers>
  337. </httpHandlers><httpHandlers>
  338. <httpHandlers>
  339.    
  340. </httpHandlers>
  341. </httpHandlers>}<httpHandlers>
  342. <httpHandlers>
  343.    
  344. </httpHandlers>
  345. </httpHandlers><httpHandlers>
  346. <httpHandlers>
  347.    
  348. </httpHandlers>
  349. </httpHandlers>set<httpHandlers>
  350. <httpHandlers>
  351.    
  352. </httpHandlers>
  353. </httpHandlers><httpHandlers>
  354. <httpHandlers>
  355.    
  356. </httpHandlers>
  357. </httpHandlers>{<httpHandlers>
  358. <httpHandlers>
  359.    
  360. </httpHandlers>
  361. </httpHandlers><httpHandlers>
  362. <httpHandlers>
  363.    
  364. </httpHandlers>
  365. </httpHandlers><httpHandlers>
  366. <httpHandlers>
  367.    
  368. </httpHandlers>
  369. </httpHandlers>TestEnvironment.SetValue("AppDomainAppPath", value);<httpHandlers>
  370. <httpHandlers>
  371.    
  372. </httpHandlers>
  373. </httpHandlers><httpHandlers>
  374. <httpHandlers>
  375.    
  376. </httpHandlers>
  377. </httpHandlers>}<httpHandlers>
  378. <httpHandlers>
  379.    
  380. </httpHandlers>
  381. </httpHandlers>}<httpHandlers>
  382. <httpHandlers>
  383.    
  384. </httpHandlers>
  385. </httpHandlers>///<httpHandlers>
  386. <httpHandlers>
  387.    
  388. </httpHandlers>
  389. </httpHandlers> /// return HttpContext.Current.Request.FilePath;<httpHandlers>
  390. <httpHandlers>
  391.    
  392. </httpHandlers>
  393. </httpHandlers>///<httpHandlers>
  394. <httpHandlers>
  395.    
  396. </httpHandlers>
  397. </httpHandlers> public static string RequestFilePath<httpHandlers>
  398. <httpHandlers>
  399.    
  400. </httpHandlers>
  401. </httpHandlers>{<httpHandlers>
  402. <httpHandlers>
  403.    
  404. </httpHandlers>
  405. </httpHandlers><httpHandlers>
  406. <httpHandlers>
  407.    
  408. </httpHandlers>
  409. </httpHandlers>get<httpHandlers>
  410. <httpHandlers>
  411.    
  412. </httpHandlers>
  413. </httpHandlers><httpHandlers>
  414. <httpHandlers>
  415.    
  416. </httpHandlers>
  417. </httpHandlers>{<httpHandlers>
  418. <httpHandlers>
  419.    
  420. </httpHandlers>
  421. </httpHandlers><httpHandlers>
  422. <httpHandlers>
  423.    
  424. </httpHandlers>
  425. </httpHandlers><httpHandlers>
  426. <httpHandlers>
  427.    
  428. </httpHandlers>
  429. </httpHandlers>if( TestEnvironment.IsTestEnvironment )<httpHandlers>
  430. <httpHandlers>
  431.    
  432. </httpHandlers>
  433. </httpHandlers><httpHandlers>
  434. <httpHandlers>
  435.    
  436. </httpHandlers>
  437. </httpHandlers><httpHandlers>
  438. <httpHandlers>
  439.    
  440. </httpHandlers>
  441. </httpHandlers><httpHandlers>
  442. <httpHandlers>
  443.    
  444. </httpHandlers>
  445. </httpHandlers>return TestEnvironment.GetValue("RequestFilePath") as string;<httpHandlers>
  446. <httpHandlers>
  447.    
  448. </httpHandlers>
  449. </httpHandlers><httpHandlers>
  450. <httpHandlers>
  451.    
  452. </httpHandlers>
  453. </httpHandlers><httpHandlers>
  454. <httpHandlers>
  455.    
  456. </httpHandlers>
  457. </httpHandlers>return HttpContext.Current.Request.FilePath;<httpHandlers>
  458. <httpHandlers>
  459.    
  460. </httpHandlers>
  461. </httpHandlers><httpHandlers>
  462. <httpHandlers>
  463.    
  464. </httpHandlers>
  465. </httpHandlers>}<httpHandlers>
  466. <httpHandlers>
  467.    
  468. </httpHandlers>
  469. </httpHandlers><httpHandlers>
  470. <httpHandlers>
  471.    
  472. </httpHandlers>
  473. </httpHandlers>set<httpHandlers>
  474. <httpHandlers>
  475.    
  476. </httpHandlers>
  477. </httpHandlers><httpHandlers>
  478. <httpHandlers>
  479.    
  480. </httpHandlers>
  481. </httpHandlers>{<httpHandlers>
  482. <httpHandlers>
  483.    
  484. </httpHandlers>
  485. </httpHandlers><httpHandlers>
  486. <httpHandlers>
  487.    
  488. </httpHandlers>
  489. </httpHandlers><httpHandlers>
  490. <httpHandlers>
  491.    
  492. </httpHandlers>
  493. </httpHandlers>TestEnvironment.SetValue("RequestFilePath", value);<httpHandlers>
  494. <httpHandlers>
  495.    
  496. </httpHandlers>
  497. </httpHandlers><httpHandlers>
  498. <httpHandlers>
  499.    
  500. </httpHandlers>
  501. </httpHandlers>}<httpHandlers>
  502. <httpHandlers>
  503.    
  504. </httpHandlers>
  505. </httpHandlers>}<httpHandlers>
  506. <httpHandlers>
  507.    
  508. </httpHandlers>
  509. </httpHandlers>///<httpHandlers>
  510. <httpHandlers>
  511.    
  512. </httpHandlers>
  513. </httpHandlers> /// return HttpContext.Current.Request.RawUrl;<httpHandlers>
  514. <httpHandlers>
  515.    
  516. </httpHandlers>
  517. </httpHandlers>///<httpHandlers>
  518. <httpHandlers>
  519.    
  520. </httpHandlers>
  521. </httpHandlers> public static string RequestRawUrl<httpHandlers>
  522. <httpHandlers>
  523.    
  524. </httpHandlers>
  525. </httpHandlers>{<httpHandlers>
  526. <httpHandlers>
  527.    
  528. </httpHandlers>
  529. </httpHandlers><httpHandlers>
  530. <httpHandlers>
  531.    
  532. </httpHandlers>
  533. </httpHandlers>get<httpHandlers>
  534. <httpHandlers>
  535.    
  536. </httpHandlers>
  537. </httpHandlers><httpHandlers>
  538. <httpHandlers>
  539.    
  540. </httpHandlers>
  541. </httpHandlers>{<httpHandlers>
  542. <httpHandlers>
  543.    
  544. </httpHandlers>
  545. </httpHandlers><httpHandlers>
  546. <httpHandlers>
  547.    
  548. </httpHandlers>
  549. </httpHandlers><httpHandlers>
  550. <httpHandlers>
  551.    
  552. </httpHandlers>
  553. </httpHandlers>if( TestEnvironment.IsTestEnvironment )<httpHandlers>
  554. <httpHandlers>
  555.    
  556. </httpHandlers>
  557. </httpHandlers><httpHandlers>
  558. <httpHandlers>
  559.    
  560. </httpHandlers>
  561. </httpHandlers><httpHandlers>
  562. <httpHandlers>
  563.    
  564. </httpHandlers>
  565. </httpHandlers><httpHandlers>
  566. <httpHandlers>
  567.    
  568. </httpHandlers>
  569. </httpHandlers>return TestEnvironment.GetValue("RequestRawUrl") as string;<httpHandlers>
  570. <httpHandlers>
  571.    
  572. </httpHandlers>
  573. </httpHandlers><httpHandlers>
  574. <httpHandlers>
  575.    
  576. </httpHandlers>
  577. </httpHandlers><httpHandlers>
  578. <httpHandlers>
  579.    
  580. </httpHandlers>
  581. </httpHandlers>return HttpContext.Current.Request.RawUrl;<httpHandlers>
  582. <httpHandlers>
  583.    
  584. </httpHandlers>
  585. </httpHandlers><httpHandlers>
  586. <httpHandlers>
  587.    
  588. </httpHandlers>
  589. </httpHandlers>}<httpHandlers>
  590. <httpHandlers>
  591.    
  592. </httpHandlers>
  593. </httpHandlers><httpHandlers>
  594. <httpHandlers>
  595.    
  596. </httpHandlers>
  597. </httpHandlers>set<httpHandlers>
  598. <httpHandlers>
  599.    
  600. </httpHandlers>
  601. </httpHandlers><httpHandlers>
  602. <httpHandlers>
  603.    
  604. </httpHandlers>
  605. </httpHandlers>{<httpHandlers>
  606. <httpHandlers>
  607.    
  608. </httpHandlers>
  609. </httpHandlers><httpHandlers>
  610. <httpHandlers>
  611.    
  612. </httpHandlers>
  613. </httpHandlers><httpHandlers>
  614. <httpHandlers>
  615.    
  616. </httpHandlers>
  617. </httpHandlers>TestEnvironment.SetValue("RequestRawUrl", value);<httpHandlers>
  618. <httpHandlers>
  619.    
  620. </httpHandlers>
  621. </httpHandlers><httpHandlers>
  622. <httpHandlers>
  623.    
  624. </httpHandlers>
  625. </httpHandlers>}<httpHandlers>
  626. <httpHandlers>
  627.    
  628. </httpHandlers>
  629. </httpHandlers>}<httpHandlers>
  630. <httpHandlers>
  631.    
  632. </httpHandlers>
  633. </httpHandlers>///<httpHandlers>
  634. <httpHandlers>
  635.    
  636. </httpHandlers>
  637. </httpHandlers> /// return HttpContext.Current.User.Identity.Name;<httpHandlers>
  638. <httpHandlers>
  639.    
  640. </httpHandlers>
  641. </httpHandlers>///<httpHandlers>
  642. <httpHandlers>
  643.    
  644. </httpHandlers>
  645. </httpHandlers> public static string UserIdentityName<httpHandlers>
  646. <httpHandlers>
  647.    
  648. </httpHandlers>
  649. </httpHandlers>{<httpHandlers>
  650. <httpHandlers>
  651.    
  652. </httpHandlers>
  653. </httpHandlers><httpHandlers>
  654. <httpHandlers>
  655.    
  656. </httpHandlers>
  657. </httpHandlers>get<httpHandlers>
  658. <httpHandlers>
  659.    
  660. </httpHandlers>
  661. </httpHandlers><httpHandlers>
  662. <httpHandlers>
  663.    
  664. </httpHandlers>
  665. </httpHandlers>{<httpHandlers>
  666. <httpHandlers>
  667.    
  668. </httpHandlers>
  669. </httpHandlers><httpHandlers>
  670. <httpHandlers>
  671.    
  672. </httpHandlers>
  673. </httpHandlers><httpHandlers>
  674. <httpHandlers>
  675.    
  676. </httpHandlers>
  677. </httpHandlers>if( TestEnvironment.IsTestEnvironment )<httpHandlers>
  678. <httpHandlers>
  679.    
  680. </httpHandlers>
  681. </httpHandlers><httpHandlers>
  682. <httpHandlers>
  683.    
  684. </httpHandlers>
  685. </httpHandlers><httpHandlers>
  686. <httpHandlers>
  687.    
  688. </httpHandlers>
  689. </httpHandlers><httpHandlers>
  690. <httpHandlers>
  691.    
  692. </httpHandlers>
  693. </httpHandlers>return TestEnvironment.GetValue("UserIdentityName") as string;<httpHandlers>
  694. <httpHandlers>
  695.    
  696. </httpHandlers>
  697. </httpHandlers><httpHandlers>
  698. <httpHandlers>
  699.    
  700. </httpHandlers>
  701. </httpHandlers><httpHandlers>
  702. <httpHandlers>
  703.    
  704. </httpHandlers>
  705. </httpHandlers>if( HttpContext.Current.Request.IsAuthenticated == false )<httpHandlers>
  706. <httpHandlers>
  707.    
  708. </httpHandlers>
  709. </httpHandlers><httpHandlers>
  710. <httpHandlers>
  711.    
  712. </httpHandlers>
  713. </httpHandlers><httpHandlers>
  714. <httpHandlers>
  715.    
  716. </httpHandlers>
  717. </httpHandlers><httpHandlers>
  718. <httpHandlers>
  719.    
  720. </httpHandlers>
  721. </httpHandlers>return null;<httpHandlers>
  722. <httpHandlers>
  723.    
  724. </httpHandlers>
  725. </httpHandlers><httpHandlers>
  726. <httpHandlers>
  727.    
  728. </httpHandlers>
  729. </httpHandlers><httpHandlers>
  730. <httpHandlers>
  731.    
  732. </httpHandlers>
  733. </httpHandlers>return HttpContext.Current.User.Identity.Name;<httpHandlers>
  734. <httpHandlers>
  735.    
  736. </httpHandlers>
  737. </httpHandlers><httpHandlers>
  738. <httpHandlers>
  739.    
  740. </httpHandlers>
  741. </httpHandlers>}<httpHandlers>
  742. <httpHandlers>
  743.    
  744. </httpHandlers>
  745. </httpHandlers><httpHandlers>
  746. <httpHandlers>
  747.    
  748. </httpHandlers>
  749. </httpHandlers>set<httpHandlers>
  750. <httpHandlers>
  751.    
  752. </httpHandlers>
  753. </httpHandlers><httpHandlers>
  754. <httpHandlers>
  755.    
  756. </httpHandlers>
  757. </httpHandlers>{<httpHandlers>
  758. <httpHandlers>
  759.    
  760. </httpHandlers>
  761. </httpHandlers><httpHandlers>
  762. <httpHandlers>
  763.    
  764. </httpHandlers>
  765. </httpHandlers><httpHandlers>
  766. <httpHandlers>
  767.    
  768. </httpHandlers>
  769. </httpHandlers>TestEnvironment.SetValue("UserIdentityName", value);<httpHandlers>
  770. <httpHandlers>
  771.    
  772. </httpHandlers>
  773. </httpHandlers><httpHandlers>
  774. <httpHandlers>
  775.    
  776. </httpHandlers>
  777. </httpHandlers>}<httpHandlers>
  778. <httpHandlers>
  779.    
  780. </httpHandlers>
  781. </httpHandlers>}<httpHandlers>
  782. <httpHandlers>
  783.    
  784. </httpHandlers>
  785. </httpHandlers>// 如果还需要访问更多的HttpContext信息,也可以采用下面的方法。请自行完成。<httpHandlers>
  786. <httpHandlers>
  787.    
  788. </httpHandlers>
  789. </httpHandlers>//public static HttpContextBase Current<httpHandlers>
  790. <httpHandlers>
  791.    
  792. </httpHandlers>
  793. </httpHandlers>//{<httpHandlers>
  794. <httpHandlers>
  795.    
  796. </httpHandlers>
  797. </httpHandlers>//<httpHandlers>
  798. <httpHandlers>
  799.    
  800. </httpHandlers>
  801. </httpHandlers>get { }<httpHandlers>
  802. <httpHandlers>
  803.    
  804. </httpHandlers>
  805. </httpHandlers>//<httpHandlers>
  806. <httpHandlers>
  807.    
  808. </httpHandlers>
  809. </httpHandlers>set { }<httpHandlers>
  810. <httpHandlers>
  811.    
  812. </httpHandlers>
  813. </httpHandlers>//}}
复制代码
注意HttpContextHelper这个类,我将平时访问的一些与请求或者与ASP.NET运行环境相关的属性全部封装在这里了。如果不够,还可以继续添加。有了这些代码,我就可以简单在控制台程序中调用它们(您也可以移到单元测试项目中):
  1. class Program{<httpHandlers>
  2. <httpHandlers>
  3.    
  4. </httpHandlers>
  5. </httpHandlers>static void Main(string[] args)<httpHandlers>
  6. <httpHandlers>
  7.    
  8. </httpHandlers>
  9. </httpHandlers>{<httpHandlers>
  10. <httpHandlers>
  11.    
  12. </httpHandlers>
  13. </httpHandlers><httpHandlers>
  14. <httpHandlers>
  15.    
  16. </httpHandlers>
  17. </httpHandlers>InitDB();<httpHandlers>
  18. <httpHandlers>
  19.    
  20. </httpHandlers>
  21. </httpHandlers><httpHandlers>
  22. <httpHandlers>
  23.    
  24. </httpHandlers>
  25. </httpHandlers>Test_AjaxStyle_SetStyle();<httpHandlers>
  26. <httpHandlers>
  27.    
  28. </httpHandlers>
  29. </httpHandlers><httpHandlers>
  30. <httpHandlers>
  31.    
  32. </httpHandlers>
  33. </httpHandlers>Test_AjaxCustomer_GetById();<httpHandlers>
  34. <httpHandlers>
  35.    
  36. </httpHandlers>
  37. </httpHandlers><httpHandlers>
  38. <httpHandlers>
  39.    
  40. </httpHandlers>
  41. </httpHandlers>Test_TestEnvironment();<httpHandlers>
  42. <httpHandlers>
  43.    
  44. </httpHandlers>
  45. </httpHandlers><httpHandlers>
  46. <httpHandlers>
  47.    
  48. </httpHandlers>
  49. </httpHandlers>Console.ReadLine();<httpHandlers>
  50. <httpHandlers>
  51.    
  52. </httpHandlers>
  53. </httpHandlers>}<httpHandlers>
  54. <httpHandlers>
  55.    
  56. </httpHandlers>
  57. </httpHandlers>static void InitDB()<httpHandlers>
  58. <httpHandlers>
  59.    
  60. </httpHandlers>
  61. </httpHandlers>{<httpHandlers>
  62. <httpHandlers>
  63.    
  64. </httpHandlers>
  65. </httpHandlers><httpHandlers>
  66. <httpHandlers>
  67.    
  68. </httpHandlers>
  69. </httpHandlers>string xmlPath = "..\\..\\DemoWebSite1\\App_Data\\MyNorthwindDataBase.xml";<httpHandlers>
  70. <httpHandlers>
  71.    
  72. </httpHandlers>
  73. </httpHandlers><httpHandlers>
  74. <httpHandlers>
  75.    
  76. </httpHandlers>
  77. </httpHandlers>WebSiteDB.LoadDbFromXml(xmlPath);<httpHandlers>
  78. <httpHandlers>
  79.    
  80. </httpHandlers>
  81. </httpHandlers>}<httpHandlers>
  82. <httpHandlers>
  83.    
  84. </httpHandlers>
  85. </httpHandlers>static void Test_AjaxStyle_SetStyle()<httpHandlers>
  86. <httpHandlers>
  87.    
  88. </httpHandlers>
  89. </httpHandlers>{<httpHandlers>
  90. <httpHandlers>
  91.    
  92. </httpHandlers>
  93. </httpHandlers><httpHandlers>
  94. <httpHandlers>
  95.    
  96. </httpHandlers>
  97. </httpHandlers>AjaxStyle ajax = new AjaxStyle();<httpHandlers>
  98. <httpHandlers>
  99.    
  100. </httpHandlers>
  101. </httpHandlers><httpHandlers>
  102. <httpHandlers>
  103.    
  104. </httpHandlers>
  105. </httpHandlers>ajax.SetStyle(StyleHelper.StyleArray[0]);<httpHandlers>
  106. <httpHandlers>
  107.    
  108. </httpHandlers>
  109. </httpHandlers><httpHandlers>
  110. <httpHandlers>
  111.    
  112. </httpHandlers>
  113. </httpHandlers>if( CookieHelper.GetCookieValue(StyleHelper.STR_PageStyle) == StyleHelper.StyleArray[0] )<httpHandlers>
  114. <httpHandlers>
  115.    
  116. </httpHandlers>
  117. </httpHandlers><httpHandlers>
  118. <httpHandlers>
  119.    
  120. </httpHandlers>
  121. </httpHandlers><httpHandlers>
  122. <httpHandlers>
  123.    
  124. </httpHandlers>
  125. </httpHandlers>Console.WriteLine("AjaxStyle.SetStyle("{0}") OK", StyleHelper.StyleArray[0]);<httpHandlers>
  126. <httpHandlers>
  127.    
  128. </httpHandlers>
  129. </httpHandlers><httpHandlers>
  130. <httpHandlers>
  131.    
  132. </httpHandlers>
  133. </httpHandlers>else<httpHandlers>
  134. <httpHandlers>
  135.    
  136. </httpHandlers>
  137. </httpHandlers><httpHandlers>
  138. <httpHandlers>
  139.    
  140. </httpHandlers>
  141. </httpHandlers><httpHandlers>
  142. <httpHandlers>
  143.    
  144. </httpHandlers>
  145. </httpHandlers>Console.WriteLine("AjaxStyle.SetStyle("{0}") faild.", StyleHelper.StyleArray[0]);<httpHandlers>
  146. <httpHandlers>
  147.    
  148. </httpHandlers>
  149. </httpHandlers><httpHandlers>
  150. <httpHandlers>
  151.    
  152. </httpHandlers>
  153. </httpHandlers>CookieHelper.ClearCookie();<httpHandlers>
  154. <httpHandlers>
  155.    
  156. </httpHandlers>
  157. </httpHandlers><httpHandlers>
  158. <httpHandlers>
  159.    
  160. </httpHandlers>
  161. </httpHandlers>ajax.SetStyle("abc");<httpHandlers>
  162. <httpHandlers>
  163.    
  164. </httpHandlers>
  165. </httpHandlers><httpHandlers>
  166. <httpHandlers>
  167.    
  168. </httpHandlers>
  169. </httpHandlers>// 一个无效的值。<httpHandlers>
  170. <httpHandlers>
  171.    
  172. </httpHandlers>
  173. </httpHandlers><httpHandlers>
  174. <httpHandlers>
  175.    
  176. </httpHandlers>
  177. </httpHandlers>if( CookieHelper.GetCookieValue(StyleHelper.STR_PageStyle) == null  )<httpHandlers>
  178. <httpHandlers>
  179.    
  180. </httpHandlers>
  181. </httpHandlers><httpHandlers>
  182. <httpHandlers>
  183.    
  184. </httpHandlers>
  185. </httpHandlers><httpHandlers>
  186. <httpHandlers>
  187.    
  188. </httpHandlers>
  189. </httpHandlers>Console.WriteLine("AjaxStyle.SetStyle("abc") OK");<httpHandlers>
  190. <httpHandlers>
  191.    
  192. </httpHandlers>
  193. </httpHandlers><httpHandlers>
  194. <httpHandlers>
  195.    
  196. </httpHandlers>
  197. </httpHandlers>else<httpHandlers>
  198. <httpHandlers>
  199.    
  200. </httpHandlers>
  201. </httpHandlers><httpHandlers>
  202. <httpHandlers>
  203.    
  204. </httpHandlers>
  205. </httpHandlers><httpHandlers>
  206. <httpHandlers>
  207.    
  208. </httpHandlers>
  209. </httpHandlers>Console.WriteLine("AjaxStyle.SetStyle("abc") faild.");<httpHandlers>
  210. <httpHandlers>
  211.    
  212. </httpHandlers>
  213. </httpHandlers>}<httpHandlers>
  214. <httpHandlers>
  215.    
  216. </httpHandlers>
  217. </httpHandlers><httpHandlers>
  218. <httpHandlers>
  219.    
  220. </httpHandlers>
  221. </httpHandlers>static void Test_AjaxCustomer_GetById()<httpHandlers>
  222. <httpHandlers>
  223.    
  224. </httpHandlers>
  225. </httpHandlers>{<httpHandlers>
  226. <httpHandlers>
  227.    
  228. </httpHandlers>
  229. </httpHandlers><httpHandlers>
  230. <httpHandlers>
  231.    
  232. </httpHandlers>
  233. </httpHandlers>AjaxCustomer ajax = new AjaxCustomer();<httpHandlers>
  234. <httpHandlers>
  235.    
  236. </httpHandlers>
  237. </httpHandlers><httpHandlers>
  238. <httpHandlers>
  239.    
  240. </httpHandlers>
  241. </httpHandlers>object result = ajax.GetById(1);<httpHandlers>
  242. <httpHandlers>
  243.    
  244. </httpHandlers>
  245. </httpHandlers><httpHandlers>
  246. <httpHandlers>
  247.    
  248. </httpHandlers>
  249. </httpHandlers>if( result is JsonResult )<httpHandlers>
  250. <httpHandlers>
  251.    
  252. </httpHandlers>
  253. </httpHandlers><httpHandlers>
  254. <httpHandlers>
  255.    
  256. </httpHandlers>
  257. </httpHandlers><httpHandlers>
  258. <httpHandlers>
  259.    
  260. </httpHandlers>
  261. </httpHandlers>Console.WriteLine("AjaxCustomer.GetById(1) OK");<httpHandlers>
  262. <httpHandlers>
  263.    
  264. </httpHandlers>
  265. </httpHandlers><httpHandlers>
  266. <httpHandlers>
  267.    
  268. </httpHandlers>
  269. </httpHandlers>else<httpHandlers>
  270. <httpHandlers>
  271.    
  272. </httpHandlers>
  273. </httpHandlers><httpHandlers>
  274. <httpHandlers>
  275.    
  276. </httpHandlers>
  277. </httpHandlers><httpHandlers>
  278. <httpHandlers>
  279.    
  280. </httpHandlers>
  281. </httpHandlers>Console.WriteLine("AjaxCustomer.GetById(1) faild");<httpHandlers>
  282. <httpHandlers>
  283.    
  284. </httpHandlers>
  285. </httpHandlers>}<httpHandlers>
  286. <httpHandlers>
  287.    
  288. </httpHandlers>
  289. </httpHandlers>static void Test_TestEnvironment()<httpHandlers>
  290. <httpHandlers>
  291.    
  292. </httpHandlers>
  293. </httpHandlers>{<httpHandlers>
  294. <httpHandlers>
  295.    
  296. </httpHandlers>
  297. </httpHandlers><httpHandlers>
  298. <httpHandlers>
  299.    
  300. </httpHandlers>
  301. </httpHandlers>TestEnvironment.SetValue("key1", 123);<httpHandlers>
  302. <httpHandlers>
  303.    
  304. </httpHandlers>
  305. </httpHandlers><httpHandlers>
  306. <httpHandlers>
  307.    
  308. </httpHandlers>
  309. </httpHandlers>TestEnvironment.SetValue("key2", "abc");<httpHandlers>
  310. <httpHandlers>
  311.    
  312. </httpHandlers>
  313. </httpHandlers><httpHandlers>
  314. <httpHandlers>
  315.    
  316. </httpHandlers>
  317. </httpHandlers>if( (int)TestEnvironment.GetValue("key1") == 123 )<httpHandlers>
  318. <httpHandlers>
  319.    
  320. </httpHandlers>
  321. </httpHandlers><httpHandlers>
  322. <httpHandlers>
  323.    
  324. </httpHandlers>
  325. </httpHandlers><httpHandlers>
  326. <httpHandlers>
  327.    
  328. </httpHandlers>
  329. </httpHandlers>Console.WriteLine("TestEnvironment.SetValue(123) OK.");<httpHandlers>
  330. <httpHandlers>
  331.    
  332. </httpHandlers>
  333. </httpHandlers><httpHandlers>
  334. <httpHandlers>
  335.    
  336. </httpHandlers>
  337. </httpHandlers>if( (string)TestEnvironment.GetValue("key2") == "abc" )<httpHandlers>
  338. <httpHandlers>
  339.    
  340. </httpHandlers>
  341. </httpHandlers><httpHandlers>
  342. <httpHandlers>
  343.    
  344. </httpHandlers>
  345. </httpHandlers><httpHandlers>
  346. <httpHandlers>
  347.    
  348. </httpHandlers>
  349. </httpHandlers>Console.WriteLine("TestEnvironment.SetValue("abc") OK.");<httpHandlers>
  350. <httpHandlers>
  351.    
  352. </httpHandlers>
  353. </httpHandlers>}
复制代码

用过ASP.NET MVC的人可能会问我:
为什么不使用System.Web.Abstractions定义的那些类型,那样不是更容易支持单元测试吗?
是啊,我也知道那种做法的好处。但那样做的工作量也会更大。
根据目前的MyMVC设计方式,如果要引入HttpContextBase, HttpRequestBase, HttpResponseBase这类对象,就需要设计Controller基类,并且创建Controller的过程也会比目前复杂,或者要把ASP.NET MVC那套创建Controller的过程搬过来,否则仍然会不完整。然而,我还是打算自己再设计另一种简单的方法 尽可能 地去解决这个问题。上面的方法就是我的设计,虽然不够完整,却是简单有效的,而且测试代码也会简单很多。另一方面,我不提供Controller基类,但可以设计诸如HttpContextHelper.Current这样的访问方式,最终的结果仍然是可以支持单元测试的,况且HttpContextHelper.Current这种用法也不会让人难以适应。不提供还有另外的好处:允许设计自己的基类。
还有一点要补充的是:MyMVC框架内部也没有使用System.Web.Abstractions,是的,我知道。
这也只能说:框架的代码不能进行单元测试而已。   但不影响用户的Action代码的单元测试。
再说框架中的代码有些也很难做单元测试,毕竟太依赖于ASP.NET,而且我没那么多的空闲时间以及驱动力。
MyMVC还有一个没有支持的是文件的上传与下载。
这里我来说说对于这块功能访如何去实现:
1. 可以直接访问HttpContext.Current ,并忽略这些代码的单元测试能力。
2. 自行实现我前面没有实现的HttpContextHelper.Current 。
是的,我的确没有完成这个功能,而把它留给了用户,抱歉。
关于框架代码与示例代码

在本文的未尾,我提供了MyMVC框架的代码,以及全部示例代码。
以前我也提供过我的老版本框架的演示示例,我认为我已经考虑地相当周到了:
1. 没有IIS,没有VS,一样可以运行我的DEMO,因为我把FishAspnetLoader放进去了,调用的BAT文件也准备好了。
2. SQL SERVER如果支持【用户实例】模式,部署会容易。
3. 在数据方面,我不但提供了mdf文件,还提供了sql脚本。
4. 还准备了一些说明文件。

然而,事实却没有我想像那么好,还是有很多人给我发邮件,问我示例为什么不能运行。
不能运行的环境也是让我完全没有想到的:
1. 有人把它部署到了IIS6,扩展名的映射遇到问题。
2. 有人把它部署到了IIS7,可我没有提供对IIS7的配置!
3. 有人没有安装SQL SERVER。这个只能是没有办法了!
4. 有人不能完成示例程序所需的SQL SERVER配置。
5. 有人用VS2010打开项目并升级了.net版本,遇到一些说不清楚的问题。
吸取前面的教训后,这次我的示例采用XML文件做为数据源,而且增加了IIS7的配置。
不过,有一点我不能替您设置的是XML文件的写入权限。
如果数据不能保存,请检查目录的写入权限,此时程序没有任何提示。
再补充二点:
1. 如果您使用VS2010打开示例项目,请不要选择升级.net版本,不要盲目点击确定。
2. 如果在IIS中部署示例网站遇到问题,那么建议使用VS运行示例网站。
如果您还有配置ASP.NET应用程序的问题,那么请关注我的后续博客。
下篇博客我打算谈一下在部署ASP.NET网站时,IIS6/7 以及SQL SERVER中必须知道的一些设置。

点击此处下载示例代码
注意:本文所介绍的框架还提供另外一个工具做为演示示例,
点击后面链接即可阅读。【用ASP.NET写个SQLSERVER的小工具】


如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】按钮。
如果,您希望更容易地发现我的新博客,不妨点击一下右下角的【关注 Fish Li】。
因为,我的写作热情也离不开您的肯定支持。
感谢您的阅读,如果您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是Fish Li 。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
3.gif
您需要登录后才可以回帖 登录 | 立即注册