码迷,mamicode.com
首页 > Web开发 > 详细

ASP.NET - 请求处理机制浅析

时间:2018-02-04 11:14:43      阅读:211      评论:0      收藏:0      [点我收藏+]

标签:应对   update   插件   []   存储   文件中   freelist   build   factory   

 一些基本概念

1.进程( Process )
//在一定的内存中承载应用程序,一个进程的错误可能造成其它进程的崩溃

2.应用程序域(AppDomain)
//Net程序需要Clr进行托管以保障安全,AppDomain正是Clr创建的区块,Clr利用进程,将其划分为N块逻辑分区
//这些分区就称为AppDomain,一个进程可以被划分成N个AppDomain。
//而.Net程序集通过CLR被载入到某个AppDomain中进行处理,也即AppDomain的作用是用来承载.Net应用程序的,其优势在于以下几点:
*.内存开销
//一个AppDomain的内存开销显著低于进程,而且跨域访问对象的内存开销也要显著低于跨进程访问对象
*.内存控制
//在C#中AppDomain被表示为一个类型,它提供了卸载程序集的方法,
//而Clr正是利用AppDomain进行垃圾回收和对程序集的卸载,开发人员也可以利用AppDomain对.net程序进行内存控制
//一旦程序超载则可以手动AppDomain卸载程序集,卸载后再将程序集重新载入以便降低内存占用。
*.热插拔
//在C#中AppDomain被表示为一个类型,它提供了加载程序集的方法
//把应用程序的某个分离的功能做成一个即插即用的插件,可随时应对客户需求的变更。
*.边界隔离
//一个进程的错误可能带来其它进程的崩溃,
//比如一台服务器开10个进程挂上10个网站应用程序,一个错误就会导致10个网站全军覆没,
//而AppDomain是进程的分区,域的边界隔离机制可以将多个.Net程序隔离,使它们相互独立,
//也即把每个网站程序放在一个进程的10个域中,一个AppDomain出错永远不会影响到其它AppDomain,
//从而不会导致整个进程的崩溃。但可能多个域都需要引用某个公用的程序集,最典型的例子就是MSCorLib.dll。
//该程序集包含了基元类型等重要的.net类型,像这样的程序集不需要跨域访问,
//因为在CLR初始化时就会将这种程序集自动载入一个公共域中,这样,所有的AppDomain都共享该程序集的类型。

3.HTTP通信接口( HTTP.SYS )
//Windows的核心组件,任何基于Windows平台的应用程序都要通过它提供的API接口才能进行HTTP通信

4,应用程序池( Application Pools )
//提供给开发人员管理应用程序的工具,控制应用程序的运行,结束,内存分配,请求最大链接数等

5.工作者进程( w3wp.exe )
//Windows的进程,与应用程序池是相互为用的关系,池管理应用程序,
//而w3wp.exe承载应用程序的运行。两者相互协作,控制应用程序的生命。
//工作者进程下可以划分多个AppDomain域来承载多个web应用程序。
//既然工作者进程总是关联一个应用程序池,
//所以你也可以这样理解:程序池是一个进程,该进程从Cpu中划分了一定的内存,web程序就被限制在程序池中,一个池子可以承载多个web程序的运行。

 

HTTP请求的整个流程

HTTP请求最早由HTTP.SYS接收,接着传递给IIS,请求进入IIS后,IIS会测试该请求所获取的是静态还是动态资源,而早期的web总是以静态的html资源返回给客户端,后来逐渐出现了动态资源,而IIS无法处理这种请求,所以需要一些扩展,通过把请求传递给扩展程序,由扩展程序去处理请求。

静态资源

IIS直接取出html,jpg等资源后往客户端发送。

CGI资源

基于CGI协议的早期通用网关接口,可处理扩展名为cgi的动态资源的请求,如果扩展名为CGI,则IIS会开启cgi.exe进程,执行由c,vb,python,php编写的可执行文件对请求进行处理。

扩展程序

通过IIS提供的配置,可以将扩展程序注册到由IIS管理的扩展程序映射表中,非静态资源的请求进入IIS后,IIS将查找扩展程序映射表,为了便于理解,可以视此表为键值对集合,key是动态资源的扩展名,value是处理请求的扩展程序。处理HTTP请求的常见扩展程序则有以下几种:

1.asp.dll扩展程序,执行由asp编写的可执行文件对请求进行处理。

2.FASTCGI扩展程序,这是CGI进化版的扩展程序,执行由c,vb,python,php编写的可执行文件对请求进行处理。

3.aspnet_isapi.dll扩展程序,可处理各种动态资源的请求,最强。

搭建Clr运行时

IIS确认后缀名所对应的扩展程序后则会通知应用程序池,后者通知w3wp.exe处理Http请求,而w3wp.exe进程会先确认CLR是否已经在运行,如果没有,则将aspnet_isapi.dll载入内存,由aspnet_isapi.dll负责搭建CLR(.Net运行时)。我们知道asp.net的程序集必须通过CLR的即时编译才能转化为cpu指令,才能够处理来自客户端请求的动态资源,所以工作者进程首先得把Clr运行时搭建出来。

创建应用程序域

