IIS与NET桥梁

   注: 以下理论是针对ASP.NET的

  

       IIS与net是如何建立联系的?是通过ASPNET_ISAPI.dll这个文件建立联系的,那么这个dll在什么地方?在C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll中,不同的.net版本,aspnet_isapi.dll不同。

       那么ASPNET_ISAPI.dll是怎么衔接IIS与net的呢?

      首先由ASPNET_ISAPI.dll中的ISAPIRuntime实例调用ProcessRequest方法,这个方法接收一个ECB(非托管对象,其中包含着所有底层的请求信息如服务器变量,HTTP输入流,HTTP输出流等)和一个服务器类型参数 iWRType(这个参数用于指定创建何种版本的ISAPIWorkerRequest),然后把它传给了ISAPIWorkerRequest对象,这个对象负责创建一个表示当前请求的HttpWorkerRequest对象。其中ISAPIWorkerRequest是一个继承自HttpWorkerRequest的抽象类(HttpWorkerRequest也是抽象类)针对不同的IIS版本,具有不同的ISAPIWorkerRequest子类,比如:ISAPIWorkerRequestOutOfProc(IIS 5.x),ISAPIWorkerRequestInProcForIIS6 ,ISAPIWorkerRequestInProcForIIS7。

ProcessRequest通过ISAPI传入的 iWRType 来创建不同HttpWorkerRequest,从而屏蔽了不同IIS的差异,这样后续的操作就不需要考虑这种差异了。

//IntPtr表示的是指针,不同语言间通信是通过指针进行通信的,就是所谓的com组件,这个地址传的是浏览器传进来的数据,最后把数据封装成HttpWorkerRequest对象

public int ProcessRequest(IntPtr ecb, int iWRType)
{
   
int num;
   
try
   
{
HttpWorkerRequest wr
= ISAPIWorkerRequest.CreateWorkerRequest(ecb, iWRType);
       
string appPathTranslated = wr.GetAppPathTranslated();
       
string appDomainAppPathInternal = HttpRuntime.AppDomainAppPathInternal;
       
if ((appDomainAppPathInternal == null) || StringUtil.EqualsIgnoreCase(appPathTranslated, appDomainAppPathInternal))
       
{//这里开始便把请求的处理流程就交给了HttpRuntime
            HttpRuntime.ProcessRequestNoDemand(wr);
       
//在ProcessRequestNoDemand方法中所有的HTTP请求会被排成一个队列,顺次执行,并且最终会引发ProcessRequestInternal(HttpWorkerRequest wr)方法
            return 0;
        }

        HttpRuntime.ShutdownAppDomain(ApplicationShutdownReason.PhysicalApplicationPathChanged, SR.GetString(
"Hosting_Phys_Path_Changed", new object[] { appDomainAppPathInternal, appPathTranslated }));
        num
= 1;
    }

   
catch (Exception exception)
   
{
        Misc.ReportUnhandledException(exception,
new string[] { SR.GetString("Failed_to_process_request") });
       
throw;
    }

   
return num;
}

 

  由上面的代码中大家可以看出最终是调用了ProcessRequestInternal方法,这个方法很重要,我们来看一下它主要做了些什么。

 

