ASP.NET Core技术研究-探秘Host主机启动过程

ASP.NET Core技术研究-探秘Host主机启动过程,第1张

概述当我们将原有ASP.NET 应用程序升级迁移到ASP.NET Core之后,我们发现代码工程中多了两个类Program类和Startup类。 接下来我们详细探秘一下通用主机Host的启动过程。 一、P

当我们将原有ASP.NET 应用程序升级迁移到ASP.NET Core之后,我们发现代码工程中多了两个类Program类和Startup类。

接下来我们详细探秘一下通用主机Host的启动过程。

一、Program类的Main函数入口

Program类最重要的功能就是启动主机,这里有一个主机的概念,是ASP.NET Core全新引入的。

主机负责应用程序启动和生存期管理。 同时,主机也是封装应用程序资源的对象:

依赖注入 (DI)LoggingConfigurationIHostedService 实现

启动主机时,它在 DI 容器中找到 IHostedService 的每个实现,然后调用 IHostedService.StartAsync。 在 web 应用中,其中一个 IHostedService 的实现是启动 http 服务器实现的 web 服务。这里的http服务器默认是Kestrel。

即:ASP.NET Core主机启动时,会启动一个http服务器,默认是Kestrel。启动后监听并响应某个端口的http请求。

我们继续看Program类的代码: 

  

   从上述代码可以看到,Main函数中首先调用CreateHostBuilder方法,返回一个IHostBuilder。然后调用IHostBuilder.Build()方法完成

二、Host.CreateDefaultBuilder(args): 构造IHostBuilder的默认实现HostBuilder

   在CreateHostBuilder方法内部,首先调用了Host.CreateDefaultBuilder构造了一个HostBuilder,这个我们先看下源码,看看到底Host类内部做了什么 *** 作:

   https://github.com/dotnet/extensions/blob/release/3.1/src/Hosting/Hosting/src/Host.cs

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",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<EventLogLoggerProvIDer>(level => level >= LogLevel.Warning);                }                logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));                logging.AddConsole();                logging.AddDeBUG();                logging.AddEventSourceLogger();                if (iswindows)                {                    // Add the EventLogLoggerProvIDer on windows machines                    logging.AddEventLog();                }            })            .UseDefaultServiceProvIDer((context,options) =>            {                var isDevelopment = context.HostingEnvironment.IsDevelopment();                options.ValIDateScopes = isDevelopment;                options.ValIDateOnBuild = isDevelopment;            });            return builder;        }

  从上述代码中,可以看到CreateDefaultBuilder内部构造了一个HostBuilder,同时设置了:

将内容根目录(contentRootPath)设置为由 GetCurrentDirectory 返回的路径。通过以下源加载主机配置环境变量(DOTNET_前缀)配置命令行参数配置     通过以下对象加载应用配置appsettings.Json appsettings.{Environment}.Json密钥管理器 当应用在 Development 环境中运行时环境变量命令行参数     添加日志记录提供程序控制台调试EventSourceEventLog( windows环境下)当环境为“开发”时,启用范围验证和依赖关系验证。

   以上构造完成了HostBuilder,针对ASP.NET Core应用,代码继续调用了HostBuilder.ConfigureWebHostDefaults方法。

三、IHostBuilder.ConfigureWebHostDefaults:通过GenericWebHostBuilder对HostBuilder增加ASP.NET Core的运行时设置

    构造完成HostBuilder之后,针对ASP.NET Core应用,继续调用了HostBuilder.ConfigureWebHostDefaults方法。这是一个ASP.NET Core的一个扩展方法:

    

      我们继续看ConfigureWebHostDefaults扩展方法内部做了哪些事情:

      源码连接:https://github.com/dotnet/aspnetcore/blob/master/src/DefaultBuilder/src/GenericHostBuilderExtensions.cs      

