.NET Core技术研究-主机Host
2021-03-18 19:24
标签:sync validate cut info build -o cas task 说明
前一段时间,和大家分享了 ASP.NET Core技术研究-探秘Host主机启动过程 但是没有深入说明主机的设计。今天整理了一下主机的一些知识,结合先前的博文,完整地介绍一下.NET Core的主机的设计和构建启动过程。 一、什么是主机 主机是一个封装了应用资源的对象,即:主机封装了一堆应用资源,封装了哪些应用资源呢? 二、Web主机和通用主机 先说Web主机:即ASP.NET Core Web主机,概括的讲就是托管Web程序的Host。在低于 3.0 的 ASP.NET Core 版本中,Web 主机用于 HTTP 工作负载。 我们新建一个ASP.NET Core2.2的Web应用程序,在Program类的Main函数中我们可以看到整个WebHost的构造、启动过程: .NET Core提供Web主机的同时,还提供了一个通用主机的概念。 通用主机Host和Web主机提供了类似的架构和功能,包含依赖注入框架DI、日志、配置、各类应用(托管服务)。通用主机的出现,给了我们更多开发的选择,比如说后台处理任务场景。 在.NET Core3.1版本后,微软不再建议将 Web 主机用于 Web 应用,直接使用Host通用主机来替换WebHost, 一句话:通用主机可以托管任何类型的应用,包括 Web 应用。 通用主机将替换 Web 主机。为了向下兼容,WebHost依然可以使用。 我们新建一个ASP.NET Core3.1的Web应用程序,在Program类的Main函数中我们可以看到整个WebHost的构造、启动过程: 接下来,我们将以ASP.NET Core 3.1这个版本,介绍一下主机的构建过程和启动过程 三、主机是如何构建的 从上述代码可以看到,Main函数中首先调用CreateHostBuilder方法,返回一个IHostBuilder。然后调用IHostBuilder.Build()方法完成 1. 通过Host.CreateDefaultBuilder(args): 构造IHostBuilder的默认实现HostBuilder 在CreateHostBuilder方法内部,首先调用了Host.CreateDefaultBuilder构造了一个HostBuilder,这个我们先看下源码,看看到底Host类内部做了什么操作: 从上述.NET Core源代码中,可以看到CreateDefaultBuilder内部构造了一个HostBuilder,同时设置了: 以上构造完成了HostBuilder,针对ASP.NET Core应用,代码继续调用了HostBuilder.ConfigureWebHostDefaults方法。 2. IHostBuilder.ConfigureWebHostDefaults:通过GenericWebHostBuilder对HostBuilder增加ASP.NET Core的运行时设置 构造完成HostBuilder之后,针对ASP.NET Core应用,继续调用了HostBuilder.ConfigureWebHostDefaults方法。这是一个ASP.NET Core的一个扩展方法: 我们继续看ConfigureWebHostDefaults扩展方法内部做了哪些事情: ASP.NET Core源码连接:https://github.com/dotnet/aspnetcore/blob/master/src/DefaultBuilder/src/GenericHostBuilderExtensions.cs 首先,通过类GenericHostWebHostBuilderExtensions,对IHostBuilder扩展一个方法:ConfigureWebHost:builder.ConfigureWebHost 在这个扩展方法中实现了对IWebHostBuilder的依赖注入:即将GenericWebHostBuilder实例传入方法ConfigureWebHostDefaults内部 代码连接:https://github.com/dotnet/aspnetcore/blob/release/3.1/src/Hosting/Hosting/src/GenericHostWebHostBuilderExtensions.cs 通过GenericWebHostBuilder的构造函数GenericWebHostBuilder(buillder),将已有的HostBuilder增加了ASP.NET Core运行时设置。 可以参考ASP.NET Core源代码:https://github.com/dotnet/aspnetcore/blob/release/3.1/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs 先看到这,让我们回到ConfigureWebHostDefaults: 将上面两段代码合并一下进行理解:ConfigureWebHostDefaults做了两件事情: ①. 扩展IHostBuilder增加ConfigureWebHost,引入IWebHostBuilder的实现GenericWebHostBuilder,将已有的HostBuilder增加ASP.NET Core运行时的设置。 ② ConfigureWebHost代码中的configure(webhostBuilder):对注入的IWebHostBuilder,调用 WebHost.ConfigureWebDefaults(webHostBuilder),启用各类设置,如下代码解读: 其内部实现了: 3. 返回ConfigureWebHostDefaults代码中的configure(webHostBuilder):执行Program类中的webBuilder.UseStartup 以上过程完成了IHostBuilder.ConfigureWebHostDefaults,通过GenericWebHostBuilder对HostBuilder增加ASP.NET Core的运行时设置。 接下来就是主机的Build过程了: 4. CreateHostBuilder(args).Build() CreateHostBuilder返回的IHostBuilder,我们通过代码Debug,看一下具体的类型:Microsoft.Extensions.Hosting.HostBuilder。 具体的Build过程是怎么样的?先看下Build的源码:https://github.com/dotnet/extensions/blob/release/3.1/src/Hosting/Hosting/src/HostBuilder.cs 主机Build的过程主要完成了: 四、主机是如何启动运行的 我们先通过Debug,看一下Host的信息:Microsoft.Extensions.Hosting.Internal.Host 这个Run方法也是一个扩展方法:HostingAbstractionsHostExtensions.Run ASP.NET Core源代码链接:https://github.com/dotnet/extensions/blob/release/3.1/src/Hosting/Abstractions/src/HostingAbstractionsHostExtensions.cs 其实内部转调的还是Host.StartAsync方法,在内部启动了DI依赖注入容器中所有注册的服务。 .NET Core代码链接:https://github.com/dotnet/extensions/blob/release/3.1/src/Hosting/Hosting/src/Internal/Host.cs 五、主机中注册一个托管服务 以一个后台自更新(每隔5s 检查一次程序变更、进行输出)场景作为Demo,我们看一下如何在主机中注册一个托管服务。 自更新服务UpdateService,需要继承接口IHostService。 同时,我们需要在ConfigureServices方法中,将UpdateService添加到IoC服务容器中 程序启动后,可以看到以下输出: 以上是对.NET Core主机的概念、设计初衷、构建过程、启动运行过程、服务注册的整理和分享。 周国庆 2020/4/18 .NET Core技术研究-主机Host 标签:sync validate cut info build -o cas task 说明 原文地址:https://www.cnblogs.com/lonelyxmas/p/12766653.html
public static IHostBuilder CreateDefaultBuilder(string[] args)
{
var builder = new HostBuilder();
builder.UseContentRoot(Directory.GetCurrentDirectory());
builder.ConfigureHostConfiguration(config =>
{
config.AddEnvironmentVariables(prefix: "DOTNET_");
if (args != null)
{
config.AddCommandLine(args);
}
});
builder.ConfigureAppConfiguration((hostingContext, config) =>
{
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
if (env.IsDevelopment() && !string.IsNullOrEmpty(env.ApplicationName))
{
var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
if (appAssembly != null)
{
config.AddUserSecrets(appAssembly, optional: true);
}
}
config.AddEnvironmentVariables();
if (args != null)
{
config.AddCommandLine(args);
}
})
.ConfigureLogging((hostingContext, logging) =>
{
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
// IMPORTANT: This needs to be added *before* configuration is loaded, this lets
// the defaults be overridden by the configuration.
if (isWindows)
{
// Default the EventLogLoggerProvider to warning or above
logging.AddFilter
using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore;
namespace Microsoft.Extensions.Hosting
{
///
using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.Extensions.Hosting
{
public static class GenericHostWebHostBuilderExtensions
{
public static IHostBuilder ConfigureWebHost(this IHostBuilder builder, Action
internal static void ConfigureWebDefaults(IWebHostBuilder builder)
{
builder.ConfigureAppConfiguration((ctx, cb) =>
{
if (ctx.HostingEnvironment.IsDevelopment())
{
StaticWebAssetsLoader.UseStaticWebAssets(ctx.HostingEnvironment, ctx.Configuration);
}
});
builder.UseKestrel((builderContext, options) =>
{
options.Configure(builderContext.Configuration.GetSection("Kestrel"));
})
.ConfigureServices((hostingContext, services) =>
{
// Fallback
services.PostConfigure
public class UpdateService : IHostedService
{
Task updateTask = null;
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
public Task StartAsync(CancellationToken cancellationToken)
{
updateTask = Task.Run(() =>
{
while (cancellationTokenSource.Token.IsCancellationRequested==false)
{
//Check new data...
Console.WriteLine(DateTime.Now + ": Executed");
Task.Delay(5000).Wait();
}
});
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
cancellationTokenSource.Cancel();
return Task.CompletedTask;
}
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton