配置相关

URL&Port

设置端口

  Properties/launchSettings.json 文件,该文件指定应用响应的端口。或通过如下方式:

1
2
3
4
5
var app = WebApplication.Create(args);

app.MapGet("/", () => "Hello World!");

app.Run("http://localhost:3000");

设置多个端口

  在以下代码中,应用响应端口 3000 和 4000。

1
2
3
4
5
6
7
8
var app = WebApplication.Create(args);

app.Urls.Add("http://localhost:3000");
app.Urls.Add("http://localhost:4000");

app.MapGet("/", () => "Hello World");

app.Run();

从命令行设置端口

  以下命令使应用响应端口 7777:

1
dotnet run --urls="https://localhost:7777"

  如果在 appsettings.json 文件中也配置了 Kestrel 终结点,则使用 appsettings.json 文件指定的 URL。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"Kestrel": {
"Endpoints": {
"Https": {
"Url": "https://localhost:9999"
}
}
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}

从环境中读取端口

  以下代码从环境中读取端口:

1
2
3
4
5
6
7
var app = WebApplication.Create(args);

var port = Environment.GetEnvironmentVariable("PORT") ?? "3000";

app.MapGet("/", () => "Hello World");

app.Run($"http://localhost:{port}");

  从环境设置端口的首选方法为使用 ASPNETCORE_URLS 环境变量,如以下部分所示。

ASPNETCORE_URLS 环境变量可用于设置端口:

1
ASPNETCORE_URLS=http://localhost:3000

ASPNETCORE_URLS 支持多个 URL:

1
ASPNETCORE_URLS=http://localhost:3000;https://localhost:5000

侦听所有接口

  以下示例演示如何侦听所有接口

1
2
3
4
5
6
7
8
9
10
var app = WebApplication.Create(args);

// 以下三种方式,选择其一即可
app.Urls.Add("http://*:3000");
app.Urls.Add("http://+:3000");
app.Urls.Add("http://0.0.0.0:3000");

app.MapGet("/", () => "Hello World");

app.Run();

使用 ASPNETCORE_URLS 侦听所有接口

1
ASPNETCORE_URLS=http://*:3000;https://+:5000;http://0.0.0.0:5005

使用 ASPNETCORE_HTTPS_PORTS 侦听所有接口

1
2
ASPNETCORE_HTTP_PORTS=3000;5005
ASPNETCORE_HTTPS_PORTS=5000

HTTPS开发证书配置

配置文件配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"Kestrel": {
"Certificates": {
"Default": {
"Path": "cert.pem",
"KeyPath": "key.pem"
}
}
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
var builder = WebApplication.CreateBuilder(args);

// Configure the cert and the key
builder.Configuration["Kestrel:Certificates:Default:Path"] = "cert.pem";
builder.Configuration["Kestrel:Certificates:Default:KeyPath"] = "key.pem";

var app = builder.Build();

app.Urls.Add("https://localhost:3000");

app.MapGet("/", () => "Hello World");

app.Run();

使用证书API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System.Security.Cryptography.X509Certificates;

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.ConfigureKestrel(options =>
{
options.ConfigureHttpsDefaults(httpsOptions =>
{
var certPath = Path.Combine(builder.Environment.ContentRootPath, "cert.pem");
var keyPath = Path.Combine(builder.Environment.ContentRootPath, "key.pem");

httpsOptions.ServerCertificate = X509Certificate2.CreateFromPemFile(certPath,
keyPath);
});
});

var app = builder.Build();

app.Urls.Add("https://localhost:3000");

app.MapGet("/", () => "Hello World");

app.Run();

读取环境

1
2
3
4
5
6
var app = WebApplication.Create(args);

app.Environment.IsDevelopment(); // 是否是开发环境
app.Environment.IsProduction(); // 是否是生产环境
app.Environment.IsStaging(); // 是否是测试环境
app.Environment.IsEnvironment("Preview"); // 是否是指定的环境

配置

读取配置

  以下代码从配置系统读取:默认情况下,WebApplicationBuilder 从多个源读取配置,包括:

  • appSettings.json 和 appSettings.{environment}.json
  • 环境变量
  • 命令行
1
2
3
4
5
6
7
var app = WebApplication.Create(args);

var message = app.Configuration["HelloKey"] ?? "Config failed!";

app.MapGet("/", () => message);

app.Run();

添加配置

  以下示例添加 INI 配置提供程序:

1
2
3
4
5
var builder = WebApplication.CreateBuilder(args);

builder.Configuration.AddIniFile("appsettings.ini");

var app = builder.Build();

日志

使用日志

  以下代码在应用程序启动时将消息写入日志:

1
2
3
4
5
6
7
var app = WebApplication.Create(args);

app.Logger.LogInformation("The app started");

app.MapGet("/", () => "Hello World");

app.Run();

添加日志提供程序

1
2
3
4
5
6
7
8
9
10
var builder = WebApplication.CreateBuilder(args);

// Configure JSON logging to the console.
builder.Logging.AddJsonConsole();

var app = builder.Build();

app.MapGet("/", () => "Hello JSON console!");

app.Run();

服务

获取容器内服务

  下面的代码演示如何在应用程序启动过程中从 DI 容器获取服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddScoped<SampleService>();

var app = builder.Build();

app.MapControllers();

using (var scope = app.Services.CreateScope())
{
var sampleService = scope.ServiceProvider.GetRequiredService<SampleService>();
sampleService.DoSomething();
}

app.Run();

  以下代码演示如何使用 [FromKeyedServices] 属性从 DI 容器访问密钥:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddKeyedSingleton<ICache, BigCache>("big");
builder.Services.AddKeyedSingleton<ICache, SmallCache>("small");

var app = builder.Build();

app.MapGet("/big", ([FromKeyedServices("big")] ICache bigCache) => bigCache.Get("date"));

app.MapGet("/small", ([FromKeyedServices("small")] ICache smallCache) => smallCache.Get("date"));

app.Run();

public interface ICache
{
object Get(string key);
}
public class BigCache : ICache
{
public object Get(string key) => $"Resolving {key} from big cache.";
}

public class SmallCache : ICache
{
public object Get(string key) => $"Resolving {key} from small cache.";
}

注册服务

1
2
3
4
5
6
7
8
9
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddTransient<IMyService,MyService>(); // 瞬时
builder.Services.AddScoped<IMyService,MyService>(); // 作用域
builder.Services.AddSingleton<IMyService,MyService>(); // 单例

var app = builder.Build();

app.Run();

更改默认DI容器

1
2
3
4
5
6
7
8
9
var builder = WebApplication.CreateBuilder(args);

builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());

// Register services directly with Autofac here. Don't
// call builder.Populate(), that happens in AutofacServiceProviderFactory.
builder.Host.ConfigureContainer<ContainerBuilder>(builder => builder.RegisterModule(new MyApplicationModule()));

var app = builder.Build();

更改应用程序信息

  以下代码设置内容根、应用程序名称和环境:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
Args = args,
ApplicationName = typeof(Program).Assembly.FullName,
ContentRootPath = Directory.GetCurrentDirectory(),
EnvironmentName = Environments.Staging,
WebRootPath = "customwwwroot"
});

Console.WriteLine($"Application Name: {builder.Environment.ApplicationName}");
Console.WriteLine($"Environment Name: {builder.Environment.EnvironmentName}");
Console.WriteLine($"ContentRoot Path: {builder.Environment.ContentRootPath}");
Console.WriteLine($"WebRootPath: {builder.Environment.WebRootPath}");

var app = builder.Build();

也可以通过环境变量或命令行的方式修改以上信息

  下表显示了用于更改内容根、应用程序名称和环境的环境变量及命令行参数:

feature 环境变量 命令行参数
应用程序名称 ASPNETCORE_APPLICATIONNAME –applicationName
环境名称 ASPNETCORE_ENVIRONMENT –environment
内容根 ASPNETCORE_CONTENTROOT –contentRoot

泛型主机

主机定义

  主机是封装应用资源的对象,例如:

  • 依赖关系注入(DI)
  • Logging
  • Configuration
  • IHostedService实现

  当主机启动时,它将对在托管服务的服务容器集合中注册的IHostedService的每个实现调用IHostedService.StartAsync。在web应用中,其中一个IHostedService实现是启动IHostedService的web服务。

  将应用的所有相互依赖资源包括在一个对象中可控制应用启动和正常关闭。

设置主机

  主机通常由Program.cs中的代码配置、生成和运行。以下代码会使用添加到DI容器中的IHostedService实现创建一个主机:

1
2
3
4
5
6
7
await Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddHostedService<SampleHostedService>();
})
.Build()
.RunAsync();

  对于 HTTP 工作负载,在 CreateDefaultBuilder 之后调用 ConfigureWebHostDefaults:

1
2
3
4
5
6
7
await Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.Build()
.RunAsync();

