概述:

本文基于ASP.NET 2.0的源代码,对ASP.NET 2.0运行时进行了简要的分析,希望能帮助你理解ASP.NET 2.0中请求处理过程及页面编译模型。

关键字:

ASP.NET 2.0运行时,原理,请求处理,页面编译,ASP.NET 2.0 HTTP Runtime

主要类:

System.Web.HttpRuntime

System.Web.HttpApplicationFactory

System.Web.HttpApplication

System.Web.Compilation.BuildManager

System.Web.Compilation.ApplicationBuildProvider

System.Web.Compilation.BuildProvidersCompiler

System.Web.UI.PageHandlerFactory

请求处理简要流程图:

 

阅读建议:

用Reflector工具边查看ASP.NET 2.0的源代码边阅读。

分析:

当我们通过浏览器向ASP.NET 2.0网站的一个asp.net页面发起请求时,在服务器端首先是IIS收到请求,IIS一看是asp.net页面,心里很开心,因为这个请求不用它处理,交给ASP.NET ISAPI就行了。ASP.NET ISAPI的工作也比较轻松,他的主要任务就是安排aspnet_wp.exe处理请求,并监视aspnet_wp.exe进程的执行情况,如果aspnet_wp.exe进程太累了,不能出色地完成任务,ASP.NET ISAPI就要让他下岗,换一个新的aspnet_wp.exe来处理工作。

aspnet_wp.exe的主要任务是将请求交给一系列称为的 HTTP 管道的托管对象。如果把ASP.NET ISAPI比做销售经理,那aspnet_wp.exe就是生产经理,而HTTP 管道就是生产的流水线。负责流水线的小组就是HttpRuntime,生产经理aspnet_wp.exe会将订单(HTTP请求)交给HttpRuntime小组的工作人员ProcessRequest(HttpWorkerRequest wr),HttpRuntime根据内部的分工,最终由ProcessRequestInternal(HttpWorkerRequest wr)在流水线上进行生产,所以ProcessRequestInternal(HttpWorkerRequest wr)是我们分析的重点。

ProcessRequestInternal的主要工作是:

1. 创建HttpContext实例。

2. 对第一次请求进行初始化(EnsureFirstRequestInit)。

a) 在EnsureFirstRequestInit中通过调用System.Web.HttpRuntime.FirstRequestInit进行一些初始化工作,比如:将Web.Config配置读到到RuntimeConfig中,从bin目录中装载所有dll文件。

3. 创建HttpWriter实例。

4. 通过调用HttpApplicationFactory.GetApplicationInstance创建HttpApplication实例。

在HttpApplicationFactory.GetApplicationInstance中有三个关键方法:

HttpApplicationFactory._theApplicationFactory.EnsureInited();

HttpApplicationFactory._theApplicationFactory.EnsureAppStartCalled(context);

HttpApplicationFactory._theApplicationFactory.GetNormalApplicationInstance(context);

下面我们对这三个方法逐个进行分析:

1) HttpApplicationFactory._theApplicationFactory.EnsureInited();

该方法检查HttpApplicationFactory是否被初始化,如果没有,就通过HttpApplicationFactory.Init()进行初始化。

在Init()中,先获取global.asax文件的完整路径,然后调用CompileApplication()对global.asax进行编译。

那编译是如何进行的呢?

编译的工作由BuildManager完成的。BuildManager先得到GlobalAsaxType(也就是HttpApplication),然后调用BuildManager.GetGlobalAsaxBuildResult()=》GetGlobalAsaxBuildResultInternal()=》EnsureTopLevelFilesCompiled()进行编译。

在EnsureTopLevelFilesCompiled中,先进行CompilationStage.TopLevelFiles编译,对下面三个目录中的文件进行编译:

a. CompileResourcesDirectory();

编译App_GlobalResources目录。

b. CompileWebRefDirectory();

编译App_WebReferences目录。

c. CompileCodeDirectories();

编译App_Code目录。

接着进行CompilationStage.GlobalAsax 编译,对global.asax进行编译,方法调用情况:CompileGlobalAsax()=》ApplicationBuildProvider.GetGlobalAsaxBuildResult(BuildManager.IsPrecompiledApp)。

在GetGlobalAsaxBuildResult中具体的编译是由ApplicationBuildProvider与BuildProvidersCompiler共同完成的。

BuildProvidersCompiler.PerformBuild();进行编译工作。

