使用 HttpApplication 对象

ASP.NET 框架中的许多类都提供了许多很方便的属性可以直接映射到 HttpContext 类中定义的属性。这种交叠有一个很好的例子就是 HttpApplication,它就是全局应用类的基类,在下表中,你可以看到 HttpApplication 类中定义的属性和方法。许多和 HttpContext 中定义的很相似。

表 1 – HttpApplication 类中定义的成员

名称 描述
Application 对应到 HttpContext.Application 属性,通过它可以获取应用层面的状态数据。
CompleteRequest() 终止当前请求的生命周期,直接跳转到 LogRequest 事件。
Context 返回当前请求的 HttpContext 对象。
Init() 每个注册模块上的 Init() 方法调用之后调用。
Modules 返回一个 HttpModuleCollection 对象,当中详细描述了当前应用中的模块。
RegisterModule(type) 注册新模块的静态方法。
Request 返回 HttpContext.Request 值, 但是如果值为 null 的时候会抛出一个 HttpException。
Response 返回 HttpContext.Response 值,但是如果值为 null 的时候会抛出一个 HttpException。
Server 映射到 HttpContext.Server。
Session 返回 HttpContext.Session 值,但是如果值为 null 的时候会抛出一个 HttpException。

大多数的这些成员都是很方便的属性可以映射到 HttpContext 类中的属性,但是有三个值得注意,接下来详细说明。

处理属性异常

Request, Response, Session 和 User 属性返回的是 HttpContext 类中相对应的属性的值,但是,这些属性如果从 HttpContext 上对应的属性中获取的值是 null 就会抛出一个 HttpException。

发生这样的事是因为 HttpApplication 类会为两种不同的生命周期接收通知:应用生命周期和请求生命周期。描述单个请求的对象是不可以在全局应用类中用来处理应用相关的事件,所以如果我们在处理应用层级的通知的时候使用了与请求相关联的属性就会抛出 HttpException 异常。

抛出这样一个异常的策略是非常粗糙的,因为这使得处理未知来源的 HttpApplication 对象非常困难,我们可以看一下下面的代码:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing; namespace SimpleApp
{
public class MvcApplication : System.Web.HttpApplication
{
public MvcApplication()
{
PostAcquireRequestState += (src, args) => CreateTimeStamp();
} protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
CreateTimeStamp();
} private void CreateTimeStamp()
{
string stamp = Context.Timestamp.ToLongTimeString();
if (Session != null)
{
Session["request_timestamp"] = stamp;
}
else
{
Application["app_timestamp"] = stamp;
}
}
}
}

现在,我们删除我们之前写的代码,重新定义一个新的方法用来创建时间戳并将其存放在状态数据中。现在,我们不需要对状态数据了解太多,只需要知道 Session 属性会为每一个独立的请求返回状态数据对象。

提示:注意到,我为 PostAcquireRequestState 事件创建了请求时间戳。这是因为模块直到 AcquireRequestState 事件触发之后才会提供状态数据服务。因此,即使全局应用类实例创建出来用来处理请求相关的事件,Session 属性也会返回 null。

这个新方法叫做 CreateTimeStamp,旨在减少代码冗余并为应用层级和请求层级的事件添加事件戳。但是,只要现在应用一启动就会报错,因为在这段代码中,在全局应用类创建出来处理 Application_Start 方法的时候想要尝试读取 Session 属性。

我能够使用 try…catch 代码块,但是这是一个糟糕的实践,因为异常处理不应该用来管理一个应用中可预见的流程。因此,我们应该直接使用 HttpContext 中同等的属性。代码如下:

 private void CreateTimeStamp()
{
string stamp = Context.Timestamp.ToLongTimeString();
if (Context.Session != null)
{
Session["request_timestamp"] = stamp;
}
else
{
Application["app_timestamp"] = stamp;
}
}

注意到,我只是修改了之前对 Session 属性的检查;如果它不为 null,我就可以使用 HttpApplication 类中定义的 Session 属性。Application 属性总是能够返回 HttpApplicationState 对象,状态管理相关的知识我们会在后期讲解到。

我们需要注意这种问题特别是在全局应用类中不与独立请求相关联的对象。ASP.NET 其他地方,特别是在 MVC 框架 controller 类中。我们总是可以使用 context 来表示一个请求。我们可以看一下下面的例子:

 using SimpleApp.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace SimpleApp.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View(GetTimeStamps());
} [HttpPost]
public ActionResult Index(Color color)
{
Color? oldColor = Session["color"] as Color?;
if (oldColor != null)
{
Votes.ChangeVote(color, (Color)oldColor);
}
else
{
Votes.RecordVote(color);
} ViewBag.SelectedColor = Session["color"] = color;
return View(GetTimeStamps());
} private List<string> GetTimeStamps()
{
return new List<string> { String.Format("App timestamp: {0}", HttpContext.Application["app_timestamp"]),
String.Format("Request timestamp: {0}", Session["request_timestamp"])};
}
}
}

Controller 类是 MVC 框架的基础,当中提供了一个方便的 Session 属性与 HttpContext.Session 相关联(但是我需要使用 HttpContext.Application,因为它并没有相关联的简便的属性)。

你可以在应用启动的时候看到时间戳。因为两个值在起初的时候很可能是相同的,但是如果你重新刷新浏览器窗口的话,你会发现应用时间戳一直不变,而请求时间戳会在每次更新的时候发生改变。

