.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做了大刀阔斧的调整,并且引入很多新的词汇,比如
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(); } } }
通过以下源加载主机配置(环境变量(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采用的承载模型以IWebHostBuilder和IWebHost为核心,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
使用ConfigureWebHostBuilder与ConfigureHostBuilder属性来创建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在构建过程中加入Worker与UserHostService应用服务,并且通过查看继承关系,两则都是继承了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接口主要提供StartAsync和StopAsync方法。
基于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。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?