ASP.NET HTTP 运行时
ASP.NET HTTP 运行时
一个请求从 URL 字符串到 HTML 代码的“漫长曲折”之路
Dino Esposito
Wintellect
2003年7月10日
摘要:本文详细介绍了 HTTP 运行时的组成部分,以及在处理对 ASP.NET 应用程序的各种请求时采用的逻辑。文章还以 Web Garden 模型和最新的 IIS 6 进程模型为切入点,分析了辅助进程的行为,并说明了 HTTP 请求变为纯 HTML 文本的全过程。(本文包含一些指向英文站点的链接。)
适用于:
Microsoft® ASP.NET
目录
- 简介
- ASP.NET 结构的组件
- Web Garden 模型
- HTTP 管道
- 临时文件和页面程序集
- 小结
简介
不管使用哪种底层平台,可靠性和性能都是对所有 Web 应用程序的主要要求,尽管从某种意义上讲,这两个要求是相互矛盾的。例如,要构建更可靠、更健壮的应用程序,可能需要将 Web 服务器与具体的应用程序分离,使应用程序在进程外工作。但是,如果在不同于 Web 服务器进程的内存环境中工作,应用程序将变慢。因此,需要采取合理的措施,以确保进程外代码尽可能快地运行。
在构建 Microsoft® ASP.NET 运行时环境时,依据的设计原则即:充分考虑可靠性和性能。得到的 ASP.NET 进程模型包含了两个系统元素 - 一个存在于 Web 服务器进程中的进程内连接器,一个外部的辅助进程。另外,ASP.NET 运行时结构的可伸缩能力很强,可以自动使用多处理器硬件中任意选定的处理器。这种模式被称为“Web Garden”,它可以使多个辅助进程同时运行,而且各个进程均在独立的处理器中。
高度概括起来,ASP.NET 运行时具有三大属性:
- 应用程序和 ASP.NET 辅助进程之间完全分离。提供服务的辅助进程的寿命决不会影响应用程序的寿命。换句话说,当应用程序启动并处于运行状态时,辅助进程可以随时终止。
- 尽管 ASP.NET 应用程序从不在 Web 服务器内采用进程内的方式运行,但大多数情况下,其总体性能仍接近于进程内应用程序的性能。
- 为 Web Garden 体系结构提供了内置的和可配置的支持。只要简单检查一下配置文件中的设置,辅助进程就可以克隆自己,以利用所有与进程密切相关的 CPU。因此,在大多数情况下,您在具备多处理器的计算机中获得的可缩放性将呈线性增长的趋势。(本文后面将详细介绍此内容。)
本文将介绍 ASP.NET 运行时环境的组成元素,然后一步一步地讲述从 URL 请求变为纯 HTML 文本的“漫长而曲折”的过程。
除非另有说明,否则以下介绍中均指 ASP.NET 的默认进程模型,即 Microsoft® Internet Information Services (IIS) 5.x 中唯一的模型。
ASP.NET 结构的组件
执行 ASP.NET 应用程序需要宿主 Web 服务器的支持。在 Microsoft® Windows® 的 Server 平台中,Web 服务器由名为 inetinfo.exe 的 IIS 可执行文件表示。Windows 2000 及以上版本的操作系统本身均提供了 Web 服务器。但需要注意,在 Microsoft® Windows Server™ 2003 中,并未默认安装 IIS 和 ASP.NET,必须通过单击“控制面板”中的“添加或删除程序”小程序将其添加到系统中。
IIS 是一个未托管的可执行程序,它提供了一个基于 ISAPI 扩展模块和筛选器模块的可扩展模型。通过编写此类模块,开发人员可以直接管理对特定资源类型的请求,并在各个预定义的步骤中接收当前请求。扩展和筛选器是一些 DLL,可以导出一些具有已知名称和签名的函数。这些插件组件是在 IIS 配置数据库中注册并配置的。
只有少数几种被客户端请求的资源类型由 IIS 直接处理。例如,对 HTML 页面、文本文件、JPEG 和 GIF 图像的传入请求由 IIS 处理。对 Active Server Page (*.asp) 文件的请求通过调用名为 asp.dll 的 ASP 专用扩展模块进行解析。同样,对 ASP.NET 资源(例如,*.aspx、*.asmx、*.ashx)的请求将传递到 ASP.NET ISAPI 扩展。该系统组件是一个名为 aspnet_isapi.dll 的 Win32 DLL。ASP.NET 扩展可以处理多种资源类型,包括 Web 服务和 HTTP 处理程序调用。
ASP.NET ISAPI 扩展是一个 Win32 DLL,未集成托管代码。它是接收和分派对各种 ASP.NET 资源的请求的控制中心。按照设计,该模块存在于 IIS 进程中,在具有管理员权限的 SYSTEM 帐户下运行。开发人员和系统管理员不能修改此帐户。ASP.NET ISAPI 扩展负责调用 ASP.NET 辅助进程 (aspnet_wp.exe),而该进程又负责控制请求的执行。除了对请求进行安排以外,ASP.NET ISAPI 还监视辅助进程的运行情况,并在性能降低到一定程度时将进程取消。
辅助进程是一小段 Win32 shell 代码,集成了公共语言运行库 (CLR) 并运行托管代码。它负责处理对 ASPX、ASMX 和 ASHX 资源的请求。一般来说,此进程在一台给定的计算机中只有一个实例。所有当前激活的 ASP.NET 应用程序均在其中运行,每个应用程序都位于一个独立的 AppDomain 中。但是,如前所述,辅助进程支持 Web Garden 模式,即进程的相同副本都运行在与进程密切相关的 CPU 中。(更多内容,请参阅本文后面的“Web Garden 模型”部分。)
ISAPI 和辅助进程之间的通讯是使用一组命名管道进行的。命名管道是一种 Win32 机制,用于跨进程边界传输数据。顾名思义,命名管道的工作方式与管道相似:在一端输入数据,在另一端输出相同的数据。建立的管道既可以连接本地进程,也可以连接远程计算机上运行的进程。对于本地进程间通讯,管道是 Windows 中的最有效、最灵活的工具。
为确保获得最优性能,aspnet_isapi 使用异步命名管道来将请求转发给辅助进程并获得响应。另一方面,辅助进程在需要查询有关 IIS 环境的信息(即服务器变量)时又使用同步管道。aspnet_isapi 模块创建固定数量的命名管道,并使用重叠的操作以通过小的线程池处理同一时间进行的连接。当通过管道进行的数据交换操作结束后,完成例程将断开客户端,并重新使用管道实例为新的客户端服务。线程池和重叠操作均可以保证使 ASP.NET ISAPI 的性能达到令人满意的水平。但是,aspnet_isapi 扩展决不会处理 HTTP 请求。
ASP.NET 请求的处理逻辑可以概括为以下步骤。
- 当请求到达时,IIS 检查资源类型并调用 ASP.NET ISAPI 扩展。如果启用了默认的进程模型,aspnet_isapi 会将请求排队,并将请求分配给辅助进程。所有的请求数据都通过异步 I/O 发送。如果启用了 IIS 6 进程模型,请求将自动在辅助进程 (w3wp.exe) 中排队,此辅助进程用于处理应用程序所属的 IIS 应用程序池。IIS 6 辅助进程不了解 ASP.NET 和托管代码的任何情况,它只是处理 *.aspx 扩展并加载 aspnet_isapi 模块。当 ASP.NET ISAPI 在 IIS 6 进程模型中运行时,它的工作方式有所不同,仅在 w3wp.exe 辅助进程的上下文中加载 CLR。
- 收到请求后,ASP.NET 辅助进程将通知 ASP.NET ISAPI,它将为请求服务。通知通过同步 I/O 实现。之所以使用同步模型,是因为请求只有在 ISAPI 内部请求表中被标记为“executing”,辅助进程才能开始处理它。如果请求已经由特殊的辅助进程进行处理,则不能再将它指定到其他进程,除非原始进程已取消。
- 在辅助进程的上下文中执行请求。有时,辅助进程可能需要回调 ISAPI 以完成请求,也就是需要说枚举服务器变量。这种情况下,辅助进程将使用同步管道,因为这样可以保持请求处理逻辑的顺序。
- 完成后,响应被发送到打开了异步管道的 aspnet_isapi。现在,请求的状态变为“Done”,之后将从请求表中被删除。如果辅助进程崩溃,正在处理的所有请求仍将保持“executing”状态并持续一段时间。如果 aspnet_isapi 检测到辅助进程已取消,它将自动终止请求并释放所有相关的 IIS 资源。
以上说明是指默认的 ASP.NET 进程模型,即在 IIS 5.x 中运行的工作模型。IIS 6(Windows Server 2003 提供)的默认工作方式对 ASP.NET 进程模型也有影响。当集成在 IIS 6.0 中时,ASP.NET 1.1 会自动调整自己的工作方式以适应宿主环境。这时,不再需要使用 aspnet_wp 辅助进程,machine.config 文件中定义的某些配置参数也被忽略。从 ASP.NET 的角度来看,IIS 6 的最大改变是有关请求的一切都在 aspnet_isapi 的控制之下,且都处在 w3wp.exe 辅助进程的上下文中。辅助进程的帐户是为 Web 应用程序所属的应用程序池设置的帐户。默认情况下,该帐户是 NETWORKSERVICE—,它是一个内置的弱帐户,在功能上与 ASPNET 等价。
辅助进程受一个名为进程回收 (Recycling) 的功能的控制。进程回收具有 aspnet_isapi 功能,当现有进程消耗的内存太多、响应太慢或挂起时可以自动启动新进程。出现这种情况时,新请求将由新实例处理,新实例从而变成新的活动进程。但是,指定给旧进程的所有请求仍保持挂起状态。如果旧进程结束了挂起的请求并进入空闲状态,该进程即终止。如果辅助进程崩溃,或者由于其他原因停止处理请求,则所有挂起的请求将被重新指定给新进程。
尽管 ASP.NET ISAPI 和辅助进程是 ASP.NET 运行时结构的主要组成部分,但还有其他一些可执行文件也发挥着作用。下表列出了所有这些组件。
表 1:构成 ASP.NET 运行时环境的可执行文件
名称 | 类型 | 帐户 |
---|---|---|
aspnet_isapi.dll | Win32 DLL(ISAPI 扩展) | LOCAL SYSTEM |
aspnet_wp.exe | Win32 EXE | ASPNET |
aspnet_filter.dll | Win32 DLL(ISAPI 筛选器) | LOCAL SYSTEM |
aspnet_state.exe | Win32 NT Service | ASPNET |
aspnet_filter.dll 组件是一个小的 Win32 ISAPI 筛选器,用来备份 ASP.NET 应用程序的无 Cookie 会话状态。在 Windows Server 2003 中,当启用 IIS 6 进程模型时,aspnet_filter.dll 还将筛选出 Bin 目录中对非可执行资源的请求。
aspnet_state.exe 的作用对 Web 应用程序更为重要,因为它用于管理会话状态。该项服务是可选的,可以用来在 Web 应用程序内存空间之外保存会话状态数据。该可执行文件是一种 NT 服务,既可以在本地运行,也可以远程运行。当该服务被激活后,可以将 ASP.NET 应用程序配置为将所有会话信息保存在此进程的内存中。一种类似的方案是提供更为可靠的数据存储方式,不受进程回收和 ASP.NET 应用程序故障的影响。该服务在 ASPNET 本地帐户下运行,但可以使用服务控制管理器 (Service Control Manager) 接口来配置它。
另一个应该介绍的可执行文件是 aspnet_regiis.exe,尽管严格来讲,它并不属于 ASP.NET 运行时结构。该实用程序可以用来配置环境,以在一台计算机上并行执行不同版本的 ASP.NET,还可用于维修 IIS 和 ASP.NET 损坏的配置。该实用程序的工作方式是更新存储在 IIS 配置数据库的根目录和子目录中的脚本映射。脚本映射是资源类型和 ASP.NET 模块之间的一种关联关系。最后,还可以使用该工具来显示已安装的 ASP.NET 版本的状态,执行其他配置操作,如授予对特定文件夹的 NTFS 权限、创建客户脚本目录。
Web Garden 模型
Web Garden 模型可以通过 machine.config 文件中的 <processModel> 部分进行配置。请注意,<processModel> 部分是唯一不能放在应用程序特定的 web.config 文件中的配置部分。这就是说,Web Garden 模式可以应用到计算机中运行的所有应用程序。但通过使用 machine.config 源文件中的 <location> 节点,可以针对各个应用程序调节计算机的设置。
<processModel> 部分有两个属性可以影响 Web Garden 模型,它们是 webGarden 和 cpuMask。webGarden 属性接受布尔值,表示是否使用了多个辅助进程(一个相关的 CPU 对应一个进程)。默认情况下,该属性的值为 false。cpuMask 属性保存一个 DWORD 值,该值的二进制表示为能够运行 ASP.NET 辅助进程的 CPU 提供了位屏蔽。其默认值为 -1 (0xFFFFFF),表示可以使用所有可用的 CPU。如果 webGarden 属性为 false,则 cpuMask 属性的内容将被忽略。cpuMask 属性还为正在运行的 aspnet_wp.exe 的副本数设置了上限。
常言道“闪光的不都是金子”,用在这里很合适。Web Garden 模式使得多个辅助进程可以同时运行。但是,需要注意的是所有进程都会有自己的应用程序状态、进程内会话状态、ASP.NET 缓存、静态数据以及运行应用程序所需的其他内容。启用 Web Garden 模式之后,ASP.NET ISAPI 将根据 CPU 的数量尽可能多地启动辅助进程,每个辅助进程都是下一进程的完整克隆(每一进程都与相应的 CPU 密切相关)。为平衡工作负荷,传入的请求以单循环的方式在运行的进程之间进行划分。辅助进程就象在单处理器中一样被回收。请注意,ASP.NET 继承了操作系统中所有的 CPU 使用限制,并且不包括实现限制的自定义语义。
总之,Web Garden 模型并不适用于所有应用程序。应用程序的状态越多,其的性能损失也越多。工作数据存储在共享内存的块中,以便一个进程输入的变化可以立即被其他进程得知。但是,处理请求时,工作数据被复制到进程的上下文中。因此,各个辅助进程将处理自己的工作数据,而应用程序的状态越多,性能损失就越大。鉴于此,仔细、明智的应用程序基准测试是绝对必要的。
只有重启 IIS 后,对配置文件中 <processModel> 部分所做的更改才会生效。在 IIS 6 中,Web Garden 模式的参数保存在 IIS 配置数据库中,webGarden 和 cpuMask 属性被忽略。
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 文件中的 <httpHandlers> 部分定义了 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。
<preserve assem="mvxvx8xr" type="ASP.sample_aspx"> <filedep name="c:/inetpub/wwwroot/vdir/sample.aspx" /> </preserve>
当然,只有在分析 filedep 文件的源代码以生成动态程序集时才创建该文件。对 filedep 文件所做的任何更改都会使程序集无效,在下一次请求时必须重新编译。需要注意的是,在 ASP.NET 架构的未来版本中,该实现过程可能会有较大改变。不论什么原因,只要您决定在当前应用程序中使用它,都必须十分小心。
由于更新而要为页面创建新的程序集时,ASP.NET 将验证是否可以删除旧的程序集。如果旧的程序集只包含修改后的页面的类,ASP.NET 将试图删除并替换该程序集,否则将在保留旧程序集的情况下创建一个新程序集。
在删除过程中,ASP.NET 可能会发现程序集文件已被加载并锁定。这种情况下,可以为旧程序集添加一个“.DELETE”扩展名,以将其重新命名。(注意,所有 Windows 文件都可以在使用过程中重新命名。)只要应用程序重新启动(例如,由于对某个应用程序文件如 global.asax 和 web.config 进行了更改),这些临时的 .DELETE 文件就将被删除。但在处理下一个请求时,ASP.NET 运行时不会删除这些文件。
请注意,默认情况下,在整个应用程序重新启动之前,每个 ASP.NET 应用程序最多可以重新编译 15 个页面,同时会损失一些会话和应用程序数据。当最近的编译次数超过了 <httpRuntime> 部分的 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.NET、HTTP 运行时和页面对象模型,请查阅 Microsoft Press 2003 年出版的我的新书 Programming Microsoft ASP.NET。
关于作者
Dino Esposito 是一位来自意大利罗马的培训教师和顾问。作为 Wintellect 小组的成员,Dino 专门研究 ASP.NET 和 ADO.NET,主要在欧洲和美国从事教学和咨询工作。Dino 还管理着 Wintellect 的 ADO.NET 课件,为 MSDN Magazine 的 Cutting Edge 专栏撰写文章。要与他联系,请发送电子邮件至 dinoe@wintellect.com。
相关文章:

