写在前面
停了近一个月的技术博客,随着正式脱离996的魔窟,接下来也正式恢复了。本文从源码角度进一步讨论.NET Core 3.0 中关于Host扩展的一些技术点,主要内容是关于创建Long Run Program的创建与守护。
关于Host,我们最容易想到的就是程序的启动与停止,而其中隐藏着非常关键的功能,就是Host的初始化,我们所需要的所有资源都必须而且应该在程序启动过程中初始化完成,当然本文的主要内容并不是Host初始化。当然,为了更好的守护与管理已经启动的Host,.NET Core 3.0将程序的生命周期事件的订阅开放给开发者,当然也包括自定义的Host Service对象。
注:本文代码基于.NET Core 3.0 Preview9
.NET Core 3.0中创建Long Run Program
IHost与IHostBuilder
当我们创建Long Run Program时,会首先关注程序的启动与停止,.NET Core 3.0为此提供了一个接口IHost,该接口位于Microsoft.Extensions.Hosting类库中,其源码如下:
该接口含有一个只读属性:IServiceProvider Services { get; },通过该属性,我们可以拿到所有Host初始化时所注入的对象信息。
IHostBuilder接口所承担的核心功能就是程序的初始化,通过:IHost Build()来完成,当然只需要运行一次即可。其初始化内容一般包括以下几个功能:
另外需要说明的是,以上功能的初始化,是通过IHostBuilder提供的接口获取用户输入的信息后,通过调用Build()方法来完成初始化。以下为IHostBuilder的部分源代码:
IHostService
文章开头有说过自定义Host Service对象,那么我们如何自定义呢,其实很简单只需要实现IHostService,并在ConfigureServices中调用services.AddHostedService<MyServiceA>()即可,以下是IHostService的源码:
根据源码我们可以知道,该接口只有两个方法,即代码程序开始与停止的方法。具体的实现可以参考如下:
IHostService是我们自定义Host管理对象的入口,所有需要压入到Host托管的对象都必须要实现此接口。
Host生命周期的管理
该接口提供了一种我们可以在程序运行期间进行管理的功能,如程序的启动与停止事件的订阅,关于Host生命周期的管理,主要由IHostApplicationLifetime和IHostLifetime这两个接口来完成。
以下是IHostApplicationLifetime的源码
IHostLifetime源码如下:
public interface IHostLifetime
{ /// <summary> /// Called at the start of <see cref="IHost.StartAsync(CancellationToken)"/> which will wait until it's complete before /// continuing. This can be used to delay startup until signaled by an external event. /// </summary> /// <param name="cancellationToken">Used to indicate when stop should no longer be graceful.</param> /// <returns>A <see cref="Task"/>.</returns> Task WaitForStartAsync(CancellationToken cancellationToken); /// <summary> /// Called from <see cref="IHost.StopAsync(CancellationToken)"/> to indicate that the host is stopping and it's time to shut down. /// </summary> /// <param name="cancellationToken">Used to indicate when stop should no longer be graceful.</param> /// <returns>A <see cref="Task"/>.</returns> Task StopAsync(CancellationToken cancellationToken);
}
具体的使用可以参考如下代码:
public class MyLifetime : IHostLifetime, IDisposable
{ ......... private IHostApplicationLifetime ApplicationLifetime { get; } public ConsoleLifetime(IHostApplicationLifetime applicationLifetime) { ApplicationLifetime = applicationLifetime ?? throw new ArgumentNullException(nameof(applicationLifetime)); } public Task WaitForStartAsync(CancellationToken cancellationToken) { _applicationStartedRegistration = ApplicationLifetime.ApplicationStarted.Register(state => { ((ConsoleLifetime)state).OnApplicationStarted(); }, this); _applicationStoppingRegistration = ApplicationLifetime.ApplicationStopping.Register(state => { ((ConsoleLifetime)state).OnApplicationStopping(); }, this); ....... return Task.CompletedTask; } private void OnApplicationStarted() { Logger.LogInformation("Application started. Press Ctrl+C to shut down."); Logger.LogInformation("Hosting environment: {envName}", Environment.EnvironmentName); Logger.LogInformation("Content root path: {contentRoot}", Environment.ContentRootPath); } private void OnApplicationStopping() { Logger.LogInformation("Application is shutting down..."); } ........
}
总结
至此,我们知道了创建Long Run Program所需要关注的几个点,分别是继承IHostService、订阅程序的生命周期时间以及Host的初始化过程。相对来说这段内容还是比较简单的,但是开发过程中,依然会遇到很多的问题,比如任务的定时机制、MQ的接入、以及程序的性能优化等等,这些都需要我们在实践中进一步总结完善。