Clr运行时搭建完成后,将开始创建应用程序域,( 此处需要注意,应用程序域使用的是延迟初始化机制,也即只有当第一个请求进入IIS并被有效传递给工作者进程后,域才会被创建。假如你手动关闭域以此来减轻内存开销,又或者遭遇不可控的因素致使域被关闭,那么当下一个请求被IIS传递给工作者进程后,域又会被重新初始化)。由Clr调用System.Web.Hosting命名空间下的AppDomainFactory的Create方法(.Net.20时代是调用AppManagerAppDomainFactory.Create)在当前工作者进程中创建出AppDomain对象和ISAPIRuntime对象,域创建完成后,工作者进程将把HTTP请求传递给处于域中的ISAPIRuntime对象,而该对象会调用自身的ProcessRequest方法,该方法根据原始的Http报文创建一个从HttpWorkerRequest派生的IsapiWorkerRequest对象,此对象就代表了Http请求的报文信息,接着该方法还会调用HttpRuntime的ProcessRequestNoDemand方法,该方法会调用其它方法,后续一系列的方法调用的逻辑都是为了能创建出HttpContext、HttpContext.Response、HttpContext.Request、HttpApplication、HttpModule和执行Http请求的管道事件,这些方法的部分源码如下: 

//HttpRuntime.ProcessRequestNoDemand的部分源码
//此方法的作用:将Http请求报文对象添加到Http请求队列中
internal static void ProcessRequestNoDemand( HttpWorkerRequest wr )
{
    //RequestQueue是存储IsapiWorkerRequest的队列集合
    //获取Http请求报文的队列集合
    RequestQueue queue = _theRuntime._requestQueue;
    //更新Http请求报文计数器,这将当前的Http请求报文添加到了集合中(个人臆测)
    wr.UpdateInitialCounters( );
    if (queue != null)
    {
        //再从队列中获取当前的Http请求报文
        wr = queue.GetRequestToExecute( wr );
    }
    //ProcessRequestNow方法内部会将IsapiWorkerRequest参数传递给ProcessRequestInternal方法
    ProcessRequestNow( wr );

}

//HttpRuntime.ProcessRequestInternal的部分源码
//此方法的作用:根据Http请求的报文创建HttpContext、HttpContext.Response、HttpContext.Request对象、执行每一个注册好的Http请求的管道事件
private void ProcessRequestInternalHttpWorkerRequest wr )
{
    HttpContext context;
    //根据IsapiWorkerRequest创建HttpContext对象
    //而在HttpContext的构造函数中会创建出Request和Response的实例
    try { context = new HttpContext( wr, false ); }
    catch
    {
        try
        {
            //400错误,请求无效
            wr.SendStatus( 400"Bad Request" );
            //将错误信息输出
            wr.SendKnownResponseHeader( 12"text/html; charset=utf-8" );
            byte[] data = Encoding.ASCII.GetBytes( "<html><body>Bad Request</body></html>" );
            wr.SendResponseFromMemory( data, data.Length );
            wr.FlushResponse( true );
            wr.EndOfRequest( );
            return;
        }
    }

    //GetApplicationInstance方法内部会调用GetNormalApplicationInstance方法
    IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance( context );

    if (applicationInstance is IHttpAsyncHandler)
    {
        //依次执行处理Http请求的管道事件
        handler2.BeginProcessRequest( context, this._handlerCompletionCallback, context );
    }
}

//HttpApplicationFactory.GetNormalApplicationInstance的部分源码
//此方法的作用:创建HttpApplication对象
//此方法内部维护着一个HttpApplication池,从池中取出一个闲置状态的HttpApplication或重新创建一个HttpApplication来处理Http请求
private HttpApplication GetNormalApplicationInstanceHttpContext context )
{
    HttpContext state = null;
    //如果HttpApplication池存在处于闲置状态的HttpApplication则取出一个用于处理请求
    if (this._numFreeAppInstances > 0)
    {
        state = (HttpApplication)this._freeList.Pop( );
        //更新HttpApplication计数器
        this._numFreeAppInstances--;
    }
    //如果池中没有闲置的HttpApplication,则重新创建一个HttpApplication
    else
    {
        state = (HttpApplication)HttpRuntime.CreateNonPublicInstance( this._theApplicationType );
    }
    //InitInternal方法内部会调用InitModules方法
    state.InitInternal( context, this._state, this._eventHandlerMethods );
    return state;
}

//HttpApplicationFactory.InitModules的部分源码
//此方法的作用:初始化Http模块(HttpModule)
private void InitModules( )
{
    //读取注册在Web.config配置文件中的所有HttpModule节信息
    HttpModuleCollection modules = RuntimeConfig.GetAppConfig( ).HttpModules.CreateModules( );
    //HttpModule集合作为HttpApplicationFactory._moduleCollection的成员被使用
    this._moduleCollection = modules;
    //初始化所有HttpModule对象
    this.InitModulesCommon( );
    //注册ASP.NET的19个用于处理Http请求的管道事件
    this._stepManager.BuildSteps( this._resumeStepsWaitCallback );
}

 

  

 

 

 

 

 

 

 

 

 

 

 

 关闭域:httpruntime.unloadappdomain

客户端请求的动态资源的url原本是类似于以下形式
HTTP://Server_name/ISAPI.dll/File_name.aspx
经过IIS的优化,才变成了我们熟悉的方式
HTTP://Server_name/File_name.aspx

 未证实

 

待续……

 

Visual Studio包含ISAPI向导加快开发

ASP.NET - 请求处理机制浅析

标签:应对   update   插件   []   存储   文件中   freelist   build   factory   

原文地址:https://www.cnblogs.com/myrocknroll/p/8409400.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!