编程开发 > ASP > 文章内容

ASP.NETHTTP运行时组成详解(下)

2017-6-16编辑:daibenhua

  HTTP 管道

  ASP.NET ISAPI 扩展启动辅助进程后,它将传递部分命令行参数。辅助进程使用这些参数来执行加载 CLR 前需要执行的任务。传递的值包括:COM 和 DCOM 安全性所要求的身份验证等级、可以使用的命名管道的数量和 IIS 进程标识。命名管道的名称是使用 IIS 进程标识和允许的管道数随机生成的。辅助进程不接收可用管道的名称,但可以接收识别管道名称所需的信息。

  COM 和 DCOM 安全性与 Microsoft? .NET Framework 有何关系?实际上,CLR 是作为 COM 对象提供的。更准确地说,CLR 本身不是由 COM 代码构成的,但是指向 CLR 的接口却是一个 COM 对象。因此,辅助进程加载 CLR 的方式与加载 COM 对象的方式相同。

  当 ASPX 请求遇到 IIS 时,Web 服务器将根据选择的身份验证模型(匿名、Windows、Basic 或 Digest)来分配一个令牌。当辅助进程收到要处理的请求时,令牌被传递到辅助进程。请求由辅助进程中的线程获取。该线程从最初获取传入请求的 IIS 线程继承身份令牌。在 aspnet_wp.exe 中,负责处理请求的实际帐户取决于在特殊的 ASP.NET 应用程序中是如何配置模拟的。如果模拟被禁用(默认设置),则线程将在辅助进程的帐户下运行。默认情况下,该帐户在 ASP.NET 进程模型中为 ASPNET,在 IIS 6 进程模型中为 NETWORKSERVICE。这两个帐户都是“弱”帐户,提供的功能比较有限,可以有效抵挡回复性攻击 (Revert-to-self Attack)。(回复性攻击是指将模拟的客户端的安全性令牌回复到父进程令牌。为辅助进程分配弱帐户可以挫败此类攻击。)

  高度概括起来,ASP.NET 辅助进程完成的一项主要任务就是将请求交给一系列称为的 HTTP 管道的托管对象。要激活 HTTP 管道,可以创建一个 HttpRuntime 类的新实例,然后调用其 ProcessRequest 方法。如前所述,ASP.NET 中始终只运行一个辅助进程(除非启用了 Web Garden 模型),该进程在独立的 AppDomain 中管理所有的 Web 应用程序。每个 AppDomain 都有自己的 HttpRuntime 类实例,即管道中的输入点。HttpRuntime 对象初始化一系列有助于实现请求的内部对象。Helper 对象包括缓存管理器(Cache 对象)和内部文件系统监视器(用于检测构成应用程序的源文件的更改)。HttpRuntime 为请求创建上下文,并用与请求相关的 HTTP 信息填充上下文。上下文用 HttpContext 类的实例来表示。

  另一个在 HTTP 运行时的设置初期创建的 Helper 对象是文本书写器,用于包含浏览器的响应文本。文本书写器是 HttpWriter 类的实例,此对象对页面代码以编程方式发送的文本进行缓存。HTTP 运行时被初始化后,它将查找实现请求的应用程序对象。应用程序对象是 HttpApplication 类的实例,该类就是 global.asax 文件背后的类。global.asax 在编程时是可选的,但在构建结构时是必需的。因此,如果应用程序中没有构建类,则必须使用默认对象。ASP.NET 运行时包括几个中间工厂类,可以用来查找并返回有效的 Handler 对象以处理请求。整个过程中用到的第一个工厂类是 HttpApplicationFactory。它的主要任务是使用 URL 信息来查找 URL 虚拟目录和汇集的 HttpApplication 对象之间的匹配关系。

  应用程序工厂类的行为可以概括为以下几点:

  工厂类维护 HttpApplication 对象池,并使用它们来处理应用程序的请求。池的寿命与应用程序的寿命相同。

  应用程序的第一个请求到达时,工厂类提取有关应用程序类型的信息(global.asax 类)、设置用于监视更改的文件、创建应用程序状态并触发 Application_OnStart 事件。

  工厂类从池中获取一个 HttpApplication 实例,并将要处理的请求放入实例中。如果没有可用的对象,则创建一个新的 HttpApplication 对象。要创建 HttpApplication 对象,需要先完成 global.asax 应用程序文件的编译。

  HttpApplication 开始处理请求,并且只能在完成这个请求后才能处理新的请求。如果收到来自同一资源的新请求,则由池中的其他对象来处理。

  应用程序对象允许所有注册的 HTTP 模块对请求进行预处理,并找出最适合处理请求的处理程序类型。这通过查找请求的 URL 的扩展和配置文件中的信息来完成。

  HTTP 处理程序是一些实现 IHttpHandler 接口的类。.NET Framework 为常见的资源类型提供了一些预定义的处理程序,包括 ASPX 页面和 Web 服务。machine.config 文件中的 部分定义了 HttpApplication 对象必须实例化才能处理特定类型资源的请求的类名。如果 Helper 类是一个处理程序工厂,GetHandler 方法将确定要使用的处理程序类型。这时,将从一组类似的对象中获取适当类型的处理程序,并对其进行配置以处理请求。

  IHttpHandler 接口提供了两个方法:IsReusable 和 ProcessRequest。前者将返回一个布尔值,表示处理程序是否可以被汇集。(大多数预定义的处理程序都是汇集的,但是您可以自行定义每次都需要新实例的处理程序。)ProcessRequest 方法包含处理特定类型资源所需的所有逻辑。例如,ASPX 页面的处理程序基于以下伪代码:

  private void ProcessRequest()

  {

  // 确定请求是否是回发 (postback)

  IsPostBack = DeterminePostBackMode();

  // 触发 ASPX 源代码的 Page_Init 事件

  PageInit();

  // 加载 ViewState,处理已发送的值。

  if (IsPostBack) {

  LoadPageViewState();

  ProcessPostData();

  }

  // 触发 ASPX 源代码的 Page_Load 事件

  PageLoad();

  // 1) 再次处理已发送的值(当

  // 动态创建控件时)

  // 2) 将属性更改的服务器端事件提升为输入驱动的

  // 控件(即复选框的状态改变)

  // 3) 执行与回发事件相关的所有代码

  if (IsPostBack) {

  ProcessPostDataSecondTry();

  RaiseChangedEvents();

  RaisePostBackEvent();

  }

  // 触发 ASPX 源代码的 Page_PreRender 事件

  PreRender();

  // 将控件的当前状态保存到 ViewState 中

  SavePageViewState();

  // 将页面内容呈现给 HTML

  RenderControl(CreateHtmlTextWriter(Response.Output));

  }

  无论调用的资源类型如何,基于 HTTP 处理程序的模型是相同的。唯一随资源类型变化而变化的元素是处理程序。HttpApplication 对象负责查找应该使用哪种处理程序来处理请求。HttpApplication 对象还负责检测对动态创建的、表示资源的程序集(如 .aspx 页面或 .asmx Web 服务)所进行的更改。如果检测到更改,应用程序对象将确保编译并加载所请求的资源的最新来源。

  四、临时文件和页面程序集

  要全面了解 ASP.NET HTTP 运行时,让我们来分析一下当请求 ASP.NET 页面时,文件系统层所发生的变化。接下来,您将了解由 HTTP 管道的对象管理和监视的一组动态创建的临时文件。

  虽然可以将页面的核心代码隔离在代码背后的 C# 或 Microsoft? Visual Basic? .NET 类中,但可以将 Web 页面编写和部署为 .aspx 文本文件。对于要显示为 URL 的页面来说,.aspx 文件在应用程序的 Web 空间中必须始终可用。.aspx 文件的实际内容将确定应用程序对象要加载的程序集(或多个程序集)。

  按照设计,HttpApplication 对象将查找一个根据请求的 ASPX 文件命名的类。如果页面命名为 sample.aspx,则要加载的相应的类名为 ASP.sample_aspx。应用程序对象在 Web 应用程序的所有程序集文件夹中查找这样的类,这些文件夹包括全局程序集缓存 (GAC)、Bin 子文件夹和 Temporary ASP.NET Files 文件夹。如果未找到这样的类,HTTP 结构将分析 .aspx 文件的源代码,创建一个 C# 或 Visual Basic .NET 类(具体创建哪种类,取决于 .aspx 页面上设置的语言),同时对其进行编译。新创建的程序集的名称是随机生成的,位于特定于应用程序的子文件夹中,路径如下所示: C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\Temporary ASP.NET Files。

  子文件夹 v1.1.4322 特定于 ASP.NET 1.1。如果您使用的是 ASP.NET 1.0,子文件夹的版本号会有所不同,即子文件夹名为 v1.0.3705。再次访问页面时,程序集就已存在,不需要重新创建。但是,HttpApplication 对象是如何确定特定于页面的程序集是否存在呢?它每次都要扫描大量文件夹吗?不,并不是这样。

  应用程序对象只查看 Temporary ASP.NET Files 文件夹中某个特殊文件夹的内容。具体路径(特定于应用程序的路径)由 HttpRuntime.CodegenDir 属性返回。如果是第一次访问 .aspx 文件(即还未创建页面程序集),则该文件夹中就不存在以 ASPX 页面名称开头的 XML 文件。例如,具有动态程序集的 sample.aspx 页面应有如下的条目:

  sample.aspx.XXXXX.xml

  XXXXX 占位符是一种散列代码。通过读取该 XML 文件的内容,应用程序对象就可以了解要加载的程序集的名称以及要在其中获取的类。以下代码片段是这种 Helper 文件的典型内容。包含 ASP.sample_aspx 类的程序集的名称是 mvxvx8xr。

  

  

  

  当然,只有在分析 filedep 文件的源代码以生成动态程序集时才创建该文件。对 filedep 文件所做的任何更改都会使程序集无效,在下一次请求时必须重新编译。需要注意的是,在 ASP.NET 架构的未来版本中,该实现过程可能会有较大改变。不论什么原因,只要您决定在当前应用程序中使用它,都必须十分小心。

  由于更新而要为页面创建新的程序集时,ASP.NET 将验证是否可以删除旧的程序集。如果旧的程序集只包含修改后的页面的类,ASP.NET 将试图删除并替换该程序集,否则将在保留旧程序集的情况下创建一个新程序集。

  在删除过程中,ASP.NET 可能会发现程序集文件已被加载并锁定。这种情况下,可以为旧程序集添加一个“.DELETE”扩展名,以将其重新命名。(注意,所有 Windows 文件都可以在使用过程中重新命名。)只要应用程序重新启动(例如,由于对某个应用程序文件如 global.asax 和 web.config 进行了更改),这些临时的 .DELETE 文件就将被删除。但在处理下一个请求时,ASP.NET 运行时不会删除这些文件。

  请注意,默认情况下,在整个应用程序重新启动之前,每个 ASP.NET 应用程序最多可以重新编译 15 个页面,同时会损失一些会话和应用程序数据。当最近的编译次数超过了 部分的 numRecompilesBeforeAppRestart 属性中设置的阈值时,将卸载 AppDomain,并重新启动应用程序。还要注意,在 .NET Framework 中,您无法卸载单个程序集。AppDomain 是可以从 CLR 卸载的最小的代码块。

  五、小结

  ASP.NET 应用程序有两大特征:进程模型和页面对象模型。ASP.NET 提前使用了 IIS 6.0 的一些功能,而 IIS 6.0 则是 Windows Server 2003 中提供的全新的、开创性的 Microsoft Web 信息服务。尤其值得一提的是,在独立的辅助进程中运行的 ASP.NET 应用程序,其行为与 IIS 6 中的所有应用程序相同。而且,尽管会出现运行时异常、内存泄露或程序错误,ASP.NET 运行时仍能自动回收辅助进程以保证实现卓越的性能。这种功能已成为 IIS 6.0 的系统功能。

  在本文中,我概括介绍了默认的 ASP.NET 进程模型的基础知识,以及 IIS 级代码(ASP.NET ISAPI 扩展)和辅助进程之间的交互。同时,还介绍了与 IIS 6 进程模型之间的最新区别。

ASP.NETHTTP运行时组成详解(上)

热点推荐

登录注册
触屏版电脑版网站地图