ApplicationBuildProvider.GetBuildResult得到编译的结果。

编译成功后,会在C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\相应的目录中生成类似App_global.asax.mlgx7n2v.dll的dll文件。

编译生成的类名为ASP.global_asax,继承自HttpApplication。

注:如果Web目录中没有Global.asax文件,就不会编译生成App_global.asax.mlgx7n2v.dll这样的文件。

2) HttpApplicationFactory._theApplicationFactory.EnsureAppStartCalled(context);

创建特定的HttpApplication实例,触发ApplicationOnStart事件,执行ASP.global_asax中的Application_Start(object sender, EventArgs e)方法。这里创建的HttpApplication实例在处理完事件后,就被回收。

3) HttpApplicationFactory._theApplicationFactory.GetNormalApplicationInstance(context);

该方法创建HttpApplication实例并进行初始化(调用System.Web.HttpApplication. InitInternal()方法)。

创建HttpApplication实例是根据实际的_theApplicationType进行创建。如果Web目录中没有global.asa文件,也就是说没有动态编译生成ASP.global_asax类型,那就直接实例化HttpApplication。如果创建了ASP.global_asax类型,那就对ASP.global_asa进行实例化。

创建HttpApplication实例之后就是调用实例的InitInternal方法。

InitInternal方法也是我们重点分析的方法,该方法的主要功能如下:

1. InitModules():根据Web.Config的设置,创建相应的HttpModules。

2. HookupEventHandlersForAppplicationAndModules:根据发生的事件,调用HttpApplication实例中相应的事件处理函数。

3. 创建很多实现IExecutionStep接口的类的实例并添加到当前HttpApplication实例的_execSteps中,等待回调时执行。从这里我们可以看到HttpApplication是以异步的方式处理请求,对请求的很多处理工作都放入了_execStep等待回调时执行。

_execStep中主要的处理工作如下:

1) 对请求的路径进行安全检查,禁止非法路径访问(ValidatePathExecutionStep)。

2) 如果设置了UrlMappings, 进行RewritePath(UrlMappingsExecutionStep)。

3) 执行事件处理函数,比如:BeginRequest、AuthenticateRequest等等。

4) 获取处理当前请求的HttpHandler,ASP.NET页面的动态编译也是在这里进行的。(MapHandlerExecutionStep)

该处理是通过调用System.Web.HttpApplication. MapHttpHandler方法。

在MapHttpHandler中,首先根据访问的地址从web.config获取相应的实现IHttpHandlerFactory的类型。对于asp.net页面,默认是PageHanlderFactory。然后创建PageHanlderFactory实例,调用GetHandlerHelper,在GetHandlerHelper中调用BuildManager.CreateInstanceFromVirtualPath编译并创建当前请求的ASP.NET页面的实例(如果已经编译过,直接从缓存中加载)。

CreateInstanceFromVirtualPath经过几次方法调用,将编译任务给了BuildManager. CompileWebFile()。CompileWebFile从web.config得到相应的BuildProvider,对于.aspx文件,相应的BuildProvider是PageBuildProvider。PageBuildProvider是如何进行页面编译的,这里就不再就进一步分析了,如果你感兴趣,可以进一步研究ASP.NET 2.0的源代码。

5) 调用相应HttpHandler的.ProcessRequest方法处理请求(如果是异步方式,调用BeginProcessReques)。(CallHandlerExecutionStep)

6) 将响应内容写入Filter。(CallFilterExecutionStep)

5. 调用HttpApplication实例的BeginProcessRequest异步处理请求。

上面所讲的_execSteps中所发生的许多事情,都是在HttpRuntime调用HttpApplication BeginProcessRequest之后,在BeginProcessRequest中调用ResumeSteps后执行的。

ASP.NET 2.0运行时是ASP.NET 2.0中非常复杂、难以理解也是很重要的部分,对ASP.NET 2.0运行时源代码的研究有处于我们加深对ASP.NET 2.0原理的理解,会给我们开发ASP.NET 2.0应用程序带来不少帮助。这篇文章是我初次学习ASP.NET 2.0运行时,为了帮助自己更好地理解ASP.NET 2.0运行时而写的,欢迎你对文章内容提出批评与建议。

我觉得写文章,不仅能提高自己的写作水平、方便交流,而且通过写文章,可以理清自己的思路、促进自己深入地思考从而加深自己对技术的理解,开发人员在编码之余抽点时间写些技术文章对提高自己还是很有帮助的。

