ASP.NET Core 6 基础入门系列(15) 项目在IIS下部署的两种进程托管模型

  在前一篇博客《ASP.NET Core 6 基础入门系列(14) ASP.NET Core 项目发布与IIS部署》中简单的介绍了Web项目的发布与IIS中部署的流程。ASP.NET Core 在 IIS下部署有 In-ProcessOut-of-Process 两种部署模式。

  ASP.NET Core Module (ANCM) 是插入 IIS 管道的本机 IIS 模块,能让 ASP.NET Core 应用程序通过 IIS 运行。 使用以下任一方式通过 IIS 运行 ASP.NET Core 应用:

  • 在 IIS 工作进程 (w3wp.exe) 内托管 ASP.NET Core 应用,称为进程内托管模型
  • 将 Web 请求转发到运行 Kestrel 服务器(dotnet.exe 进程)的后端 ASP.NET Core 应用,称为进程外托管模型

开发者需要对这两类托管模型进行权衡。 默认情况下使用的是进程内托管模型,因为这样可以得到更好的性能和诊断。

 In-Process 进程内托管部署模式

  使用进程内托管,ASP.NET Core 应用运行在与 IIS 工作进程相同的进程(w3wp.exe)中(如果采用 IIS Express,则工作进程为 iisexpress.exe)。 进程内承载相较进程外承载提供更优的性能,因为请求并不通过环回适配器进行代理,环回适配器是一个网络接口,用于将传出的网络流量返回给同一计算机。 IIS 使用 Windows 进程激活服务 (WAS)处理进程管理。

下图说明了 IIS、ASP.NET Core 模块和进程内托管的应用之间的关系:

该模式下使用的服务器类型是 IISHttpServer。图中的 ASP.NET Core Module 会将原始的请求转发给这个服务器(IISHttpServer),并将 IISHttpServer 生成的响应转交给 IIS 服务器进行回复。

  In-Process 是默认采用的部署模式,所以不需要为此进行任何设置。关于IIS下部署ASP.NET Core 项目,请参考我的博客ASP.NET Core 6 基础入门系列(14) 项目发布与IIS部署

修改 Program.cs 文件,使用如下代码获取当前处理程序的名称

重新发布,再次访问,从下图的输出结果中可以看出 ASP.NET Core 应用实际上就是运行在IIS的工作进程(w3wp.exe)中。

查看发布目录,则会发现生成的程序集和配置文件如下图所示

应用既然部署在IIS中,那么具体的配置自然就定义在web.config中,查看该文件的内容如下图所示

(1)第6行中的 path="*" verb="*" 表明所有的请求都被映射到  AspNetCoreModuleV2 这个 module 上,这就是上面介绍的 ASP.NET Core Module。

(2)如果 Module 启动 ASP.NET Core 管道并与之交互,则由第8行的 <aspNetCore> 配置节中的 processPath 属性指定的应用程序来控制。

(3)第8行的 hostingModel="inprocess" 表示部署模式为进程内容托管。

  IISHttpServer 的注册实现在 IWebHostBuilder 接口的 UseIIS() 扩展方法中。由于这个扩展方法并没有提供一个 Action<IISServerOptions> 委托参数对 IISServerOptions 配置选项进行设置,所以不得不采用原始的方式对它进行设置。由于 IHostBuilder 接口的 ConfigureWebHostDefaults 扩展方法内部会调用这个方法,所以我们并不需要为此做额外的工作。

(一)启用进程内托管

自 ASP.NET Core 3.0 起,默认情况下已为部署到 IIS 的所有应用启用进程内托管。若要显式配置进程内托管的应用,请在项目文件 (.csproj) 中将 <AspNetCoreHostingModel> 属性的值设置为 InProcess

未使用 IIS 托管时,ASP.NET Core 项目模板默认使用 Kestrel 服务器。

(二)一般体系结构

请求的常规流程如下:

  1. 请求从 Web 到达内核模式 HTTP.sys 驱动程序。
  2. 驱动程序将本机请求路由到网站的配置端口上的 IIS,通常为 80 (HTTP) 或 443 (HTTPS)。
  3. ASP.NET Core Module 接收本机请求,并将其传递给 IIS HTTP 服务器 (IISHttpServer)。 (IIS HTTP 服务器是将请求从本机转换为托管的 IIS 进程内服务器实现)

在 IIS HTTP 服务器处理请求后:

  1. 请求被发送到 ASP.NET Core 中间件管道。
  2. 中间件管道处理该请求并将其作为 HttpContext 实例传递给应用的逻辑(如配置文件中配置的 processPath=".\DotNet6_Web_Study.exe" 对应的 DotNet6_Web_Study.dll)。
  3. 应用的响应通过 IIS HTTP 服务器传递回 IIS。 
  4. IIS 将响应发送到发起请求的客户端。

CreateDefaultBuilder 添加 IServer 实例的方式是:调用 UseIIS() 方法来启动 CoreCLR 和将应用托管在 IIS 工作进程(w3wp.exe 或 iisexpress.exe)内。 性能测试表明,与在进程外托管应用并将请求代理传入 Kestrel 相比,在进程中托管 .NET Core 应用可提供明显更高的请求吞吐量。 作为单个文件可执行文件发布的应用无法由进程内托管模型加载。

(三)应用程序配置

要配置 IIS 选项,请在 Program.cs 中包括 IISServerOptions 的服务配置。

    WebApplicationBuilder builder = WebApplication.CreateBuilder(args);

    builder.Services.Configure<IISServerOptions>(options =>
                                                 {
                                                     options.AllowSynchronousIO = true;
                                                 });