C++中的const关键字(zz)
【补充】mutable关键字有时我们希望类的数据成员即使在const成员函数中,依然是可以修改的,这时就可以把它们声明为mutable来实现。这样的应用,比如记录各种操作的调用次数,这时,即使在const中,依然要修改计…
Python让你成为AI 绘画大师,简直太惊艳了!(附代码))
作者 | 李秋键责编 | 李雪敬头图 | CSDN下载自视觉中国引言:基于前段时间我在CSDN上创作的文章“CylcleGAN人脸转卡通图”的不足,今天给大家分享一个更加完美的绘制卡通的项目“Learning to Cartoonize Using White-box Cartoon Representations”。首先…
Vue 2 | Part 4 v-bind绑定元素属性和样式
这期跟大家分享的,是v-bind指令。它可以往元素的属性中绑定数据,也可以动态地根据数据为元素绑定不同的样式。 绑定属性 最简单的例子,我们有一张图片,需要定义图片的src。我们可以直接在元素的属性里面定义: <div …

在 ASP.NET 中执行 URL 重写
在 ASP.NET 中执行 URL 重写 发布日期: 8/23/2004| 更新日期: 8/23/2004Scott Mitchell 4GuysFromRolla.com 适用范围: Microsoft ASP.NET 摘要:介绍如何使用 Microsoft ASP.NET 执行动态 URL 重写。URL 重写是截取传入 Web 请求并…

