.NET本质论(4)应用程序对象HttpApplication
当HttpContext对象创建之后,HttpRuntime将随后创建一个用于处理请求的对象,这个对象的类型为HttpApplication.
在ASP.NET内部,HttpRuntime管理一个定义在System.Web命名空间下的HttpApplicationFactory类的实例,HttpApplicationFactory通过工厂模式管理HttpApplication对象,在HttpApplicationFactory内部维护了一个HttpApplication对象池,使得被创建的HttpApplication对象可以被重复使用,但是,每一个HttpApplication对象每一次仅仅用于处理一个请求,这样,对于ASP.NET程序员来说,也就不需要考虑HttpApplication中多个请求并发的处理问题了。
在实际的请求处理过程中,我们还需要进行大量的工作,例如,检查当前的请求是由哪一个用户发起的,以此我们就可以针对不同的用户进行不同的处理,或者根据用户来决定是否对用户的请求进行处理,对于没有权限的用户返回一个缺少相应权限的回应等。如果我们在一个方法中来完成这些任务,显然会造成方法的过度臃肿。在HttpApplication中,利用.NET中的事件机制,通过在处理过程中依次发出的多个事件,将这个处理过程分解为多个步骤,这个处理机制通常我们称为处理管道,下面我们将会详细讨论处理管道的内在机制和HttpApplication的多个事件。
1.处理管道
所谓的处理管道,就是处理复杂问题的时候,将处理的过程分解为多个处理步骤,我们将这种经过多个步骤的处理方式称为处理管道。在.NET中,借助于事件的强大威力,我们可以通过处理管道将复杂的处理步骤封装起来,通过事件将处理过程 的多个步骤给程序员以便于程序员对管理管道进行扩展。如下图概述了HttpApplication处理管道的工作过程。

对于一个管道来说,它往往要暴露出大量的事件,通过这些事件,提供程序员的扩展机制。但是,对于一具有着众多事件的类来说,定义大量的事件意味着创建对象的时候需要付出创建事件的成本,因为在.NET中,所谓的事件就是一个受限制的委托成员,定义多个事件,意味着在创建的对象中将会需要更多的存储空间。针对这个问题,在System.ComponentModel.Component类中,提供了处理多个事件的基础:Events属性,它的类型为System.ComponentModel.EventHandlerList,这是一个线性的字典,当需要事件的时候, 就通过key将事件保存到集合中,没有对应的事件,就不会付出创建事件的成本,这样,通过EventHandlerList可以在一个集合中管理多个事件对象,节省对象占用的空间,它的主要成员如下:

在使用的时候,首先从Component派生一个类,这个类将继承Component的Events集合属性。对于这个派生类所需要定义的每一个类,这个类将继承Component的Event集合属性。对于这个派生类所需要定义的每一个事件,在类中定义一个对应的作为Key的对象,以后,通过这个Key对象来访问由Events集合管理的事件。
程序员也可以自己在类中定义一个类似的字典来完成这个任务,并不一定要从Component类中派生。如下
public class ProcessPipeline : System.ComponentModel.Component
{
#region
private static readonly object startEvent = new object();
private static readonly object preProcessEvent = new object();
private static readonly object postProcessEvent = new object();
private static readonly object endEvent = new object();
#endregion #region
public event EventHandler StartProcess
{
add { this.Events.AddHandler(startEvent, value); }
remove { this.Events.RemoveHandler(startEvent, value); }
}
public event EventHandler PreProcess
{
add { this.Events.AddHandler(preProcessEvent, value); }
remove { this.Events.RemoveHandler(preProcessEvent, value); }
}
public event EventHandler PostProcess
{
add { this.Events.AddHandler(postProcessEvent, value); }
remove { this.Events.RemoveHandler(postProcessEvent, value); }
}
public event EventHandler EndProcess
{
add { this.Events.AddHandler(endEvent, value); }
remove { this.Events.RemoveHandler(endEvent, value); }
}
#endregion #region
protected void OnStartProcess(EventArgs e)
{
if (this.Events[startEvent] != null)
{
(this.Events[startEvent] as EventHandler)(this, e);
}
} protected void OnPreProcess(EventArgs e)
{
if (this.Events[preProcessEvent] != null)
{
(this.Events[preProcessEvent] as EventHandler)(this, e);
}
} protected void OnPostProcess(EventArgs e)
{
if (this.Events[postProcessEvent] != null)
{
(this.Events[postProcessEvent] as EventHandler)(this, e);
}
} protected void OnEndProcess(EventArgs e)
{
if (this.Events[endEvent] != null)
{
(this.Events[endEvent] as EventHandler)(this, e);
}
}
#endregion public void Process()
{
Console.WriteLine("开始处理");
this.OnStartProcess(EventArgs.Empty);
Console.WriteLine("准备处理");
this.OnPreProcess(EventArgs.Empty);
Console.WriteLine("下在处理中。。。");
this.OnPostProcess(EventArgs.Empty);
Console.WriteLine("处理结束");
this.OnEndProcess(EventArgs.Empty);
}
}
namespace 自定义事件管道
{
class Program
{
static void Main(string[] args)
{ ProcessPipeline process = new ProcessPipeline();
process.StartProcess
+= new EventHandler(process_StartProcess);
process.StartProcess
+= new EventHandler(process_StartProcess1);
process.StartProcess
-= new EventHandler(process_StartProcess);
process.PreProcess
+= new EventHandler(process_PreProcess);
process.PostProcess
+= new EventHandler(process_PostProcess);
process.EndProcess
+= new EventHandler(process_EndProcess);
process.Process();
Console.ReadLine();
}
static void process_StartProcess(object sender, EventArgs e)
{
Console.WriteLine("开始处理的事件中的处理。。。");
} static void process_StartProcess1(object sender,EventArgs e)
{
Console.WriteLine("开始处理的事件前的事件中的处理1");
} static void process_PreProcess(object sender, EventArgs e)
{
Console.WriteLine("处理前的事件中的处理。。。");
}
static void process_PostProcess(object sender, EventArgs e)
{
Console.WriteLine("正在处理的事件中处理中。。。。");
}
static void process_EndProcess(object sender, EventArgs e)
{
Console.WriteLine("处理完成的事件处理。。。");
}
}
}
在ProcessPipeline类中,定义了4个事件,首先需要注意的是在类中并没有定义4个实际的委托成员来对应事件,通过从Component派生,实际上从基类继承了一个EventHandlerList类型的成员,通过将事件以属性的形式来定义,并映射到EventHandlerList中不管在类中定义了多少个事件,在创建的对象实例中只需要这样一个EventHandlerList的对象来保存事件响应的委托对象。
其次,在Process方法中,模拟了处理的过程,在处理的过程中,通过调用触发事件的On开头的方法,以事件的形式将处理的步骤暴露给程序员。
使用这个类的时候,对于程序员关心的处理事件,可以通过注册事件处理方法到相应的事件上,在ProcessPipeline进行处理的过程中,相应的事件处理方法会被调用。
.NET本质论(4)应用程序对象HttpApplication的更多相关文章
- ASP.NET本质论第二章应用程序对象学习笔记1
1.请求的处理参数—上下文对象HttpContext 1) 针对每一次请求,ASP.NET将创建一个处理这次请求所使用的HttpContext对象实例,这个对象实例将用来在ASP.NET服务器的处理过 ...
- .NET本质论之三(应用程序对象 )
2.1 请求的处理参数------上下文对象HttpContext 现在,请求已经到达了ASP.NET服务器,为了处理请求,ASP.NET在服务器上创建了HttpRequest类型的对象以表示请求 ...
- Application 应用程序对象使用介绍
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="DemoApplicatio ...
- 微信小程序 - 对象转换成对象数组
后端传过来的一个个对象 {1,2,3,4},{1,3,5,},{1,3,5} 我们应该转化为数组对象 [{},{},{},{}] ,最后通过wx:for遍历到页面 示例图:
- 【ASP.NET】必须知道的ASP.NET核心处理
该找工作了,回头复习一下基础知识,增加一下理论知识的理解,下面我们看一下今天要说的. ASP.NET应用程序对象 一.请求的处理参数:上下文对象HttpContext 当一个请求到达ASP.NET服务 ...
- 了解AutoCAD对象层次结构 —— 1 ——应用程序
想象这样一个场景:当您开始一天的工作,坐到电脑前面,用鼠标双击桌面上的AutoCAD Civil 3D图标,这时一个AutoCAD Civil 3D应用程序将运行起来.打开Windows任务管理器,我 ...
- Know the Core Objects of Your App---了解应用程序的内核对象
Back to App Design You develop apps using the Cocoa application environment. Cocoa presents the app’ ...
- asp.net MVC 应用程序的生命周期
下面这篇文章总结了 asp.net MVC 框架程序的生命周期.觉得写得不错,故转载一下. 转载自:http://www.cnblogs.com/yplong/p/5582576.html ...
- 【译】ASP.NET应用程序和页面生命周期
为何翻译此文 一.此文是Code Project社区2010年4月ASP.NET板块的最佳文章,说明了此文的份量: 二.锻炼自己的英文技术文章翻译能力,提高英文技术文档阅读能力: 三.了解掌握ASP. ...
随机推荐
- 黄聪:VS2010每次F5启动都重新编译但是没办法进入断点
这个问题主要是没有把Debug和Realse的生成配置勾上:
- Android Gradle实用技巧——多渠道打包
友盟有很多不错的功能,例如渠道统计等. 想要做渠道统计,有一个要求就是要在manifest文件中添加各个渠道的配置.只有一两个渠道还好说,但是渠道多了的话,手动修改然后打包简直是噩梦. 幸好现在And ...
- System.InvalidOperationException: Sequence contains no elements
foreach (var keyCode in unexpectedKeyCodesDetected) { string unexpected = expectedCapturedKeyCodes.W ...
- Sprite的原点
对于某些类型的游戏,例如飞行射击游戏或者顶视角的2D游戏,通常会直接选取图片的中心做为原点.但对于<冰杖秘闻>这样的 2D ARPG 来说,会更多的从三维场景的角度来选择原点,即选择物品底 ...
- POJ 1155 TELE 背包型树形DP 经典题
由电视台,中转站,和用户的电视组成的体系刚好是一棵树 n个节点,编号分别为1~n,1是电视台中心,2~n-m是中转站,n-m+1~n是用户,1为root 现在节点1准备转播一场比赛,已知从一个节点传送 ...
- Linux命令(20)查看当前网速
Linux查看网络即时网速 sar -n DEV 1 100 1代表一秒统计并显示一次 100代表统计一百次 还可以使用ntop工具
- centos利用cloudflare的bpf-tools实现ddos防护
概念 利用BPF( Berkeley Packet Filter)工具集结合iptables的xt_bpf模块可以实现高性能包过滤,从而应对大规模的ddos攻击.BPF Tools包含一组简单的pyt ...
- Spring的AOP与代理
spring 支持两种注入方式: setter/constructor 支持多种配置方式: xml/java5注解/java类配置 支持两种事务管理: 声明性/编程性 实际上上述方式只有一个就能保证系 ...
- ylbtech-dbs:ylbtech-2,PAM(个人资产管理系统)
ylbtech-dbs:ylbtech-2,PAM(个人资产管理系统) -- =============================================-- Personal Asse ...
- 老师你好。使用cordova生成的hellowold 的安卓5.0版本太高。怎么才可以生成4.4的呢?
你好 在你的应用目录,有个config.xml文件,课程没有介绍每个配置项.你可以增加一项 preference name="android-targetSdkVersion" v ...