IISServerOptions中的所有属性及含义如下

 Out-of-Process 进程外托管部署模式

  ASP.NET Core用在 IIS 中还可以采用 Out-of-Process 模式进行部署。如下图所示

在这种部署模式下,采用 KestrelServer 的 ASP.NET Core 应用运行在独立的 dotnet.exe 进程中,ASP.NET Core Module 会负责进程管理。当IIS接收到目标应用的请求时,如果目标应用所在的进程并未启动,则 ASP.NET Core Module 还负责执行“dotnet”命令激活此进程,相当于充当了 WAS(Windows ActivationService)的作用。使用单独的进程还可以托管同一个应用池中的多个应用。

  1. 请求从 Web 到达内核模式 HTTP.sys 驱动程序。
  2. 驱动程序将请求路由到网站的配置端口上的 IIS。 配置的端口通常是 80 (HTTP) 或 443 (HTTPS)。
  3. 此模块将该请求转发到应用的随机端口上的 Kestrel。 随机端口不是 80 或 443。

  在激活 ASP.NET Core 承载进程之前,ASP.NET Core Module 会选择一个可用的端口,该端口和当前应用的路径(该路径将作用 ASPNET Core 应用的 PathBase)被写入环境变量,对应环境变量名称分别为“ASPNETCORE_PORT”和“ASPNETCORE_ APPL_PATH”。以 Out-Of-Process 模式部署 ASP.NET Core 应会接收 IIS 转发的请求,为了能够过滤其他来源的请求,ASP.NET Core Module 会生成一个 Token 并写入环境变量“ASPNETCORE_TOKEN”。后续转发的请求会利用一个报头“MS-ASPNETCORE-TOKEN”传递此Token, ASP.NET Core 应用校验是否与之前生成的Token匹配。

  ASPNET Core Module 还会利用环境变量传递其他设置,如认证方案被写入环境变量“ASPNETCORE _IIS_HTTPAUTH",另一个 “ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED环境变量用来设置 Web Socket的支持状态。由于这些环境变量名称的前缀都是“ASPNETCORE_”,所以它们都会作为默认配置源。KestrelServer 最终会绑定到基于该端口的本地址终节点(localhost)进行监听。由于监听地址是由 ASP.NET Core Module 控制的,所以它只需将请求转发到该地址,最终将接收到的响应交给IIS返回。由于这里涉及本地回环网(Loopback)的访问,其性能自然不如 In-Process 部署模式。

(一)启用进程外托管模型

编辑项目文件,修改配置如下

OutOfProcess 表示进程外托管。

(1)<AspNetCoreHostingModel> 的值不区分大小写,因此 inprocess 和 outofprocess 均为有效值。

(2)使用进程外托管应用时,使用 Kestrel 服务器,而不是 IIS HTTP 服务器 (IISHttpServer)。对于进程外托管,CreateDefaultBuilder 会调用 UseIISIntegration 来进行以下操作:

  • 在 ASP.NET Core Module 后运行时,配置服务器应侦听的端口和基本路径。
  • 配置主机以捕获启动错误。

要配置 IIS 选项,请在 ConfigureServices 中包括 IISOptions 的服务配置。

(二)进程名称

  将项目重新发布,查看发布后的web.config文件

第8行的 hostingModel="outofprocess" 表示为进程外托管。

通过下面的代码获取进程名称

浏览器中访问站点,从下图的输出结果中可以看出 ASP.NET Core 应用实际上就是运行在应用程序本身的进程中

修改web.config内容如下

浏览器中访问站点,从下图的输出结果中可以看出 ASP.NET Core 应用实际上就是运行在 dotnet.exe 进程中

(三)验证环境变量是否存在

通过以下代码逻辑来验证:

重新发布程序,在浏览器中访问

进程内和进程外托管之间的差异

在进程内托管时,将应用以下特征:

  • 使用 IIS HTTP 服务器 (IISHttpServer),而不是 Kestrel 服务器。 对于进程内托管,CreateDefaultBuilder 会调用 UseIIS 来进行以下操作:

    • 注册 IISHttpServer
    • 在 ASP.NET Core Module 后运行时,配置服务器应侦听的端口和基本路径。
    • 配置主机以捕获启动错误。
  • requestTimeout 属性不适用于进程内托管。

  • 不支持在应用之间共享应用池。 每个应用使用一个应用池。

  • 应用和已安装的运行时(x64 或 x86)的体系结构(位数)必须与应用池的体系结构匹配。 例如,为 32 位 (x86) 发布的应用必须已为其 IIS 应用程序池启用 32 位。 有关详细信息,请参阅创建 IIS 站点部分。

  • 检测到客户端连接断开。 客户端断开连接时,将取消 HttpContext.RequestAborted 取消标记。

  • 在进程内托管时,不会在内部调用 AuthenticateAsync 来初始化用户。 因此,默认情况下不激活每次身份验证后用于转换声明的 IClaimsTransformation 实现。 使用 IClaimsTransformation 实现转换声明时,请调用 AddAuthentication 以添加身份验证服务:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddTransient<IClaimsTransformation, MyClaimsTransformation>();
builder.Services.AddAuthentication(IISServerDefaults.AuthenticationScheme);
  • 不同的启动方式对应的服务器


参考文献:

  • 《使用 IIS 在 Windows 上托管 ASP.NET Core》https://learn.microsoft.com/zh-cn/aspnet/core/host-and-deploy/iis/?view=aspnetcore-6.0
  • 《用于 IIS 的 ASP.NET Core 模块 (ANCM)》https://learn.microsoft.com/zh-cn/aspnet/core/host-and-deploy/aspnet-core-module?view=aspnetcore-6.0
posted @   张传宁  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示
页脚 HTML 代码
点击右上角即可分享
微信分享提示