ASP.NET运行时详解 生命周期入口分析
说起ASP.NET的生命周期,网上有很多的介绍。之前也看了些这方面的博客,但我感觉很多程序猿像我一样,看的时候似乎明白,一段时间过后又忘了。所以,最近Heavi花了一段时间研究ASP.NET的源代码,通过代码层面来掌握ASP.NET的生命周期。分析的代码版本是ASP.NET 5。
生命周期入口HttpRunTime
在HttpRunTime中Http请求的入口处理流程比较复杂,说简单一点就是为后面的处理流程提供两个参数:IIS7WorkerRequest和HttpContext。这两个参数生成后直接调用HttpRuntime.ProcessRequestNotification(wr, httpContext)方法,执行Http请求的整个流程。
所以,我们从ProcessRequestNotificationPrivate方法开始分析。代码如下:private RequestNotificationStatus ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context)
{
RequestNotificationStatus pending = RequestNotificationStatus.Pending;
if (context.NeedToInitializeApp())
{
context.Response.InitResponseWriter();
applicationInstance = HttpApplicationFactory.GetApplicationInstance(context);
HttpApplication application = applicationInstance as HttpApplication;
if (application != null)
{
application.AssignContext(context);
}
}
wr.SynchronizeVariables(context);
if (context.ApplicationInstance != null)
{
if (context.ApplicationInstance.BeginProcessRequestNotification(context, this._requestNotificationCompletionCallback).CompletedSynchronously)
{
pending = RequestNotificationStatus.Continue;
}
}
else if (applicationInstance != null)
{
applicationInstance.ProcessRequest(context);
pending = RequestNotificationStatus.FinishRequest;
}
else
{
pending = RequestNotificationStatus.Continue;
} if (pending != RequestNotificationStatus.Pending)
{
this.FinishRequestNotification(wr, context, ref pending);
}
return pending;
}这个方法里边包含的主要流程有:
1. 初始化运行环境:EnsureFirstRequestInit。确认应用是否是第一次请求,如果是需要初始化运行环境,包括初始化Configuration、应用程序池、加载Bin下的Dll等。
2. 初始化Response对象:context.Response.InitResponseWriter。
3. 初始化Application对象:HttpApplicationFactory.GetApplicationInstance(context)。
4. 执行请求过程:context.ApplicationInstance.BeginProcessRequestNotification。
5. 完成请求通知:FinishRequestNotification。
对于上面的主要流程,我用流程图表示可能更直观些。流程图如下所示:
知道了上面的5个主要步骤,接下来就详细的介绍每个步骤执行的具体内容。
初始化运行环境
通过执行EnsureFirstRequestInit方法来初始化我们整个应用的运行环境,那具体初始化了哪些操作?我们先查看下方法的源代码:
private void EnsureFirstRequestInit(HttpContext context)
{
if (this._beforeFirstRequest)
{
lock (this)
{
if (this._beforeFirstRequest)
{
this._firstRequestStartTime = DateTime.UtcNow;
this.FirstRequestInit(context);
this._beforeFirstRequest = false;
context.FirstRequest = true;
}
}
}
}
代码就那么寥寥几行,很明显的看出源代码里边最主要的一行就是:this.FirstRequestInit(context)。也就是说初始化运行环境实际是在这个方法里边执行的。我把FirstRequestInit方法里边的代码简单归纳了一下,下面是比较核心的代码流程:
1. 初始化WEB配置:InitHttpConfiguration()。
我们经常从ConfigurationManager的AppSettings和ConnectionStrings读取配置信息,这些配置信息就是InitHttpConfiguration方法从IIS环境和WEB环境下读取到内存提供给程序使用。
2. 临时文件夹写权限判断:CheckAccessToTempDirectory()。
简单理解就是整个WEB环境在运行时需要保存某些文件到临时文件夹里边,所以必须保证我们的WEB环境有临时文件夹的写权限。
3. 初始化请求队列:InitRequestQueue()。
按照服务器CPU环境自动或手动配置请求进程队列的限制,如果需要手动配置可在Web.config中配置ProcessModelSection部分。
4. 健康监测系统运行环境:HealthMonitoringManager.StartHealthMonitoringHeartbeat()。
启动一个计时器,定时检测编译错误、未处理异常、登录失败等信息,并记录到Windows事件日志、SQL Server数据库以及Trace输出窗口等。我们可以通过在Web.config中配置HealthMonitoringSection模块来初始化检测机制。
5. 约束IIS文件夹:RestrictIISFolders(context)。
执行ISAPI接口的函数(具体是执行什么操作,目前还不清楚)。
6. 加载Bin下面的程序集:PreloadAssembliesFromBin()。
加载Bin以及Bin下的子目录的所有程序集。
7. 请求标头检查,防止注入攻击:this.InitHeaderEncoding()。运行环境初始化过程流程图如下:
初始化Response对象
该步骤就一个操作,初始化我们常用到的Reponse.Output输出对象。
初始化Application对象
执行HttpApplicationFactory工厂的GetApplicationInstance方法初始化Application对象。先把代码贴出来:
internal static IHttpHandler GetApplicationInstance(HttpContext context)
{
//…省略其他代码
_theApplicationFactory.EnsureInited();
_theApplicationFactory.EnsureAppStartCalled(context);
return _theApplicationFactory.GetNormalApplicationInstance(context);
}
代码第一行执行工厂的EnsureInited方法,获取global.asax文件所在路径,然后编译它。编译后启动检测,查看global.asax文件是否有更新,如果有更新WEB应用会被停止。
代码第二行执行工厂方法EnsureAppStartCalled(context),创建特别的HttpApplication实例,触发ApplicationOnStart事件,执行global_asax中的Application_Start事件,新建的特别的HttpApplication实例在处理完事件后就被回收。
代码第三行执行工厂方法GetNormalApplicationInstance(context),创建我们在WEB应用中经常用到的Application对象。既然是我们经常用到的Application对象,那么GetNormalApplicationInstance方法里边应该不仅仅是简单的创建步骤。我们先看下GetNormalApplicationInstance方法的代码:private HttpApplication GetNormalApplicationInstance(HttpContext context)
{
HttpApplication state = null;
lock (this._freeList)
{
if (this._numFreeAppInstances > )
{
state = (HttpApplication)this._freeList.Pop();
this._numFreeAppInstances--;
if (this._numFreeAppInstances < this._minFreeAppInstances)
{
this._minFreeAppInstances = this._numFreeAppInstances;
}
}
}
if (state == null)
{
state = (HttpApplication)HttpRuntime.CreateNonPublicInstance(this._theApplicationType);
using (new ApplicationImpersonationContext())
{
state.InitInternal(context, this._state, this._eventHandlerMethods);
}
}
return state;
}
这段代码我们必须得分析下,这里包含了我们经常说的“应用程序池“,体现在代码里边就是_freeList集合,在获取Application对象时,先从_freeList查找空闲的Application对象,如果有就直接返回一个空闲对象;如果没有则执行HttpRuntime.CreateNonPublicInstance(this._theApplicationType)方法创建一个Application对象,创建之后调用InitInternal方法执行初始化操作。
InitInternal方法比较重要,它初始化了我们的HttpModules,并且构建了Http请求的20多个管道执行步骤。InitInternal方法执行的具体内容比较庞大,我会单独分一个章节来介绍。但要提出一点,该方法为我们创建了具体的管道管理对象StepManager,该对象在下一个”执行请求过程“步骤中会用到。
执行请求过程
初始化操作执行完了就该处理我们的请求了,Application对象的BeginProcessRequestNotification方法包含了请求的处理过程。看下代码:
internal IAsyncResult BeginProcessRequestNotification(HttpContext context, AsyncCallback cb)
{
if (this._context == null)
{
this.AssignContext(context);
}
context.CurrentModuleEventIndex = -;
HttpAsyncResult result = new HttpAsyncResult(cb, context);
context.NotificationContext.AsyncResult = result;
this.ResumeSteps(null);
return result;
}
方法创建HttpAsyncResult对象,保存了我们的回调事件。等ResumeSteps方法执行完后再回调HttpAsyncResult的事件。接下来看看ResumeSteps方法的具体内容。代码比较简单,如下所示:
private void ResumeSteps(Exception error)
{
this._stepManager.ResumeSteps(error);
}代码里边有一个_stepManager对象,在上一个步骤“初始化Application对象”中我们有提到StepManager,StepManager实体对象也是在那个步骤中被创建的。ResumeSteps方法启动了Http请求执行管道的20多个步骤。那么,StepManager到底包含哪些内容?我们查看下他的定义:
internal abstract class StepManager
{
internal abstract void BuildSteps(WaitCallback stepCallback);
internal abstract void InitRequest();
internal abstract void ResumeSteps(Exception error);
}StepManager是一个抽象类,定义了三个抽象方法,BuildSteps(构建步骤)和ResumeSteps(执行步骤)我们已经知道了,InitRequest用来初始化请求信息。StepManager总共有两个实现类:ApplicationStepManager和PipelineStepManager。ApplicationStepManager是IIS6以及IIS7经典模式执行步骤管理对象,PipelineStepManager是IIS7的执行步骤管理
对象。这两个对象会在下一章节详细介绍。完成请求通知
FinishRequestNotification主要做善后工作,代码如下:
private void FinishRequestNotification(IIS7WorkerRequest wr, HttpContext context, ref RequestNotificationStatus status)
{
HttpApplication applicationInstance = context.ApplicationInstance;
context.ReportRuntimeErrorIfExists(ref status);
IntPtr requestContext = wr.RequestContext;
bool sendHeaders = UnsafeIISMethods.MgdIsLastNotification(requestContext, status);
try
{
context.Response.UpdateNativeResponse(sendHeaders);
}
catch (Exception exception)
{
}
if (sendHeaders)
{
context.FinishPipelineRequest();
}
if (status != RequestNotificationStatus.Pending)
{
PipelineRuntime.DisposeHandler(context, requestContext, status);
}
}
从代码可以看出FinishRequestNotification方法记录运行时异常,调用context.FinishPipelineRequest方法完成整个请求、释放Request、Response以及Application对象。
总结
通过上面几个步骤的分析,请求的入口是在HttpRuntime。第一次Http请求发生后,HttpRuntime初始化整个WEB环境,然后通过HttpApplication的工厂类HttpApplicationFactory创建HttpApplication。HttpApplication实体对象通过StepManager的BuildSteps方法构建请求管道(Pipeline)步骤,然后通过ResumeSteps方法执行管道所有的事件。
下一章节主要介绍管Pipeline步骤的构建和执行细节以及页面的生命周期,敬请期待!
ASP.NET运行时详解 生命周期入口分析的更多相关文章
- ASP.NET运行时详解 集成模式和经典模式
遗留问题 在<ASP.NET运行时详解 生命周期入口分析>中遗留两个问题,包括Application的InitInternal方法执行细节.IIS6和II7经典模式请求管道管理类Appli ...
- ASP.NET 运行时详解 揭开请求过程神秘面纱
对于ASP.NET开发,排在前五的话题离不开请求生命周期.像什么Cache.身份认证.Role管理.Routing映射,微软到底在请求过程中干了哪些隐秘的事,现在是时候揭晓了.抛开乌云见晴天,接下来就 ...
- ASP.NT运行原理和页面生命周期详解及其应用
ASP.NT运行原理和页面生命周期详解及其应用 1. 下面是我画的一张关于asp.net运行原理和页面生命周期的一张详解图.如果你对具体不太了解,请参照博客园其他帖子.在这里我主要讲解它的实际应用. ...
- 微信小程序开发之详解生命周期方法
生命周期是指一个小程序从创建到销毁的一系列过程 在小程序中 ,通过App()来注册一个小程序 ,通过Page()来注册一个页面 先来看一张小程序项目结构 从上图可以看出,根目录下面有包含了app.js ...
- Activity详解生命周期(Android)
Activity是Android组件中最基本也是最为常见用的四大组件(Activity,Service服务,Content Provider内容提供者,BroadcastReceiver广播接收器)之 ...
- Tomcat源码分析 | 一文详解生命周期机制Lifecycle
目录 什么是Lifecycle? Lifecycle方法 LifecycleBase 增加.删除和获取监听器 init() start() stop() destroy() 模板方法 总结 前言 To ...
- iOS 运行时详解
注:本篇文章转自:http://www.jianshu.com/p/adf0d566c887 一.运行时简介 Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行 ...
- ASP.NET 运行机制详解
1.浏览器和服务器的交互原理 通俗描述:我们平时通过浏览器来访问网站,其实就相当于你通过浏览器去访问一台电脑上访问文件一样,只不过浏览器的访问请求是由被访问的电脑上的一个 WEB服务器软件来接收处理, ...
- asp.net MVC 应用程序的生命周期
下面这篇文章总结了 asp.net MVC 框架程序的生命周期.觉得写得不错,故转载一下. 转载自:http://www.cnblogs.com/yplong/p/5582576.html ...
随机推荐
- PCM音频设备的操作(转)
对音频设备的操作主要是初始化音频设备以及往音频设备发送 PCM(Pulse Code Modulation)数据.为了方便,本文使用 ALSA(Advanced Linux Sound Archite ...
- liunx 服务内存消耗100% 怎么处理
一.排查问题 查看内存使用 free 查看进程使用存储状况.看是不是业务进程在消耗存储,如果是就要优化业务代码了 使用top 命令 如果不是怎么办 二.处理办法 1.把没有用到的消耗内存的服务进程 ...
- Navi.Soft30.开放平台.百度.开发手册
1系统简介 1.1功能简述 现在是一个信息时代,并且正在高速发展.以前获取信息的途径非常少,可能只有电视台,收音机等有限的来源,而现在的途径数不胜数,如:QQ,微信,官方网站,个人网站等等 本开发手册 ...
- windows7系统下如何安装windows xp系统(无法识别硬盘,删除隐藏分区)
一.硬盘模式的设置 要设置好硬盘模式,否则安装操作系统的时候,根本就不识别硬盘,自然无法安装操作系统了.此步骤主要是解决无法识别硬盘的问题. 首先,进入BIOS当中,一般在advanced当中,有一个 ...
- 【原创】开源BI领袖-SpagoBI5.X最详细的中文版介绍
SpagoBI是唯一100%的开源商业智能套件由 Engineering Group的SpagoBI实验室(www.eng.it)开发和管理.它提供了强大的分析能力,从传统的报表和图表功能到自助分析. ...
- [原]OpenGL基础教程(四)VBO+纹理绘制四边形
工程下载地址:http://pan.baidu.com/s/1ntr7NHv 提取码:yf1h 一.本文牵扯知识点梳理: (1)VBO (2)纹理 (3)libpng(加载png) (4)shader ...
- java-cef系列视频第四集:自定义协议
上一集我们介绍了如何为java-cef添加flashplayer支持. 本视频介绍java-cef中的自定义协议 本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 中国大陆许可协议进行许可.
- CSS - Select 标签在不同浏览器中的高度设置
当使用Select标签时,在不同浏览器中显示的高度不同,如何解决此问题: 解决方法链接:http://stackoverflow.com/questions/20477823/select-html- ...
- 顺序图(Sequence Diagram)
顺序图(Sequence Diagram)对系统的动态方面来建模. 顺序图是强调消息时间顺序的交互图. 协作图则是强调接收和发送消息的对象的结构组织的交互图 如何对动态方面建模? 所谓动态文面,即 ...
- MVC学习中遇到问题
1:无法连接到localdb数据库 解决方案:下载localdb安装软件 2:运行程序时提示数据库已存在,请更改连接名 解决方案:因为在两个不同的解决方案中使用了同样的连接字符串造成生成了同样的数据库 ...