默认生成器设置

  • CreateDefaultBuilder方法
    • 内容根目录设置为由GetCurrentDiectory返回的路径
    • 通过以下对象加载主机配置:
      • 前缀为DOTNET_的环境变量
      • 命令行参数
    • 通过以下对象加载应用配置:
      • appsettings.json
      • appsettings.{Environment}.json
      • 应用在Development环境中运行时的用户机密
      • 环境变量
      • 命令行参数
    • 添加日志记录提供程序:
      • 控制台
      • 调试
      • EventSource
      • EventLog(仅当在Windows上运行时)
    • 当环境为“开发”时,启动范围验证和依赖关系验证
  • ConfigureWebHostDefaults方法
    • 从前缀为 ASPNETCORE_ 的环境变量加载主机配置。
    • 使用应用的托管配置提供程序将 Kestrel 服务器设置为 web 服务器并对其进行配置。
    • 添加主机筛选中间件。
    • 如果 ASPNETCORE_FORWARDEDHEADERS_ENABLED 等于 true,则添加转接头中间件。
    • 支持 IIS 集成

框架提供的服务

  自动注入以下服务:

服务 描述
IHostApplicationLifetime 将 IHostApplicationLifetime(以前称为 IApplicationLifetime)服务注入任何类以处理启动后和正常关闭任务。 接口上的三个属性是用于注册应用启动和应用停止事件处理程序方法的取消令牌。 接口还包括一个 StopApplication 方法,该方法允许应用请求正常关闭。
IHostLifetime IHostLifetime 实现控制主机何时启动和何时停止。 使用了已注册的最后一个实现。Microsoft.Extensions.Hosting.Internal.ConsoleLifetime 是默认的 IHostLifetime 实现。
IHostEnvironment/IWebHostEnvironment 将 IHostEnvironment 服务注册到一个类,获取关于以下设置的信息:ApplicationName、EnvironmentName、ContentRootPath。Web 应用实现 IWebHostEnvironment 接口,该接口继承 IHostEnvironment 并添加 IWebHostEnvironment。

主机配置

  主机配置用于 IHostEnvironment 实现的属性。
  CreateDefaultBuilder 包含前缀为 DOTNET_ 的环境变量提供程序和命令行参数。 对于 web 应用程序,添加前缀为 ASPNETCORE_ 的环境变量提供程序。 当系统读取环境变量时,便会删除前缀。 例如,ASPNETCORE_ENVIRONMENT 的环境变量值就变成 environment 密钥的主机配置值。

1
2
3
4
5
6
7
8
Host.CreateDefaultBuilder(args)
.ConfigureHostConfiguration(hostConfig =>
{
hostConfig.SetBasePath(Directory.GetCurrentDirectory());
hostConfig.AddJsonFile("hostsettings.json", optional: true);
hostConfig.AddEnvironmentVariables(prefix: "PREFIX_");
hostConfig.AddCommandLine(args);
});

应用配置

  可以在 HostBuilderContext.Configuration 中获取由 ConfigureAppConfiguration 创建的配置以用于后续操作,并将其作为 DI 的服务。 主机配置也会添加到应用配置。

1
2
3
4
5
6
7
8
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((builderContext, configureationBuilder) =>
{
var env = builderContext.HostingEnvironment;

// 添加一个自定义的配置文件,比如 appsettings.Development.json
configureationBuilder.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
});

适用于Web应用的设置

  一些主机设置仅适用于 HTTP 工作负荷。 默认情况下,用于配置这些设置的环境变量可以有一个 DOTNET_ 或 ASPNETCORE_ 前缀,该前缀在以下设置列表中显示为 {PREFIX_} 占位符。

  IWebHostBuilder 上的扩展方法适用于这些设置。 显示如何调用扩展方法的示例代码假定 webBuilder 是 IWebHostBuilder 的实例,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.CaptureStartupErrors(true); // 捕获启动时的错误
webBuilder.UseSetting(WebHostDefaults.DetailedErrorsKey, "true"); // 环境为 Development时,应用会捕获详细错误
webBuilder.UseSetting(WebHostDefaults.HostingStartupAssembliesKey, "assembly1;assembly2"); // 启动时一并加载的程序集
webBuilder.UseSetting(WebHostDefaults.HostingStartupExcludeAssembliesKey, "assembly1;assembly2"); // 启动时要排除加载的程序集
webBuilder.UseSetting("https_port", "8080"); // HTTPS 重定向端口。
webBuilder.PreferHostingUrls(true); // 指示主机是否应该侦听使用 IWebHostBuilder 配置的 URL,而不是使用 IServer 实现配置的 URL。
webBuilder.UseSetting(WebHostDefaults.PreventHostingStartupKey, "true"); // 阻止承载启动程序集自动加载,包括应用的程序集所配置的承载启动程序集。

