.NET Core详解Host(宿主)

一、前言

  在上一篇内容,我们回顾了.NET Core的项目结构,以及Console项目转变成Web项目(MVC/WebAPI/Razro)的实践。在Program的Main方法中首先使用工厂模式创建运行一个Host的,先输入配置参数或者命令参数->构建主机->运行主机。既然在Main方法中第一步就关于Host的创建运行,那么这个肯定是至关重要的组件,所以发挥探索的精神,深入了解.NET Core中Host的概念。查找相关官方文档,个人博客介绍,自己的理解,整理如下内容,对这个知识的一个学习。

二、Host的定义

  Host在计算机中比较容易理解为主机的意思,在.NET Core启动类中使用“主机”感觉不合适。在通过翻译这个词,得出在不同的场景、上下文中,其翻译的意思是不一样的,所以不一定是主机,不能简单理解Host就是主机,要依据使用环境确定具体含义,如下是主要的词义。

  ①计算机和网络领域:通常指的是一个网络上的设备或系统,它可以是一个服务器、工作站、路由器或其他任何连接到网络的设备。在网络通信中,host通常有一个唯一的IP地址,用于在网络上标识和定位它。在Web指的是Web服务器的主机名或IP地址,它是URL的一部分,用于指定Web内容的来源。所以这个定义是在计算机行业比较常见的词义,比如服务器主机,IP地址等。

  ②操作系统:指运行操作系统和应用程序的计算机硬件,代指计算机的硬件设备。

  ③活动或事件:指的是活动或事件的组织者或负责人,他们负责活动的策划、执行和招待。

  ④电视节目:在电视或广播节目中,host指的是节目的主持人,他们负责引导节目的进行和与嘉宾或观众互动,这个是在英语学习比较常见的词义。

  ⑤生物学:在生物学中,特别是在寄生虫学中,host可以指一个生物体,它为另一种生物体(如寄生虫)提供生活环境和营养,这个词义延伸出在计算机领域宿主的词义。

  总结:通过上述Host词义,在计算机、操作系统中使用主机;在实际的生活中是负责人或者主持人;在生物学是提供寄宿的环境,延伸出宿主的意思,这个在应用程序中一样表示为“宿主”。比如一些应用程序,本身没有运行的进程环境,通过寄宿在其他进程中运行使用该进程的计算机资源(IO、CPU、存储)完成程序功能。后续在.NET Core中基于一致性原则,统一定义为“宿主”的概念

三、Web的宿主

  由ASP.NET框架到ASP.NET Core框架解开对平台Windows的依赖关系,包括与IIS的强绑定,从而支持跨平台重大战略意义。在这个过程中ASP.NET Core做了大刀阔斧的调整,并且引入很多新的词汇,比如WebHost、IServiceCollection、IServiceProvider、IApplicationBuilder、ILogger、IConfiguration、IMiddleware 和 RequestDelegate、IServer和IHttpApplication

  Host/WebHost是什么?为什么在应用程序入口创建该对象?主要实现那些功能,目的是什么?按照.NET Core的版本发布,其主要变迁历史内容有那些?基于源代码开源其内部源代码?在实际使用过程中注意点有那些?

  上述一系列问题是对Host/WebHost的全面认识的过程,通过对上述问题的疑惑的解答,基本能够理解微软设计这个目的,所以本文带着这些问题,查找想过文档内容来给出答案,答案并非标准的,是对其的一个理解认识。

