前言
上次,我们介绍了《如何获取 ASP.NET Core 启动地址》。
但是,如果要在 BackgroundService 中获取启动地址可不那么容易,因为 BackgroundService 在 app 启动前就开始执行了:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHostedService<DemoBackgroundService>();var app = builder.Build();app.MapGet("/", () => "Hello My IO!");await app.StartAsync();Console.WriteLine(app.Urls.First());await app.WaitForShutdownAsync();internal class DemoBackgroundService : BackgroundService
{protected override async Task ExecuteAsync(CancellationToken stoppingToken){Console.WriteLine("BackgroundService ExecuteAsync");await Task.CompletedTask;}
}
那要怎么实现呢?
IHostApplicationLifetime
我们可以利用ASP.NET Core应用程序生存期事件,等待启动完成再获取启动地址:
internal class DemoBackgroundService : BackgroundService
{private readonly IServiceProvider _services;private string _url;public DemoBackgroundService(IServiceProvider services, IHostApplicationLifetime lifetime){_services = services;lifetime.ApplicationStarted.Register(OnAppStarted);}public void OnAppStarted(){var server = _services.GetService<IServer>();_url = server.Features.Get<IServerAddressesFeature>().Addresses.First();}protected override async Task ExecuteAsync(CancellationToken stoppingToken){while (string.IsNullOrWhiteSpace(_url)){await Task.Delay(1000); }Console.WriteLine("BackgroundService ExecuteAsync");Console.WriteLine(_url);await Task.CompletedTask;}
}
现在可以正常获取 ASP.NET Core 启动地址了:
SemaphoreSlim
轮询虽然可以解决问题,但感觉不太优雅。
我们可以创建一个信号灯 SemaphoreSlim,在ExecuteAsync
方法中等待信号灯,而在启动后释放信号灯:
static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(0, 1);public void OnAppStarted()
{...semaphoreSlim.Release();
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{await semaphoreSlim.WaitAsync();...
}
可以看到,这样还带来了另外一个好处,比上面的解决方式更快地进入到了 BackgroundService:
结论
今天,我们利用了ASP.NET Core应用程序生存期事件,实现了在 BackgroundService 获取 ASP.NET Core 启动地址。
添加微信号【MyIO666】,邀你加入技术交流群