使用特殊方法处理请求生命周期事件
为了在全局应用类中处理这些事件,我们会创建一个名称以 Application_ 开头,以事件名称结尾的方法,比如 Application_BeginRequest。举个例子,就像 Application_Start 和 Application_End 方法,ASP.NET 框架就会在事件触发的时候找到这些函数并触发它。下面是更新后的代码片段:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.Web.Mvc; 6 using System.Web.Routing; 7 8 namespace SimpleApp 9 { 10 public class MvcApplication : System.Web.HttpApplication 11 { 12 protected void Application_Start() 13 { 14 AreaRegistration.RegisterAllAreas(); 15 RouteConfig.RegisterRoutes(RouteTable.Routes); 16 } 17 18 protected void Application_BeginRequest() 19 { 20 RecordEvent("BeginRequest"); 21 } 22 23 protected void Application_AuthenticateRequest() 24 { 25 RecordEvent("AuthenticateRequest"); 26 } 27 28 protected void Application_PostAuthenticateRequest() 29 { 30 RecordEvent("PostAuthenticateRequest"); 31 } 32 33 private void RecordEvent(string name) 34 { 35 List<string> eventList = Application["events"] as List<string>; 36 if (eventList == null) 37 { 38 Application["events"] = eventList = new List<string>(); 39 } 40 eventList.Add(name); 41 } 42 } 43 }
我定义了一个叫做 RecordEvent 的方法,用来接收一个事件的名称作为参数,并将其存储到 HttpApplication 类的 Application 属性中。
注意:在没有深入了解 Application 属性之前,请勿滥用这个属性。
我从添加到全局应用类中的其他三个方法中调用了 RecordEvent 方法。这些方法会在 BeginRequest, AuthenticateRequest 和 PostAuthenticateRequest 触发的时候被调用。我们暂时不需要将这些函数显式注册成事件处理器,ASP.NET 框架会自动定位和调用这些函数。
展示事件信息
为了展示我们代码中接收到的事件的信息,我们需要更改 Home controller 和它的 Index 视图。代码如下:
1 using SimpleApp.Models; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Web; 6 using System.Web.Mvc; 7 8 namespace SimpleApp.Controllers 9 { 10 public class HomeController : Controller 11 { 12 public ActionResult Index() 13 { 14 return View(HttpContext.Application["events"]); 15 } 16 17 [HttpPost] 18 public ActionResult Index(Color color) 19 { 20 Color? oldColor = Session["color"] as Color?; 21 22 if (oldColor != null) 23 { 24 Votes.ChangeVote(color, (Color)oldColor); 25 } 26 else 27 { 28 Votes.RecordVote(color); 29 } 30 31 ViewBag.SelectedColor = Session["color"] = color; 32 return View(HttpContext.Application["events"]); 33 } 34 } 35 }
为了获取到存储在全局应用类中的数据,我们需要使用到 HttpContext.Application 属性,我们后面会详细讲解上下文对象。现在,我们需要更新相关的 Razor 视图:
1 @using SimpleApp.Models 2 @model List<string> 3 @{ 4 Layout = null; 5 } 6 7 <!DOCTYPE html> 8 9 <html> 10 <head> 11 <meta charset="utf-8" /> 12 <meta name="viewport" content="width=device-width" /> 13 <title>Vote</title> 14 <link rel="stylesheet" href="~/Content/bootstrap.min.css" /> 15 <link rel="stylesheet" href="~/Content/bootstrap-theme.min.css" /> 16 </head> 17 <body class="container"> 18 <div class="panel panel-primary"> 19 20 @if (ViewBag.SelectedColor == null) 21 { 22 <h4 class="panel-heading">Vote for your favourite color</h4> 23 } 24 else 25 { 26 <h4 class="panel-heading">Change your vote from @ViewBag.SelectedColor</h4> 27 } 28 29 <div class="panel-body"> 30 @using (Html.BeginForm()) 31 { 32 @Html.DropDownList("color", new SelectList(Enum.GetValues(typeof(Color))), "Choose a Color", new { @class = "form-control" }) 33 34 <div> 35 <button class="btn btn-primary center-block" type="submit">Vote</button> 36 </div> 37 } 38 </div> 39 </div> 40 41 <div class="panel panel-primary"> 42 <h5 class="panel-heading">Results</h5> 43 44 <table class="table table-striped table-condensed"> 45 <tr> 46 <th>Color</th> 47 <th>Votes</th> 48 </tr> 49 @foreach (Color c in Enum.GetValues(typeof(Color))) 50 { 51 <tr> 52 <td>@c</td> 53 <td>@Votes.GetVotes(c)</td> 54 </tr> 55 } 56 </table> 57 </div> 58 59 <div class="panel panel-primary"> 60 <h5 class="panel-heading">Events</h5> 61 <table class="table table-condensed table-striped"> 62 @foreach (string eventName in Model) 63 { 64 <tr><td>@eventName</td></tr> 65 } 66 </table> 67 </div> 68 </body> 69 </html>
事件名称列表作为模型对象传递到视图中,我们使用 Razor foreach 循环来生成 HTML table 元素。
图 1 - 展示生命周期事件详情
提示:这种技术只能使用在排在 PreRequestHandlerExecute 事件之前的事件之上,因为 controller 中的 action 方法会在 PreRequestHandlerExecute 和 PostRequestHandlerExecute 事件之间执行,所以后续触发的事件都已经在响应生成好之后发生了。
[根据 Adam Freeman – Pro ASP.NET MVC 5 Platform 选译]