如果 asp.net core 服务需要先访问外部的 API,才能完全启动服务,需要怎么做呢?
有两个办法可以解决这个问题。
方法1:创建一个IHost扩展方法
首先创建一个类似于下面代码的扩展类,为 IHost 类增加一个 PostStart 方法。
public static class PostStartHostExtention
{
public static IHost PostStart(this IHost host)
{
using(var scope = host.Services.CreateScope())
{
var serviceProvider = scope.ServiceProvider;
// 在这里加上你的初始化方法
return host;
}
}
}
然后,给 CreateHostBuilder 流式方法中增加调用 PostStart, 注意一定要在调用 Run 方法之前调用它。
logger.Debug("Starting host...");
CreateHostBuilder(args)
.Build()
.PostStart() // 在这里调用PostStart
.Run();
这样我们就可以在正式启动服务前完成任何初始化操作了。
这种初始化方式需要我们写一个扩展方法,这个扩展方法是不支持异步执行的。所以你需要同步调用外部api,这样你的服务或者控制台程序会有一段时间失去响应。下面介绍的方法可以解决这个问题。
方法2:通过增加一个 IHostedService
asp.net core 支持增加后台服务,比如你需要定期更新token。使用这种方式,asp.net core 可以帮助我们实现后台服务的全生命周期管理。这样我们就有机会处理服务启动,运行中以及停止时的事件了。
如果你使用StartUp类,那么你可以在 ConfigureServices 方法中增加下面的代码来创建一个托管服务。
services.AddHostedService<MyHostedService>();
这个托管服务需要实现 IHostedService 和 IDisposable 接口。下面是一个来自微软的完整示例。
public class TimedHostedService : IHostedService, IDisposable
{
private int executionCount = 0;
private readonly ILogger<TimedHostedService> _logger;
private Timer _timer;
public TimedHostedService(ILogger<TimedHostedService> logger)
{
_logger = logger;
}
public Task StartAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Timed Hosted Service running.");
_timer = new Timer(DoWork, null, TimeSpan.Zero,
TimeSpan.FromSeconds(5));
return Task.CompletedTask;
}
private void DoWork(object state)
{
var count = Interlocked.Increment(ref executionCount);
_logger.LogInformation(
"Timed Hosted Service is working. Count: {Count}", count);
}
public Task StopAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Timed Hosted Service is stopping.");
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
我们可以在 StartAsync 中处理服务启动前的任务。在 StopAsync 中处理 asp.net core 停止时的任务。