图 1 - 展示应用和请求时间戳

[根据 Adam Freeman – Pro ASP.NET MVC 5 Platform 选译]

[译] ASP.NET 生命周期 – ASP.NET 上下文对象(六)的更多相关文章

  1. [译] ASP.NET 生命周期 – ASP.NET 应用生命周期(一)

    概述 ASP.NET 平台定义了两个非常重要的生命周期.第一个是 应用生命周期  (application life cycle),用来追踪应用从启动的那一刻到终止的那一刻.另一个就是 请求生命周期 ...

  2. [译] ASP.NET 生命周期 – ASP.NET 上下文对象(五)

    ASP.NET 上下文对象 ASP.NET 提供了一系列对象用来给当前请求,将要返回到客户端的响应,以及 Web 应用本身提供上下文信息.间接的,这些上下文对象也可以用来回去核心 ASP.NET 框架 ...

  3. [译] ASP.NET 生命周期 – ASP.NET 上下文对象(七)

    使用 HttpRequest 对象 HttpRequest 对象描述的是一个正在被处理的 HTTP 请求.下表列举了 HttpRequest 中的属性,它们提供了当前请求的相关信息(HttpReque ...

  4. [译] ASP.NET 生命周期 – ASP.NET 请求生命周期(三)

    使用特殊方法处理请求生命周期事件 为了在全局应用类中处理这些事件,我们会创建一个名称以 Application_ 开头,以事件名称结尾的方法,比如 Application_BeginRequest.举 ...

  5. [译] ASP.NET 生命周期 – ASP.NET 请求生命周期(四)

    不使用特殊方法来处理请求生命周期事件 HttpApplication 类是全局应用类的基类,定义了可以直接使用的一般 C# 事件.那么使用标准 C# 事件还是特殊方法那就是个人偏好的问题了,如果喜欢, ...

  6. [译] ASP.NET 生命周期 – ASP.NET 请求生命周期(二)

    ASP.NET 请求生命周期 全局应用类也可以用来跟踪每个独立请求的生命周期,包括请求从 ASP.NET 平台传递到 MVC 框架.ASP.NET 框架会创建一个定义在 Global.asax 文件中 ...

  7. [译] ASP.NET 生命周期 – ASP.NET 上下文对象(八)

    使用 HttpResponse 对象 HttpResponse 对象是与 HttpRequest 对象相对应的,用来表示构建中的响应.它当中提供了方法和属性可供我们自定义响应,有一些在使用 MVC 视 ...

  8. Asp.net生命周期与Http协议

    Http协议,底层的东西还是不是特别熟悉,感觉要经过沉淀之后才能理解这些东西吧 1.Asp.net生命周期 Asp.net生命周期: 从发起请求开始,到IIS进行处理的全部过程,然后再到获取结果 当请 ...

  9. Git使用总结 Asp.net生命周期与Http协议 托管代码与非托管代码的区别 通过IEnumerable接口遍历数据 依赖注入与控制反转 C#多线程——优先级 AutoFac容器初步 C#特性详解 C#特性详解 WPF 可触摸移动的ScrollViewer控件 .NET(C#)能开发出什么样的APP?盘点那些通过Smobiler开发的移动应用

    一,原理 首先,我们要明白Git是什么,它是一个管理工具或软件,用来管理什么的呢?当然是在软件开发过程中管理软件或者文件的不同版本的工具,一些作家也可以用这个管理自己创作的文本文件,由Linus开发的 ...

随机推荐

  1. 解决浏览器background-image属性不支持css3动画

    问题 最近在使用background-image属性来实现css3的逐帧动画时,碰到了个问题.在chrome浏览器上,background-image属性是支持css3动画的,但是到了firefox上 ...

  2. LeetCode 142

    Linked List Cycle II Given a linked list, return the node where the cycle begins. If there is no cyc ...

  3. 使用AccessibilityService模拟点击事件失败的分析

    使用AccessibilityService模拟点击事件的方法: AccessibilityNodeInfo.performAction(AccessibilityNodeInfo.ACTION_CL ...

  4. Dynamic\Static\IsKinematic

    1.Dynamic: 有Collider和RigidBody的GameObject, Unity视之为Dynamic. 适用于经常变换移动的对象. 2.Static: 只含有Collider的Game ...

  5. 纯CSS制作“跳动的心”demo

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  6. ActiveMQ(5.10.0) - Configuring the JAAS Authentication Plug-in

    JAAS provides pluggable authentication, which means ActiveMQ will use the same authentication API re ...

  7. MyBatis(3.2.3) - Paginated ResultSets using RowBounds

    Sometimes, we may need to work with huge volumes of data, such as with tables with millions of recor ...

  8. 【AngularJs】---实现select的ng-options

    controller .controller('MainController', function($scope, $http, $ionicModal, $timeout) { var post = ...

  9. 解决ASP.NET网站发布问题

    目录 前言 开始 aspx.cs文件放到单独的类库项目 一个可选择勾选页面的发布工具:LimusicAddin 前言 Asp.net 发布分为:动态编译和预编译.预编译又分为:In Place Pre ...

  10. C# list使用方法

    C# list使用方法 集合是OOP中的一个重要概念,C#中对集合的全面支持更是该语言的精华之一. 为什么要用泛型集合? 在C# 2.0之前,主要可以通过两种方式实现集合: a.使用ArrayList ...