使用 IIS 和 ASP.NET Core 进行进程内托管

进程内托管在与其 IIS 工作进程相同的进程中运行 ASP.NET Core 应用。 进程内承载相较进程外承载提供更优的性能,因为请求并不通过环回适配器进行代理,环回适配器是一个网络接口,用于将传出的网络流量返回给同一计算机。

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

ASP.NET Core Module in the in-process hosting scenario

启用进程内托管

自 ASP.NET Core 3.0 起,默认情况下已为部署到 IIS 的所有应用启用进程内托管。

若要显式配置进程内托管的应用,请在项目文件 (.csproj) 中将 <AspNetCoreHostingModel> 属性的值设置为 InProcess

<PropertyGroup>
  <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>

一般体系结构

请求的常规流程如下:

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

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

  1. 请求被发送到 ASP.NET Core 中间件管道。
  2. 中间件管道处理该请求并将其作为 HttpContext 实例传递给应用的逻辑。
  3. 应用的响应通过 IIS HTTP 服务器传递回 IIS。
  4. IIS 将响应发送到发起请求的客户端。

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

作为单个文件可执行文件发布的应用无法由进程内托管模型加载。

应用程序配置

要配置 IIS 选项,请在 Program.cs 中包括 IISServerOptions 的服务配置。 下面的示例将禁用 AutomaticAuthentication

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Server.IIS;
using Microsoft.EntityFrameworkCore;
using RPauth.Data;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();

builder.Services.Configure<IISServerOptions>(options =>
{
    options.AutomaticAuthentication = false;
});

builder.Services.AddTransient<IClaimsTransformation, MyClaimsTransformation>();
builder.Services.AddAuthentication(IISServerDefaults.AuthenticationScheme);

builder.Services.AddRazorPages();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapRazorPages();

app.Run();
选项 默认 设置
AutomaticAuthentication true 若为 true,IIS 服务器将设置经过 Windows 身份验证进行身份验证的 HttpContext.User。 若为 false,服务器仅提供 HttpContext.User 的标识并在 AuthenticationScheme 显式请求时响应质询。 必须在 IIS 中启用 Windows 身份验证使 AutomaticAuthentication 得以运行。 有关详细信息,请参阅 Windows 身份验证
AuthenticationDisplayName null 设置在登录页上向用户显示的显示名。
AllowSynchronousIO false HttpContext.RequestHttpContext.Response 是否允许同步 I/O。
MaxRequestBodySize 30000000 获取或设置 HttpRequest 的最大请求正文大小。 请注意,IIS 本身有限制 maxAllowedContentLength,这一限制将在 IISServerOptions 中设置 MaxRequestBodySize 之前进行处理。 更改 MaxRequestBodySize 不会影响 maxAllowedContentLength。 若要增加 maxAllowedContentLength,请在 web.config 中添加一个将 maxAllowedContentLength 设置为更高值的项。 有关更多详细信息,请参阅配置

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

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

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

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

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

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

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

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

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Server.IIS;
using Microsoft.EntityFrameworkCore;
using RPauth.Data;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();

builder.Services.Configure<IISServerOptions>(options =>
{
    options.AutomaticAuthentication = false;
});

builder.Services.AddTransient<IClaimsTransformation, MyClaimsTransformation>();
builder.Services.AddAuthentication(IISServerDefaults.AuthenticationScheme);

builder.Services.AddRazorPages();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapRazorPages();

app.Run();

进程内托管在与其 IIS 工作进程相同的进程中运行 ASP.NET Core 应用。 进程内承载相较进程外承载提供更优的性能,因为请求并不通过环回适配器进行代理,环回适配器是一个网络接口,用于将传出的网络流量返回给同一计算机。

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

ASP.NET Core Module in the in-process hosting scenario

启用进程内托管

自 ASP.NET Core 3.0 起,默认情况下已为部署到 IIS 的所有应用启用进程内托管。

若要显式配置进程内托管的应用,请在项目文件 (.csproj) 中将 <AspNetCoreHostingModel> 属性的值设置为 InProcess

<PropertyGroup>
  <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>

一般体系结构

请求的常规流程如下:

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

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

  1. 请求被发送到 ASP.NET Core 中间件管道。
  2. 中间件管道处理该请求并将其作为 HttpContext 实例传递给应用的逻辑。
  3. 应用的响应通过 IIS HTTP 服务器传递回 IIS。
  4. IIS 将响应发送到发起请求的客户端。

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

作为单个文件可执行文件发布的应用无法由进程内托管模型加载。

应用程序配置

要配置 IIS 选项,请在 ConfigureServices 中包括 IISServerOptions 的服务配置。 下面的示例禁用 AutomaticAuthentication:

services.Configure<IISServerOptions>(options => 
{
    options.AutomaticAuthentication = false;
});
选项 默认 设置
AutomaticAuthentication true 若为 true,IIS 服务器将设置经过 Windows 身份验证进行身份验证的 HttpContext.User。 若为 false,服务器仅提供 HttpContext.User 的标识并在 AuthenticationScheme 显式请求时响应质询。 必须在 IIS 中启用 Windows 身份验证使 AutomaticAuthentication 得以运行。 有关详细信息,请参阅 Windows 身份验证
AuthenticationDisplayName null 设置在登录页上向用户显示的显示名。
AllowSynchronousIO false HttpContext.RequestHttpContext.Response 是否允许同步 I/O。
MaxRequestBodySize 30000000 获取或设置 HttpRequest 的最大请求正文大小。 请注意,IIS 本身有限制 maxAllowedContentLength,这一限制将在 IISServerOptions 中设置 MaxRequestBodySize 之前进行处理。 更改 MaxRequestBodySize 不会影响 maxAllowedContentLength。 若要增加 maxAllowedContentLength,请在 web.config 中添加一个将 maxAllowedContentLength 设置为更高值的项。 有关更多详细信息,请参阅配置

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

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

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

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

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

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

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

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

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddTransient<IClaimsTransformation, ClaimsTransformer>();
        services.AddAuthentication(IISServerDefaults.AuthenticationScheme);
    }
    
    public void Configure(IApplicationBuilder app)
    {
        app.UseAuthentication();
    }
    
  • 不支持 Web 包(单文件)部署