/*若要设置此值,请使用环境变量或调用 UseStartup。 UseStartup 可以采用程序集名称 (string) 或类型 (TStartup)。 如果调用多个 UseStartup 方法,优先选择最后一个方法。*/
webBuilder.UseStartup("StartupAssemblyName");
webBuilder.UseStartup<Startup>();

webBuilder.UseSetting(WebHostDefaults.SuppressStatusMessagesKey, "true"); // 启用后,将取消承载启动状态消息。
webBuilder.UseUrls("http://*:5000;http://localhost:5001;https://hostname:5002"); // 设置监听URL地址
webBuilder.UseWebRoot("public"); // 确定应用静态资产的相对路径,默认为wwwroot
});
配置 说明 类型 默认值 环境变量
CaptureStartupErrors 当 false 时,启动期间出错导致主机退出。 当 true 时,主机在启动期间捕获异常并尝试启动服务器。 bool 默认为 false,除非应用使用 Kestrel 在 IIS 后方运行,其中默认值是 true。 {PREFIX_}CAPTURESTARTUPERRORS
DetailedErrors 如果启用,或环境为 Development,应用会捕获详细错误。 bool false {PREFIX_}DETAILEDERRORS
HostingStartupAssemblies 承载启动程序集的以分号分隔的字符串在启动时加载。 虽然配置值默认为空字符串,但是承载启动程序集会始终包含应用的程序集。 提供承载启动程序集时,当应用在启动过程中生成其公用服务时将它们添加到应用的程序集加载。 string 空字符串 {PREFIX_}HOSTINGSTARTUPASSEMBLIES
HostingStartupExcludeAssemblies 承载启动程序集的以分号分隔的字符串在启动时排除。 string 空字符串 {PREFIX_}HOSTINGSTARTUPEXCLUDEASSEMBLIES
HTTPS_Port HTTPS 重定向端口。 用于强制实施 HTTPS。 string 未设置默认值 {PREFIX_}HTTPS_PORT
PreferHostingUrls 指示主机是否应该侦听使用 IWebHostBuilder 配置的 URL,而不是使用 IServer 实现配置的 URL。 bool false {PREFIX_}PREFERHOSTINGURLS
PreventHostingStartup 阻止承载启动程序集自动加载,包括应用的程序集所配置的承载启动程序集。 bool false {PREFIX_}PREVENTHOSTINGSTARTUP
StartupAssembly 要搜索 Startup 类的程序集。 string 应用的程序集 {PREFIX_}STARTUPASSEMBLY
SuppressStatusMessages 启用后,将取消承载启动状态消息。 bool false {PREFIX_}SUPPRESSSTATUSMESSAGES
URL IP 地址或主机地址的分号分隔列表,其中包含服务器应针对请求侦听的端口和协议。 例如 http://localhost:123。 使用“”指示服务器应针对请求侦听的使用特定端口和协议(例如 http://:5000)的 IP 地址或主机名。 协议(http:// 或 https://)必须包含每个 URL。 不同的服务器支持的格式有所不同。 string localhost:5000 {PREFIX_}URLS
WebRoot 确定应用静态资产的相对路径。 如果该路径不存在,则使用无操作文件提供程序。 string wwwroot {PREFIX_}WEBROOT

管理主机生存期

  对生成的 IHost 实现调用方法,以启动和停止应用。 这些方法会影响所有在服务容器中注册的 IHostedService 实现。

  Run*Start* 方法之间的差异是 Run* 方法会在返回之前等待主机完成,而 Start* 方法会立即返回。 Run* 方法通常用于控制台应用,而 Start* 方法则通常用于长期运行的服务中。

  • Run*函数
    • Run() :运行应用并阻止调用线程,直到关闭主机。
    • RunAsync: 运行应用并返回在触发取消令牌或关闭时完成的 Task。
    • RunConsoleAsync: 启用控制台支持、生成和启动主机,以及等待 Ctrl+C/SIGINT (Windows)、⌘+C (macOS) 或 SIGTERM 关闭。
  • Start*函数
    • Start() :同步启动主机。
    • StartAsync() :启动主机并返回在触发取消令牌或关闭时完成的 Task。在 StartAsync 开始时调用 WaitForStartAsync,在继续之前,会一直等待该操作完成。 此方法可用于延迟启动,直到外部事件发出信号。
  • 停止函数
    • StopAsync() :尝试在提供的超时时间内停止主机。
    • WaitForShutdown() :阻止调用线程,直到 IHostLifetime 触发关闭,例如通过 Ctrl+C/SIGINT (Windows)、⌘+C (macOS) 或 SIGTERM。
    • WaitForShutdownAsync :返回在通过给定的令牌和调用 StopAsync 来触发关闭时完成的 Task。