复制代码
using System.Runtime.InteropServices;
namespace consoleDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>().UseIIS().UseIISIntegration();
            })
            .Build()
            .Run();
        }
    }
}
复制代码

  1、Host/WebHost(宿主)是什么?

  在源码中关于Host类的注解“提供允许您封装应用程序的资源和生存期功能的类”,主要两个内容①提供应用程序的资源②提供生存周期的功能,是ASP.NET Core中托管应用程序的宿主环境,通俗理解WebHost像母亲,它承载和孕育了ASP.NET Core下几乎所有的对象。

  2、为什么在应用程序入口创建该对象?

  因为构建Host是给应用程序提供宿主环境,所以在应用程序启动的入口处进行创建和初始化宿主环境,给应用程序提供的资源,生命周期,关注业务逻辑开发。

  3、主要实现那些功能,目的是什么?

  Host分四个阶段,准备阶段->构建阶段->启动阶段->运行阶段,通过这四个阶段,Host主要提供了一种统一的方式来启动和运行应用程序,无论是在开发环境中还是在生产环境中。Host负责处理应用程序的生命周期、配置和依赖项管理等任务,使开发人员能够专注于应用程序的业务逻辑。

  详细功能:①将内容根目录(contentRootPath)设置为由 GetCurrentDirectory 返回的路径;②通过以下源加载主机配置(环境变量(DOTNET_前缀)配置、args的命令行参数配置);③通过以下对象加载应用配置(appsettings.json、appsettings.{Environment}.json、密钥管理器 当应用在 Development 环境中运行时、环境变量、命令行参数);④添加日志记录提供程序;控制台管理;调试;EventSource、EventLog( Windows环境下);⑤当环境为“开发”时,启用范围验证和依赖关系验证。上述内容源于源码关于Host构建完成提供的能力的注解信息。

  总结功能: ①生命周期管理:Host负责管理应用程序的生命周期它在应用程序启动时执行一些初始化任务,例如读取配置文件、注册依赖项等。在应用程序关闭时,Host会执行一些清理任务,例如释放资源、保存状态等。通过Host,我们可以确保应用程序在启动和关闭时都能够执行必要的操作。②配置管理:Host提供了一种统一的方式来管理应用程序的配置。它可以从多个配置源(如命令行参数、环境变量、配置文件等)中读取配置信息,并将其应用于应用程序。这使得我们可以根据不同的环境(如开发、测试、生产)使用不同的配置,而无需修改应用程序的代码。③依赖项注入:Host还负责管理应用程序的依赖项。它可以配置和注册依赖项容器,使得应用程序的各个组件可以方便地获取它们所需的依赖项。通过依赖项注入,我们可以实现松耦合的组件设计,提高代码的可测试性和可维护性。

  通过上述的实现功能,Host宿主环境与原来ASP.NET时候要在应用中自定义配置的管理,自定义日志管理,引入依赖注入框架,维护相关的资源,相比较ASP.NET提供强大基础功能,简化了操作,让开发人员专注于应用程序的逻辑编写。

  4、按照.NET Core的版本发布,其主要变迁历史内容有那些?

  当前.NET Core版本包括.NET Core1.0、.NET Core2.1、.NET Core3.0、.NET Core3.1、.NET 5.0/6.0/7.0/8.0/9.0,所以版本不断发布,类库一些进行比较小的调整,然而一些进行比较大调整,ASP.NET Core的应用承载-Host宿主环境在1.0、3.1、6.0版本都进行比较大的变迁调整。

  ①基于IWebHost/IWebHostBuilder的应用承载方式:ASP.NET 1.X/2.X采用的承载模型以IWebHostBuilderIWebHost为核心,IWebHost对象代表承载Web应用的宿主(Web宿主),管道随着IWebHost对象的启动被构建出来。IWebHostBuilder对象作为宿主对象的构建者,我们针对管道构建的设置都应用在它上面。如下代码所示,我们通过使用UseKestrel扩展方法注册了一个Kestrel服务器,调用它的Configure方法利用提供的Action<IApplicationBuilder>委托注册了一个中间件,该中间件将指定的“Hello World”文本作为响应内容,完成服务器与中间件构建的管道,开始监听请求,接收请求,处理请求,返回结果。

复制代码
namespace DemoNetCore2
{
    public class Program
    {
        public static void Main(string[] args)
        {
            new WebHostBuilder()
                .UseKestrel()
                .Configure(app => app.Run( async(context) => {
                    context.Response.ContentType = "text/plain; charset=utf-8";
                    await context.Response.WriteAsync("Hello World!我是基于WebHostBuilder构建的宿主环境!!");
                }))
                .Build()
                .Run();
        }
    }
}
复制代码

 然后基于代码设计原则,使用工厂创建设计模式,并且Kestrel服务器属于默认设置,然后管道涉及到多个中间件(路由、文件、授权、认证、MVC、微服务组件、自定义等等),中间与业务涉及多个对象的服务依赖注入,所以统一定义在Startup类中重构代码如下所示:

