Skip to main content

.Net Host提供的服务和接口

分类:  .Net技术 标签:  #基础 #.Net #.Net Host 发布于: 2023-06-15 15:46:11

我们前面一篇文章里学习了怎么快速的设置一个Host, 并且介绍了在设置Host的每一步里每个方法需要完成哪些配置或者动作,我们这一章来学习.Net基于Host模型提供了哪些服务和接口,这些服务和接口是如何方便用户使用的。

Host提供的服务

我们前面介绍了当设置一个Host时会自动创建一个依赖注入容器,同时作为一个框架也会随着容器的创建并自动注入一相应的服务,主要有如下的服务:

  • IHostApplicationLifeTime
  • IHostLifetime
  • IHostEnvironment

IHostApplicationLifetime

实现了这个接口的服务主要用于给用户的应用一个和Hoststartedstoppingstopped几个事件进行交互,当Host里的应用发生这些事件时,用户应用监听这些事件并完成相应的动作。

我们使用如下的例子来看一下这个服务的用法:

dotnet new worker -o WorkerDemo1
cd WorkerDemo1
code .

需要注意的是我们这里使用了.Net自带的模板worker创建了一个基于worker的示例应用,使用VS Code打开了应用目录之后,编辑文件Worker.cs, 使用如下的内容替换:

namespace WorkerDemo1;

public class Worker : IHostedService
{
    private readonly ILogger<Worker> _logger;

    public Worker(ILogger<Worker> logger, 
    IHostApplicationLifetime applicationLifetime 
    )
    {
        _logger = logger;
        applicationLifetime.ApplicationStarted.Register(OnStarted);
        applicationLifetime.ApplicationStopping.Register(OnStopping);
        applicationLifetime.ApplicationStopped.Register(OnStopped);

    }

    public async Task StartAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("1. StartAsync has been called.");
        await Task.CompletedTask;
    }

    public async Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("4. StopAsync has been called. ");
        await Task.CompletedTask;
    }

    private void OnStarted()
    {
        _logger.LogInformation("2. OnStarted has been called.");
    }

    private void OnStopping()
    {
        _logger.LogInformation("3. OnStopping has been called.");
    }

    private void OnStopped()
    {
        _logger.LogInformation("5. OnStopped has been called.");
    }
}

从代码里可以我们看到我们通过Worker类的构造函数注入了IHostApplicationLifetime示例,然后通过该示例的属性监听了基于Host的程序启动,关闭事件,并作出相应的反应。

保存该文件之后,在目录下运行dotnet run, 等程序启动后,观察输出,然后按ctrl+c中断应用,观察输出:

Microsoft Windows [Version 10.0.22000.556]
(c) Microsoft Corporation. All rights reserved.
正在生成...
info: WorkerDemo1.Worker[0]
      1. StartAsync has been called.
info: WorkerDemo1.Worker[0]
      2. OnStarted has been called.
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: D:\MyProjects\DotNetLearning\WorkerDemo1
info: WorkerDemo1.Worker[0]
      3. OnStopping has been called.
info: Microsoft.Hosting.Lifetime[0]
      Application is shutting down...
info: WorkerDemo1.Worker[0]
      4. StopAsync has been called.
info: WorkerDemo1.Worker[0]
      5. OnStopped has been called.

可以看到通过实现IHostService来作为切入点开发自己的应用,基于.Net HostAsp.net core也是从实现IHostService开始。

IHostLifetime

Host模型通过提供接口IHostLifetime实现,用于实现Host启动或者停止。默认的实现是Microsoft.Extensions.Hosting.Internal.ConsoleLifetime

用户通过实现接口IHostedServiceHost注入自己的代码,Host在启动之后,会按照通过扩展方法AddHostedService<>注册的IHostedService顺序依次启动用户的Service。 Host启动之后一般在如下几种情况下会停止运行:

  • 如果用户在主线程里没有运行HostRun或者WaitForShutdown方法,那么Host会随着Main方法的结束而自然结束。
  • 基于Host的应用崩溃。
  • 被强制使用信号SIGKILL(CTRL+Z)强行停止了。

自从.Net 6+, 默认使用了ConsoleLifetime实现,新增了如下几种方式可以停止Host以及Host启用的应用:

  • SIGINT信号(CTRL+C)
  • SIGQUIT信号(CTRL+break on windows, CTRL+\ on Unix)
  • SIGTERM信号(由其他应用发出信号,例如使用kill发送。)

由于在.Net 6+上完全支持POSIX信号,在应用中不要使用Enviroment.exit来主动退出应用,而应该使用接口IHostApplicationLifetime.StopApplication方法来停止应用。

基于IHostLifetime接口的Host如何实现Host shutdown的流程:

可以仔细的看一下官方网站给出来的图:


普通用户可以不用详细了解该过程,但是如果想深入学习和理解Host模型,可以仔细研究一下这个过程。

IHostEnvironment

注入该服务提供如下的信息:

  • IHostEnvironment.ApplicationName
  • IHostEnvironment.ContentRootFileProvider
  • IHostEnvironment.ContentRootPath
  • IHostEnvironment.EnvironmentName

Host的配置

我们之前讨论过说在静态类Host上调用CreateDefaultBuilder会自动从环境变量和命令行中读入Host的配置,我们还可以在IHostBuilder上多次调用ConfigureHostConfiguration来配置Host, 例如:

    static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureHostConfiguration(configHost =>
            {
                configHost.SetBasePath(Directory.GetCurrentDirectory());
                configHost.AddJsonFile("hostsettings.json", optional: true);
                configHost.AddEnvironmentVariables(prefix: "PREFIX_");
                configHost.AddCommandLine(args);
            });

configHost这里是一个IHostBuilder的变量,在这个实例变量上你可以调用多个方法用于配置Host

应用的配置

如果想在代码里配置应用,您可以在IHostBuilder上调用方法ConfigureAppConfiguration来配置应用。
例如:

.ConfigureAppConfiguration(
    appConfig =>
    {

    }
)

你会发现appConfig是接口IConfigurationBuilder的实例。

使用Host配置Web应用

我们前面讨论的都是基于.Net的通用型Host, 如果我们要实现可以运行Web应用的Host,我们之前也讨论过,有两种方式,第一种是从.Net6开始的基于WebApplicationBuilderWebApplicationi,还有一种是在Generic Host上配置基于web的配置,如下的代码:

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseStartup<Startup>();
    }; 

也即在IHostBuilder上继续调用方法ConfigureWebHostDefaults

ConfigureWebHostDefault方法做了哪些事?您可以参考我们上一章的说明。

基于Web的host提供了哪些内容?

我们之前讨论的都是基于Generic Host, 我们再来讨论一下如果我们是为了一个Web应用设置的Host, 提供了多少其他的内容:

  • ApplicationName
  • ContentRoot
  • EnvironmentName
  • ShutdownTimeout

等等。

关于这些您可以参考一下Host的源码:https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.Extensions.Hosting/src/Host.cs