ASP.NET 2.0运行时简要分析相关推荐

  1. 将asp.net webapi的运行时版本由4.0升级到4.5.1时遇到的问题及解决

    将asp.net webapi的运行时版本由4.0升级到4.5.1时遇到的问题及解决 参考文章: (1)将asp.net webapi的运行时版本由4.0升级到4.5.1时遇到的问题及解决 (2)ht ...

  2. Android8.0运行时权限策略变化和适配方案

    版权声明:转载必须注明本文转自严振杰的博客:http://blog.yanzhenjie.com Android8.0也就是Android O即将要发布了,有很多新特性,目前我们可以通过Android ...

  3. Android 8.0 运行时权限策略变化和适配方案

    Android8.0也就是Android O即将要发布了,有很多新特性,目前我们可以通过AndroidStudio3.0 Canary版本下载Android O最新的系统映像的Developer Pr ...

  4. Android 8.0学习(18)--- Android8.0运行时权限策略变化和适配方案

    Android8.0运行时权限策略变化和适配方案    在 Android O 之前,如果应用在运行时请求权限并且被授予该权限,系统会错误地将属于同一权限组并且在清单中注册的其他权限也一起授予应用.对 ...

  5. 获取权限android sync,GitHub - AndSync/XPermissionUtils: 可能是最精简的Android6.0运行时权限处理方式,支持Rationale提示...

    # XPermissionUtils 可能是最精简的Android6.0运行时权限处理方式,支持Rationale提示,只有一个类,100行代码,所有弹窗等操作由用户自行处理,在Demo中也有提供代码 ...

  6. 这可能是最精简的Android6.0运行时权限处理,百行代码的工具类,支持Rationale,附:各种权限详细处理

    0x00:前言 对于Android6.0运行时权限的处理方式网上有很多,包括注解,RxJava等等.一直没有正面提到我关心的问题–如果我不在Activity或者Fragment里面,需要运行时权限该怎 ...

  7. .net4.0运行时安装说明(xp,win7,win10)

    概述 现在大多windows桌面版的系统都是使用.net开发,所以我们整理了一下目前流行的.net4.0运行时的安装说明. win 10 (1511)以上(含)系统不需要安装. win7系统需要安装, ...

  8. Android6.0运行时权限解决方案

    今天在测试APP的时候发现部分手机APP定位权限使用不了.看了一下机型都是Android6.0以上版本的Android手机. 之前就听说Android6.0以上版本权限管理更严格了,没想到今天踩坑了. ...

  9. 06JVM运行时内存分析

    程序计数器 概述 程序计数器(Program Counter Register)也称之为PC寄存器,是一块较小的内存空间,用来存储指向下一条指令的地址,也可以看作是当前线程执行的字节码的行号指示器. ...

最新文章

  1. 只让输入数字、字母、中文的输入框
  2. 靶场练习第二十二天~vulnhub靶场之Momentum-2
  3. 5月第二周全球五大顶级域名总量新增10.5万个
  4. Oracle分区表之创建维护分区表索引的详细步骤
  5. MyBatis的动态SQL详解nbsp;(转载)
  6. 数电educoder的verilog参考答案
  7. HTML页面浏览历史,浏览历史记录功能
  8. 关闭android系统自动更新,彻底关闭魅族flyme系统自动更新的方法分享
  9. 远程接入Linux、unix、Windows工具-opentext ETX
  10. App个人信息保护管理暂行规定即将出台
  11. 秋招一个半月流水账+招银网路科技offer
  12. linux文件误删恢复debugfs和extundelete
  13. 关于linux网络编程的项目,linux网络编程入门
  14. x64dbg 自动化控制插件
  15. 20款免费的WordPress企业站主题下载
  16. 多元统计分析——各类图的具体应用(数据可视化)
  17. java ?: 三目运算符
  18. vscode 实用插件
  19. Linux 线程基础 1
  20. win10怎么显示文件后缀名

热门文章

  1. warning modified in the future
  2. java 基础知识总结
  3. CentOS7—HAProxy安装与配置
  4. MyBatis 实践 -动态SQL/关联查询
  5. Arcgis for JS扩展GraphicLayer实现区域对象的聚类统计与展示
  6. 关于GCC Cygwin MinGW MSYS
  7. 2.struts1.x中的异常处理
  8. 8051单片机指令和寻址方式
  9. android service中显示一个dialog
  10. http请求curl