复制代码
namespace DemoNetCore2
{
  //入口函数
public class Program { public static void Main(string[] args) { CreateWebHostBuilder(args).Build().Run(); } public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>(); } } namespace DemoNetCore2 {
  // 启动类
public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); }

        app.Run(async (context) =>
        {
          context.Response.ContentType = "text/plain; charset=utf-8";
          await context.Response.WriteAsync("Hello World!我是基于WebHostBuilder构建的宿主环境!!");
        );

            app.UseMvc();
        }
    }
}
复制代码

 上述主要在.NET Core2.X版本前使用这种方式构建宿主环境。

②基于IHost/IHostBuilder的承载方式:在应用类型中,除了Web应用,还包括后台服务,控制台应用的承载需求,为此微软推出了以IHostBuilder/IHost为核心的服务承载系统;使用IHostBuilder接口定义的很多方法(其中很多是扩展方法)为创建的IHost(通用宿主,通用宿主可以托管任何类型的应用,包括 Web 应用)对象及承载的IHostedService服务注册依赖服务;第二,为服务承载和应用提供相应的配置。如果采用基于IWebHostBuilder/IWebHost的承载方式,上述这两方面的设置由IWebHostBuilder对象来完成,后者在此基础上还提供了针对中间件的注册。代码如下:

复制代码
namespace DemoNetCore5
{
    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>();
                });
    }
}

namespace DemoNetCore3
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();
            app.Run(async (context) =>
            {
                context.Response.ContentType = "text/plain; charset=utf-8";
                await context.Response.WriteAsync("Hello World!我是基于IHostBuilder构建的宿主环境!!");
            });
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}
复制代码

 注意:Web应用本身实际上就是一个长时间运行的后台服务,我们完全可以将应用定义成一个IHostedService服务(GenericWebHostService)!!!!

上述主要在.NET 5.X版本前使用这种方式构建宿主环境。

③Minimal API:ASP.NET Core由GenericWebHostService=>IHostBuilder/IHost服务承载,微软基于Web应用和后台服务的承载方式还是应该加以区分(ASP.NET Core应用采用的SDK为“Microsoft.NET.Sdk.Web”,后台服务采用的SDK一般为“Microsoft.NET.Sdk.Worker”),引入基于WebApplicationBuilder/WebApplication的承载方式,通过这两个类来构建宿主环境,因为框架的兼容性要求,上述两种承载方式一样延续下来,WebApplicationBuilder类型的WebHost和Host属性返回了这两个对象,之前定义在IWebHostBuilder和IHostBuilder接口上的绝大部分API(并非所有API)借助它们得以复用,如下代码所示:

复制代码
public sealed class WebApplicationBuilder
{
    public ConfigureWebHostBuilder     WebHost { get; }
    public ConfigureHostBuilder     Host { get; }

    public IServiceCollection             Services { get; }
    public ConfigurationManager     Configuration { get; }
    public ILoggingBuilder         Logging { get; }

    public IWebHostEnvironment             Environment { get; }

    public WebApplication Build();
}

public sealed class ConfigureWebHostBuilder : IWebHostBuilder, ISupportsStartup
public sealed class ConfigureHostBuilder : IHostBuilder, ISupportsConfigureWebHost
复制代码

使用ConfigureWebHostBuilderConfigureHostBuilder属性来创建Web应用宿主,在这个类中同时暴露服务注册属性IServiceCollection、配置管理ConfigurationManager、日志管理ILoggingBuilder、所属环境IWebHostEnvironment,基于这些属性来轻易完成上述功能。

复制代码
namespace DemoNetCore8
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            // Add services to the container.
            builder.Services.AddAuthorization();


            var app = builder.Build();

            // Configure the HTTP request pipeline.

            app.UseAuthorization();

            app.Run(async (context) =>
            {
                context.Response.ContentType = "text/plain; charset=utf-8";
                await context.Response.WriteAsync("Hello World!我是基于IHostBuilder构建的宿主环境!!");
            });

            var summaries = new[]
            {
                "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
            };

            app.MapGet("/weatherforecast", (HttpContext httpContext) =>
            {
                var forecast = Enumerable.Range(1, 5).Select(index =>
                    new WeatherForecast
                    {
                        Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
                        TemperatureC = Random.Shared.Next(-20, 55),
                        Summary = summaries[Random.Shared.Next(summaries.Length)]
                    })
                    .ToArray();
                return forecast;
            });

            app.Run();
        }
    }
}
复制代码

 至此完成ASP.NET Core关于宿主承载方式的演变过程。