win8中使用BitLocker加密
一、加密驱动器二、管理三、TPM转载于:https://blog.51cto.com/jimshu/989359
清华硕士爆料:这些才是机器学习必备的数学基础
现如今,计算机科学、人工智能、数据科学已成为技术发展的主要推动力。无论是要翻阅这些领域的文章,还是要参与相关任务,你马上就会遇到一些拦路虎:想过滤垃圾邮件,不具备概率论中的贝叶斯思维恐怕不行;想试…

Oracle Golden Gate体系架构详解(原创) - CzmMiao的博客生活 - ITeye技术网站
Oracle Golden Gate体系架构详解(原创) - CzmMiao的博客生活 - ITeye技术网站

用C#对ADO.NET数据库完成简单操作
作者:李阳 http://oraasp.vicp.net/article/article.aspx?ID21 数据库访问是程序中应用最普遍的部分。随着C#和ADO.NET的引入,这种操作变得更简单。这篇文章将示范四种最基础的数据库操作。 ● 读取数据。其中包括多种数据类型:整型&#…

用createrepo配置Yum本地源
yum配置本地源, 在网速差的情况下,yum用在线源是一件头痛的事,所以以下为yum的本地源配置可以有好解决这个事。 1,安装createrepo包, 可以用yum安装(yum install createrepo -y); 也可以安装rpm或tar包 (网址:createre…
首次在手机端不牺牲准确率实现BERT实时推理,比TensorFlow-Lite快近8倍,每帧只需45ms...
作者 | 王言治 出品 | AI科技大本营(ID:rgznai100) 基于Transformer的预训练模型在许多自然语言处理(NLP)任务中取得了很高的准确度。但是这些预训练模型往往需要很大的计算量和内存。由于移动平台的存储空间以及计算能力的限制&a…

[svc]caffe安装笔记-显卡购买
caffe,这是是数据组需要做一些大数据模型的训练(深度学习), 要求 服务器显卡(运算卡), 刚开始老板让买的牌子是泰坦的(这是2年前的事情了). 后来买不到这个牌子的,(jd,tb)看过丽台的,看过gtx系列的哪个型号来着, 也不合适,后来买的特斯拉显卡 [查了下一些知名的显卡牌子](https…
AABO:自适应最优化Anchor设置,性能榨取的最后一步 | ECCV 2020
编译 | VincentLee来源 | 晓飞的算法工程笔记Introduction目前,主流的目标检测算法使用多种形状的anchor box作为初始预测,然后对anchor box进行回归调整,anchor box的配置是检测算法中十分重要的超参数。一般而言,anchor box的配…

Android列表控件选项中添加进度框ProgressBar实现
今天有时间就学习了下在ListView、GridView列表项中清加ProgressBar,小马用最简单的代码实现可以通用的功能,人人都能看懂,哈哈,直接说下,如果你的适配器getView方法返回的View是一个自定义控件的话,有点不好实现哦&am…

写一个通用数据访问组件
出处:http://www.csharp-corner.com willsound(翻译) 我收到过好多Email来问我如何用一个通用的数据提供者(data provider)在不失自然数据提供者(native data provider)稳定而强大功能的前提下来访问不同的数据源(data sources).一个小伙子…

InstallShield 2015 LimitedEdition VS2012 运行bat文件
转载:http://www.cnblogs.com/fengwenit/p/4271150.html 运行bat文件 网上很多介绍如何运行bat的方法,但我这个是limted 版本,不适用。 1. 打开 Define Setup Requirements and Actions –> Custom Actions 2. 右健 After Register Product –> Ne…

理解C#中的string类型
作者:未知目的 本文的目的在于揭示和DOTNET及C#相关的一些常见的和不常见的问题。在这些问题中我的第一篇文章和string数据类型有关,string数据类型是一种引用类型,但是当和其他引用类型比较的时候,很多开发人员可能并不能完全理解它的行为。 问题 对于常见的引用类…
最全总结!聊聊 Python 操作PDF的几种方法
作者 | 陈熹来源 | 早起Python前言本文主要涉及:os 模块综合应用glob 模块综合应用PyPDF2 模块操作基本操作PyPDF2 导入模块的代码常常是:from PyPDF2 import PdfFileReader, PdfFileWriter这里导入了两个方法:PdfFileReader 可以理解为读取器…

three.js(六) 地形法向量生成
2019独角兽企业重金招聘Python工程师标准>>> 上一节采用 分形算法生成地形的高度值, 接着我们需要生成每个顶点的法向量。 three.js 的PlaneGeometry 自带有法向量, 法向量分为两种 即 平面法向量 和 平面每个定点法向量。 因此一个n*n 块组成…

ASP.NET中使用多个runat=server form
作者:未知ASP.NET 在同一个页面不支持多个 runatserver forms,要解决这个问题,可以把每个 form 放在一个单独的 panel 控件中,这样用户就可以简单地通过单选按钮在不同 panel 间切换。代码如下:2FormExample.aspx<%…
激发企业大“智慧” | 深度赋能AI全场景 揭秘你不知道的移动云
2020年是人工智能技术发展的关键年。疫情之下,世界见证了人工智能在抗击疫情中发挥的积极作用;今年4月,国家发改委正式将人工智能确定为新基建的重要领域之一。在历史机遇下,AI已实现"质变和量变",正迈入与技…

ExtJS 4.x 得到资源树上任意的节点对象
上半年做ExtJS 4.x 的时候,遇到过对资源树操作的情况: Ext.tree.Panel 如下图:目的: 直接根据每个节点的{任意key : 对应value},就能找到匹配的节点对象 代码如下: refs : [ { selector : rtree, …

【转载】mysql常用函数汇总
转载地址:http://www.jb51.net/article/40179.htm 一、数学函数ABS(x) 返回x的绝对值BIN(x) 返回x的二进制(OCT返回八进制,HEX返回十六进制)CEILING(x) 返回大于x的最小整数值EXP(x) 返回值e(自然对数的底&…

有关java的一些话
2019独角兽企业重金招聘Python工程师标准>>> 跟着做完TankWar,java才算是入门了,真正学习java从看尚学堂马士兵老师的视频开始,至今三个月已过,感谢马老师的精彩讲解,您才是我真正的java入门老师࿰…

ADO.NET 2.0中的SqlCommand.ExecutePageReader
http://blog.joycode.com/liuhuimiao/在.NET 2.0 PDC或Beta1中,可以看到SqlCommand对象新增了个ExecutePageReader方法,该方法实现了分页读取数据的功能。对于分页读取数据,在ADO.NET1.1中(当然2.0也适合)一般常用动态…
组合游戏系列5: 井字棋、五子棋AlphaGo Zero 算法实战
来源 | MyEncyclopedia上一篇我们从原理层面解析了AlphaGo Zero如何改进MCTS算法,通过不断自我对弈,最终实现从零棋力开始训练直至能够打败任何高手。在本篇中,我们在已有的N子棋OpenAI Gym 环境中用Pytorch实现一个简化版的AlphaGo Zero算法…
2020职场人裸辞三大原因:不开心、工资低、没有盼头
近期,脉脉发布了《2020职场人裸辞现状调研报道》,报道显示2020最让职场人想裸辞的三大原因为:不开心、工资低、没有盼头。报告数据中还显示,工资不满预期是最让人想要裸辞的主要原因,但有超过6成职场人表示,…

Oracle PL/SQL编程学习笔记:Merge方法的使用
Oracle11g的Merge很强大! 1 create or replace procedure BRANCE_REPORT_MERGE is2 3 begin4 Merge into BRANCHREPORT desttable5 using TEMP_BRANCHREPORT tmptable6 on (desttable.SENDER_IDtmptable.SENDER_ID and desttable.BRANCH_IDtmptable.BRANCH_ID…

2.0中获取数据库连接统计数据
作者: http://blog.joycode.com/liuhuimiao/.NET 2.0中的SqlConnection多了一个StatisticsEnabled属性和ResetStatistics()、RetrieveStatistics()两个方法,用于获取SQLServer的连接统计数据。当然,这样做是以性能损耗为代价的,但…

Python学习day5作业-ATM和购物商城
Python学习day5作业Python学习day5作业ATM和购物商城作业需求ATM:指定最大透支额度可取款定期还款(每月指定日期还款,如15号)可存款定期出账单支持多用户登陆,用户间转帐支持多用户管理员可添加账户、指定用户额度、冻…
60分钟看懂HMM的基本原理
作者 | 梁云1991来源 | Python与算法之美HMM模型,韩梅梅的中文拼音的缩写,所以又叫韩梅梅模型,由于这个模型的作者是韩梅梅的粉丝,所以给这个模型取名为HMM。开玩笑!HMM模型,也叫做隐马尔科夫模型ÿ…