using System;using Microsoft.AspNetCore.Hosting;using Microsoft.AspNetCore;namespace Microsoft.Extensions.Hosting{    /// <summary>    /// Extension methods for configuring the IWebHostBuilder.    /// </summary>    public static class GenericHostBuilderExtensions    {        /// <summary>        /// Initializes a new instance of the <see cref="IWebHostBuilder"/> class with pre-configured defaults.        /// </summary>        /// <remarks>        ///   The following defaults are applIEd to the <see cref="IWebHostBuilder"/>:        ///     use Kestrel as the web server and configure it using the application's configuration provIDers,///     adds the HostFiltering mIDdleware,///     adds the Forwardedheaders mIDdleware if ASPNETCORE_FORWARDEDheaderS_ENABLED=true,///     and enable IIS integration.        /// </remarks>        /// <param name="builder">The <see cref="IHostBuilder" /> instance to configure</param>        /// <param name="configure">The configure callback</param>        /// <returns>The <see cref="IHostBuilder"/> for chaining.</returns>        public static IHostBuilder ConfigureWebHostDefaults(this IHostBuilder builder,Action<IWebHostBuilder> configure)        {            return builder.ConfigureWebHost(webHostBuilder =>            {                WebHost.ConfigureWebDefaults(webHostBuilder);                configure(webHostBuilder);            });        }    }}© 2020 GitHub,Inc.

  首先,通过类GenericHostWebHostBuilderExtensions,对IHostBuilder扩展一个方法:ConfigureWebHost:builder.ConfigureWebHost

     在这个扩展方法中实现了对IWebHostBuilder的依赖注入:即将GenericWebHostBuilder实例传入方法ConfigureWebHostDefaults内部

     代码连接:https://github.com/dotnet/aspnetcore/blob/release/3.1/src/Hosting/Hosting/src/GenericHostWebHostBuilderExtensions.cs

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<IWebHostBuilder> configure)        {            var webhostBuilder = new GenericWebHostBuilder(builder);            configure(webhostBuilder);            builder.ConfigureServices((context,services) => services.AddHostedService<GenericWebHostService>());            return builder;        }    }}

   通过GenericWebHostBuilder的构造函数GenericWebHostBuilder(buillder),将已有的HostBuilder增加了ASP.NET Core运行时设置。

   可以参考代码:https://github.com/dotnet/aspnetcore/blob/release/3.1/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs

   。。。

   先看到这,让我们回到ConfigureWebHostDefaults:

   将上面两段代码合并一下进行理解:ConfigureWebHostDefaults做了两件事情:

   1. 扩展IHostBuilder增加ConfigureWebHost,引入IWebHostBuilder的实现GenericWebHostBuilder,将已有的HostBuilder增加ASP.NET Core运行时的设置。

   2. ConfigureWebHost代码中的configure(webhostBuilder):对注入的IWebHostBuilder,调用 WebHost.ConfigureWebDefaults(webHostBuilder),启用各类设置,如下代码解读: 

 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<HostFilteringOptions>(options =>                {                    if (options.AllowedHosts == null || options.AllowedHosts.Count == 0)                    {                        // "AllowedHosts": "localhost;127.0.0.1;[::1]"                        var hosts = hostingContext.Configuration["AllowedHosts"]?.Split(new[] { ';' },StringSplitoptions.RemoveEmptyEntrIEs);                        // Fall back to "*" to disable.                        options.AllowedHosts = (hosts?.Length > 0 ? hosts : new[] { "*" });                    }                });                // Change notification                services.AddSingleton<IOptionsChangetokenSource<HostFilteringOptions>>(                            new ConfigurationChangetokenSource<HostFilteringOptions>(hostingContext.Configuration));                services.AddTransIEnt<IStartupFilter,HostFilteringStartupFilter>();                if (string.Equals("true",hostingContext.Configuration["Forwardedheaders_Enabled"],StringComparison.OrdinalignoreCase))                {                    services.Configure<ForwardedheadersOptions>(options =>                    {                        options.Forwardedheaders = Forwardedheaders.XForwardedFor | Forwardedheaders.XForwardedProto;                        // Only loopback proxIEs are allowed by default. Clear that restriction because forwarders are                        // being enabled by explicit configuration.                        options.KNownNetworks.Clear();                        options.KNownProxIEs.Clear();                    });                    services.AddTransIEnt<IStartupFilter,ForwardedheadersstartupFilter>();                }                services.AddRouting();            })            .UseIIS()            .UseIISIntegration();        }

      内部实现了:

前缀为 ASPNETCORE_ 的环境变量加载主机配置。将 Kestrel作为默认的Web服务器添加HostFiltering中间件(主机筛选中间件)如果ASPNETCORE_FORWARDEDheaderS_ENABLED=true,添加转接头中间件ForwardedHeaders 启用IIS集成

  3. 返回ConfigureWebHostDefaults代码中的configure(webHostBuilder):执行Program类中的webBuilder.UseStartup<Startup>();

  第三章节中,以上过程完成了IHostBuilder.ConfigureWebHostDefaults,通过GenericWebHostBuilder对HostBuilder增加ASP.NET Core的运行时设置。

  接下来继续Build和Run的过程。

四、CreateHostBuilder(args).Build().Run();

  CreateHostBuilder返回的IHostBuilder,我们通过代码DeBUG,看一下具体的类型:Microsoft.Extensions.Hosting.HostBuilder,这样进一步验证了前三个章节的代码。

  

  1. Build的过程

  先看下Build的源码:https://github.com/dotnet/extensions/blob/release/3.1/src/Hosting/Hosting/src/HostBuilder.cs

  

      Build的过程主要完成了:

BuildHostConfiguration: 构造配置系统,初始化 IConfiguration _hostConfiguration;CreateHostingEnvironment:构建主机HostingEnvironment环境信息,包含Applicationname、Environmentname、ContentRootPath等CreateHostBuilderContext:创建主机Build上下文HostBuilderContext,上下文中包含:HostingEnvironment和ConfigurationBuildAppConfiguration:构建应用程序配置CreateServiceProvIDer:创建依赖注入服务提供程序,  即依赖注入容器

  2. Run的过程

     我们先通过DeBUG,看一下Host的信息:Microsoft.Extensions.Hosting.Internal.Host

     

      这个Run方法也是一个扩展方法:HostingAbstractionsHostExtensions.Run

      代码链接:https://github.com/dotnet/extensions/blob/release/3.1/src/Hosting/Abstractions/src/HostingAbstractionsHostExtensions.cs

      

     其实内部转调的还是Host.StartAsync方法,在内部启动了DI依赖注入容器中所有注册的服务。

     代码链接:https://github.com/dotnet/extensions/blob/release/3.1/src/Hosting/Hosting/src/Internal/Host.cs

     

 

  整个Host主机的启动过程还是非常复杂的,我们只是简单的在代码层面研究了一遍,感觉只是有了个大致的轮廓,具体怎么执行的,是不是如上面代码的解释,还需要深入继续研究。

  参考链接:

   使用 IIS 在 windows 上托管 ASP.NET Core

   https://docs.microsoft.com/zh-cn/aspnet/core/host-and-deploy/iis/?view=aspnetcore-3.1#iis-options&WT.mc_id=DT-MVP-5003918

   配置 ASP.NET Core 以使用代理服务器和负载均衡器

   https://docs.microsoft.com/zh-cn/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-3.1#forwarded-headers&WT.mc_id=DT-MVP-5003918

   ASP.NET Core 中的 Kestrel Web 服务器实现

   https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/servers/kestrel?view=aspnetcore-3.1#host-filtering&WT.mc_id=DT-MVP-5003918

   

  接下来下一篇文章准备把源码单步调试看看。加深对ASP.NET Core底层技术原理的理解,只有理解了底层技术实现,我们在应用层才能更好、正确的使用。

   

周国庆

2020/4/6

总结

以上是内存溢出为你收集整理的ASP.NET Core技术研究-探秘Host主机启动过程全部内容,希望文章能够帮你解决ASP.NET Core技术研究-探秘Host主机启动过程所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1214918.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-05
下一篇 2022-06-05

发表评论

登录后才能评论

评论列表(0条)

保存