5、基于开源其内部源代码?

.NET Core是开源的项目,所以通过查看源码可以了解Host的构建,及其使用,源码地址是https://github.com/dotnet/runtime。

注意:1、Host(宿主)与应用(IHostedService)是一对多的关系,多个应用可以共享主机的信息,如:主机的IOC容器、主机的配置。应用配置。应用当然也可以自己去创建自己的IOC根容器和配置对象;2、宿主配置与应用配置的关系,这两个配置对象都存在于Host中,宿主配置是只跟主机相关的配置,应用配置是宿主中多个应用共享的配置,如果宿主中只有一个应用,那么完全可以拿它做最终的应用配置。另外应用配置包含宿主配置。3、通过宿主承载方式演变发现,.net core是通用框架使用优秀的设计模式降低程序的耦合性、提高程序的扩展性,兼容性,并且为了简洁性、便于创建提供静态类的方法进行创建,对于提供资源和功能尽量使用默认配置,减少自定义。

6、一个宿主对应多个应用的实践

创建一个ASP.NET Core应用,并且在应用中构建一个后台服务与自定义服务,验证一个宿主可以对应多个应用的关系,代码如下:

复制代码
namespace DemoNetCore8
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // 获取宿主创建对象
            var builder = WebApplication.CreateBuilder(args);
                
            // 在宿主加入后台任务服务(应用程序)
            builder.Services.AddHostedService<Worker>();

            // 在宿主加入自定义的应用程序
            builder.Services.AddHostedService<UserHostService>();

            // Add services to the container.
            builder.Services.AddAuthorization();

            var app = builder.Build();
            // Configure the HTTP request pipeline.

            app.UseAuthorization();

            app.Run(async (context) =>
            {
                context.Response.ContentType = "text/plain; charset=utf-8";
                await context.Response.WriteAsync("Hello World!我是基于WebApplicationBuilder构建的宿主环境!!");
            });

            var summaries = new[]
            {
                "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
            };

            app.MapGet("/weatherforecast", (HttpContext httpContext) =>
            {
                var forecast = Enumerable.Range(1, 5).Select(index =>
                    new WeatherForecast
                    {
                        Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
                        TemperatureC = Random.Shared.Next(-20, 55),
                        Summary = summaries[Random.Shared.Next(summaries.Length)]
                    })
                    .ToArray();
                return forecast;
            });

            app.Run();
        }
    }
}
复制代码

这个Host在构建过程中加入WorkerUserHostService应用服务,并且通过查看继承关系,两则都是继承了IHostedService,如下所示:

复制代码
namespace DemoNetCore8
{
    /// <summary>
    /// 
    /// </summary>
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;

        public Worker(ILogger<Worker> logger)
        {
            _logger = logger;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                if (_logger.IsEnabled(LogLevel.Information))
                {
                    _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                }
                await Task.Delay(10000, stoppingToken);
            }
        }
    }
}
复制代码

复制代码
namespace DemoNetCore8
{
    public class UserHostService : IHostedService, IDisposable
    {
        private readonly ILogger<Worker> _logger;
        public UserHostService(ILogger<Worker> logger)
        {
            _logger = logger;
        }
        
        public Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("UserHostService StartAsync");
            return Task.CompletedTask;
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("UserHostService StopAsync");
            return Task.CompletedTask;
        }

        public void Dispose()
        {
            throw new NotImplementedException();
        }
    }
}
复制代码

 其中对应IHostedService接口主要提供StartAsyncStopAsync方法。

基于Web应用一样遵循这个IHostedService,通过查看WebApplication类,及其继承的IHost接口如下:

 然后运行Web应用程序,查看是否启动了Work与自定义服务(UserHostService),如下图所示:

四、总结

  通过学习Host的词义,在.NET Core中宿主及其提供的功能介绍,.NET Core的版本迁移对Host的调整,基本完成对Host的认知,实际开发中也熟悉原理内容。

  参考:https://www.sohu.com/a/365418758_468635,https://www.cnblogs.com/artech/p/inside-asp-net-core-6-23.html,https://blog.csdn.net/weixin_57062986/article/details/133088869。

posted @   tuqunfu  阅读(702)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示