private void ProcessRequestInternal(HttpWorkerRequest wr)
{
    HttpContext extraData
= new HttpContext(wr, false);
    wr.SetEndOfSendNotification(
this._asyncEndOfSendCallback, extraData);
    Interlocked.Increment(
ref this._activeRequestCount);
    HostingEnvironment.IncrementBusyCount();
   
try
    {
       
try
        {
           
this.EnsureFirstRequestInit(extraData);
        }
       
catch
        {
           
if (!extraData.Request.IsDebuggingRequest)
            {
               
throw;
            }
        }
        extraData.Response.InitResponseWriter();
        IHttpHandler applicationInstance
= HttpApplicationFactory.GetApplicationInstance(extraData);
       
if (applicationInstance == null)
        {
           
throw new HttpException(SR.GetString("Unable_create_app_object"));
        }
       
if (EtwTrace.IsTraceEnabled(5, 1))
        {
            EtwTrace.Trace(EtwTraceType.ETW_TYPE_START_HANDLER, extraData.WorkerRequest, applicationInstance.GetType().FullName,
"Start");
        }
       
if (applicationInstance is IHttpAsyncHandler)
        {
            IHttpAsyncHandler handler2
= (IHttpAsyncHandler) applicationInstance;
            extraData.AsyncAppHandler
= handler2;
            handler2.BeginProcessRequest(extraData,
this._handlerCompletionCallback, extraData);
        }
       
else
        {
            applicationInstance.ProcessRequest(extraData);
           
this.FinishRequest(extraData.WorkerRequest, extraData, null);
        }
    }
   
catch (Exception exception)
    {
        extraData.Response.InitResponseWriter();
       
this.FinishRequest(wr, extraData, exception);
    }
}

 

 

 1. 首先检查当前HttpRuntime实例是否第一次被调用,如果是第一次调用则通过FirstRequestInit函数创建并初始化核心对象HttpContext。
          HttpContext 类包含特定于当前应用程序请求的对象,如 HttpRequest 和 HttpResponse 对象。
HttpRequest 对象包含有关当前请求的信息,包括 Cookie 和浏览器信息。HttpResponse 对象包含发送到客户端的响应,包括所有呈现的输出和 Cookie。    
      2.调用HttpResponse.InitResponseWriter函数初始化页面请求的返回对象HttpWorkerRequest.Response。

      3.通过调用HttpApplicationFactory.GetApplicationInstance创建HttpApplication 类的实例并最终调用HttpApplication实例的InitInternal方法启动应用程序。
    
      HttpApplication实例在InitInternal调用后,首先初始化Web.Config中注册的所有模块(HttpModule事件处理器,这个大家要尤其记住,因为我们真正开始编写代码的话,主要就是在这个模块中编写),然后调用HttpApplication 类的 Init 方法。接着会依次引发以下事件。

1.引发 BeginRequest 事件,该事件始终是请求处理期间发生的第一个事件。
2.引发 AuthenticateRequest 事件。
3.引发 PostAuthenticateRequest 事件。
4.引发 AuthorizeRequest 事件。
5.引发 PostAuthorizeRequest 事件。
6.引发 ResolveRequestCache 事件。
7.引发 PostResolveRequestCache 事件。
8.根据所请求资源的文件扩展名(在应用程序的配置文件中映射),选择实现 IHttpHandler 的类,对请求进行处理。如果该请求针对从 Page 类派生的对象(页),并且需要对该页进行编译,则 ASP.NET 会在创建该页的实例之前对其进行编译。
9.引发 PostMapRequestHandler 事件。
10.引发 AcquireRequestState 事件。
11.引发 PostAcquireRequestState 事件。
12.引发 PreRequestHandlerExecute 事件。
13.为该请求调用合适的 IHttpHandler 类的 ProcessRequest 方法(或异步版 BeginProcessRequest)。例如,如果该请求针对某页,则当前的页实例将处理该请求。
14.引发 PostRequestHandlerExecute 事件。 15.引发 ReleaseRequestState 事件。
16.引发 PostReleaseRequestState 事件。
17.如果定义了 Filter 属性,则执行响应筛选。
18.引发 UpdateRequestCache 事件。
19.引发 PostUpdateRequestCache 事件。
20.引发 EndRequest 事件。


        由上面第8个事件可以看出,页面在这个步骤被编译并创建了当前所请求的ASP.NET页面的实例(如果已经编译过,直接从缓存中加载)。

最后再来回顾一下:

1.首先由inetinfo.exe接收到HTTP请求

2.检查脚本映射,然后调用 ASP.NET ISAPI 扩展

3.将消息送入aspnet_wp.exe进程,并加载运行时

4.调用ISAPIRuntime.ProcessRequest方法创建HttpWorkerRequest对象

6.创建HttpContext请求上下文

7.创建HttpApplication 类的实例

8.初始化Web.Config中注册的所有模块(HttpModule)

9.调用HttpApplication 类的 Init 方法

10.触发事件,实例化页面

原文地址:https://www.cnblogs.com/blosaa/p/2308645.html