Skip to main content

.Net Host详细介绍

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

我们前面简单的介绍了什么是.Net Host, 我们这一节详细的学习和了解一下Host的内容。

我们先通过.Net Cli创建一个demo,认识一下什么是Host

在你的电脑上打开终端,依次运行如下的命令:

dotnet new webapp -o WebDemo1
cd WebDemo1
code .

基于.Net 6Host模型

使用VS Code打开目录后,查看文件Program.cs的内容如下:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();

这是基于.Net 6的用于创建Web应用的模板,关于.Net 6中提出的WebApplicationBuilderWebApplication概念,您可以参考我之前的文档:https://www.dotnetdeveloper.cn/dotnet-guide/dotnet-6-webapplication-builder-deep-learning, 在这个文档里详细的论述了从WebHostGeneric Host再到.Net 6WebApplicationBuilder

为了探索.Net 6Host模型,您可以尝试builder.Host以及builder.WebHostWebApplicationBuilder的两个属性,HostWebHost统一了两种模型,另外关于新模型,您也可以通过如下的文章仔细学习:

如上是.Net6的host模型,我们接下来看看Generic Host的代码:

基于Generic Host的模型

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }
    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            }; 
    }
}

Generic Host的模型可以看到我们是通过静态类Host来创建一个IHostBuilder的实例,然后通过IHostBuilder的方法Build()来创建一个IHost的实现,并通过IHostRun()来运行一个Host。 而需要注意的是基于.Net 6WebApplicationBuilder的方法Builder()返回的是一个WebApplication的实例, 它代表的是一个基于Web的应用。

至于在Generic Host之前的WebHost模型,完全是为了兼容之前的Asp.net Core框架而存在的,现如今完全可以不用考虑这个模型。

创建Host模型的时候做了哪些事?

虽然.Net 6推出了基于WebApplicationBuilder以及WebApplicationHost模型(实际上这么说并不准确,因为实际上并没有创造新的Host模型,仅仅是为了Web开发的需要,使用了两个包装). Generic Host模型仍然在.Net 6中还是可以使用的,例如在.Net 6中开发非Web的应用,那么就需要直接使用Generic Host的模板和模型。

我们在看一下如何设置Genric Host:

Host.CreateDefaultBuilder(args)
    .ConfigureServices((_, services) =>
    services.AddHostedService<Your Service Class>())
    .Build()
    .RunAsync();

如上创建一个Generic Host, 同时通过扩展方法AddHostedService添加用户自行编写的基于Host的服务,该服务实现IHostedService接口。

如果我们要配置一个基于.Net HostWeb应用该如何设定呢?

Host.CreateDefaultBuilder(args)
    .ConfigureServices((_, services) =>
    services.AddHostedService<Your Service Class>())
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseStartup<Startup>();
    })
    .Build()
    .RunAsync();

添加一个ConfigureWebHostDefaults的函数用于配置基于Web的应用。

CreateDefaultBuilder都干了啥?

在静态类Host上调用CreateDefaultBuilder主要处理如下的事情:

  • 将项目运行的根目录content root设为当前的目录(由命令GetCurrentDirectory返回)
  • 从环境变量以及命令行中读入Host的配置,需要注意的是环境变量名使用DOTNET_为前缀。
  • 从如下列表中读入应用的配置:
    • 配置文件appsettings.json
    • 配置文件appsettings.{Environment}.json
    • 如果应用运行在Development环境下从User secrets里读入配置。
    • 环境变量
    • 命令行参数。
  • 向系统添加如下的日志组件:
    • Console
    • Debug
    • EventSource
    • Eventlog (只在windows下启用)
  • 启用依赖注入容器,并添加Scope验证。

ConfigureWebHostDefaults干了些什么?

我们之前已经清楚的表明了,在调用ConfigureWebhostDeault()方法主要是为了给Host添加基于Web的应用,出了这个之外,还有如下的列表:

  • 从环境变量读入WebHost的配置,环境变量使用默认的前缀ASPNETCORE_
  • 设置Kestrel为Web服务器,从上一步的WebHost配置中读入配置。
  • 添加Host Filter中间件
  • 如果设置了环境变量ASPNETCORE_FORWARDHEADERS_ENABLEtrue时,添加Forward Headers中间件
  • 启用IIS集成。

Host启用的依赖注入服务添加了哪些框架自带的服务

我们前面讨论了在Generic Host启动的时候会启用依赖注入容器,同时作为框架也会自动加入更多的服务:

  • IHostApplicationLifetime
  • IHostLifetime
  • IHostEnvironment/IWebHostEnvironment

关于这些服务我们可以初略的看一下每个服务的作用。

IHostApplicationLifetime

在用户的代码中可以通过注入IHostApplicationLifetime的实例, 可以用于处理用户代码随着host的post-startup和shutdown事件。
这个接口定义了三个属性用于处理应用的startedstoppingstopped事件。

来看一个简单的例子:

需要注意的是接口IHostedService, 这个接口用于定义一个基于Host实现的服务,后面的章节我们会详细的学习这个接口。

public class HostApplicationLifetimeEventsHostedService : IHostedService
{
    private readonly IHostApplicationLifetime _hostApplicationLifetime;

    public HostApplicationLifetimeEventsHostedService(
        IHostApplicationLifetime hostApplicationLifetime)
        => _hostApplicationLifetime = hostApplicationLifetime;

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _hostApplicationLifetime.ApplicationStarted.Register(OnStarted);
        _hostApplicationLifetime.ApplicationStopping.Register(OnStopping);
        _hostApplicationLifetime.ApplicationStopped.Register(OnStopped);

        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
        => Task.CompletedTask;

    private void OnStarted()
    {
        // ...
    }

    private void OnStopping()
    {
        // ...
    }

    private void OnStopped()
    {
        // ...
    }
}

关于其他的接口或者方法我们之后的文章再一一介绍。