Intro
.NET 8 里针对 Host 做了一些更新,除了前面提到的 IHostedLifecycleService
之外,还支持的 HostedService
的并发地启动和停止,还抽象了在 .NET 7 开始支持的 HostApplicationBuilder
引入了 IHostApplicationBuilder
API,并且引入了一个 Host.CreateEmptyApplicationBuilder
来简化配置一个空的 Host.
Sample
var hostBuilder = Host.CreateEmptyApplicationBuilder(null);
hostBuilder.ConfigureHostOptions(x =>
{
x.ServicesStartConcurrently = true;
x.ServicesStopConcurrently = true;
x.StartupTimeout = TimeSpan.FromMilliseconds(100);
});
hostBuilder.Services.AddHostedService<DelayService>();
hostBuilder.Services.AddHostedService<ReportTimeService>();
var host = hostBuilder.Build();
await host.RunAsync(cancellationToken);
Host.CreateEmptyApplicationBuilder
是 .NET 8 里新增的一个 API 会创建一个空的 Host,不会注册 json,环境变量等配置,不会注册默认的服务如日志配置等
这里的 ConfigureHostOptions
是自己做了一个封装,为了类似于 IHostBuilder
一样简化 HostOptions
的配置,实现如下:
public static IHostApplicationBuilder ConfigureHostOptions(this IHostApplicationBuilder hostBuilder, Action<HostOptions> configureOptions)
{
hostBuilder.Services.Configure(configureOptions);
return hostBuilder;
}
HostOptions
里的 ServicesStartConcurrently
/ServicesStopConcurrently
以及 StartupTimeout
是 .NET 8 里新增的配置,两个 Concurrently
是一起新增的,默认值是 false
,StartupTimeout
是和前面介绍的 IHostedLifecycleService
一起新增的,上次没有提起觉得放在这里更加合适,默认没有限制
DelayService 实现如下:
file class DelayService : IHostedService
{
public async Task StartAsync(CancellationToken cancellationToken)
{
await Task.Delay(TimeSpan.FromMilliseconds(60), cancellationToken);
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
file sealed class Delay2Service : DelayService
{
}
为了更好查看效果,增加一个报告时间的后台服务,每秒钟打印一次时间:
file sealed class ReportTimeService : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
using var timer = new PeriodicTimer(TimeSpan.FromSeconds(1));
while (await timer.WaitForNextTickAsync(stoppingToken))
{
Console.WriteLine(DateTimeOffset.Now);
}
}
}
前面示例我们设置的启动超时时间是 100ms,两个 delay service 分别是 60ms,如果串行启动的话则会超时,并行启动的话应该不会超时,我们来测试一下,首先我们把两个 concurrently 的配置去掉使用默认值 false
启动
再把他们加回来,并行启动试一下
可以看到设置为 true 之后就可以正常启动起来了
More
Host.CreateEmptyApplicationBuilder
这个方法是为了 AOT,之前的方法会加载一系列的配置导致 AOT 变得困难,尤其是 console logging 相关的组件影响,并且这一方法也是 asp.net 里新加的 WebApplication.CreateSlimBuilder()
/WebApplication.CreateEmptyBuilder()
的基础,这两个方法也是为了 AOT 的需求,这两个方法和原来的 WebApplication.CreateBuilder()
我们后面有机会再单独介绍一下
ServicesStartConcurrently
/ServicesStopConcurrently
默认是 false
,如果项目里有比较多的 HostedService
影响服务启动的时候可以考虑这一配置,但是如果想要设置为 true
需要考虑一下有没有启动顺序的要求,如果有启动顺序的要求则不适合使用这一配置,前面介绍的 IHostedLifecycleService
也会受这两个参数的影响,如果设置为 true 的话他们也是并发执行
针对 Host.CreateEmptyApplicationBuilder
这一方法,方法签名如下:
public static HostApplicationBuilder CreateEmptyApplicationBuilder(HostApplicationBuilderSettings? settings)
觉得既然 settings
参数允许为 null
, 应该有个默认值 null
,这样也就不需要像前面示例一样还要显式的传递一个 null
,提了一个 issue 希望能够增加一个没有参数的重载或者设置一个默认值 https://github.com/dotnet/runtime/issues/90477
另外一个就是前面的 ConfigureHostOptions
方法,既然针对 IHostBuilder
有 ConfigureHostOptions
的扩展,针对 IHostApplicationBuilder
感觉也应该有这一扩展来简化 host 的配置,也提了一个 issue https://github.com/dotnet/runtime/issues/90478
目前两个 issue 的 milestone 都是 9.0,8.0 大概是不会有了