zoukankan      html  css  js  c++  java
  • .NET Core 3.0之深入源码理解Host(一)

    写在前面

    ASP .NET Core中的通用主机构建器是在v2.1中引入的,应用在启动时构建主机,主机作为一个对象用于封装应用资源以及应用程序启动和生存期管理。其主要功能包括配置初始化(包括加载配置以及配置转换为通用的键值对格式),创建托管环境和Host通用上下文、依赖注入等。

    在.NET Core 3.0中采用了IHostBuilder用于创建Host,同时也不再建议使用Web主机,而建议使用泛型主机,主要原因是原有的通用主机仅适用于非HTTP负载,为了提供更加广泛的主机方案,需要将HTTP管道与Web主机的接口分离出来。但Web主机仍会向后兼容。

    host-update

    .NET Core 3.0中创建通用主机

    以下代码是V3.0中提供的模板代码,可以看到在创建主机的过程中,已经摒弃了WebHostBuilder的创建方式

       1:  public class Program
       2:  {
       3:      public static void Main(string[] args)
       4:      {
       5:          CreateHostBuilder(args).Build().Run();
       6:      }
       7:   
       8:      public static IHostBuilder CreateHostBuilder(string[] args) =>
       9:          Host.CreateDefaultBuilder(args)
      10:              .ConfigureWebHostDefaults(webBuilder =>
      11:              {
      12:                  webBuilder.UseStartup<Startup>();
      13:              });
      14:  }


    而在.NET Core 2.X中

       1:  public class Program
       2:  {
       3:     public static void Main(string[] args)
       4:     {
       5:        CreateWebHostBuilder(args).Build().Run();
       6:     } 
       7:   
       8:     public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
       9:        WebHost.CreateDefaultBuilder(args)
      10:           .UseStartup<Startup>();
      11:  }

    V3.0模板中提供的CreateHostBuilder()方法看起来非常类似于V2.X中的CreateWebHostBuilder()。

    其主要区别在于对WebHost.CreateDefaultBuilder()由Host.CreateDefaultBuilder()替换。使用CreateDefaultBuilder()辅助方法可以非常轻松地从v2.x切换到v3.0。

    另一个区别是关于ConfigureWebHostDefaults()的调用。由于新的主机构建器是通用主机构建器,因此我们必须让它知道我们打算为Web主机配置默认设置。这些默认配置我们可以在ConfigureWebHostDefaults()方法中实现

    CreateDefaultBuilder

    该方法Microsoft.Extensions.Hosting.Host中,它是一个静态类,里面有两个方法,一个有参的CreateDefaultBuilder(string[] args),一个是无参的。

    无参方法源码如下,

       1:  public static IHostBuilder CreateDefaultBuilder() =>
       2:              CreateDefaultBuilder(args: null);

    可以看到该方法实际上是设置了默认值。

    IHostBuilder CreateDefaultBuilder(string[] args)方法主要有以下功能:

    创建HostBuilder对象

       1:  var builder = new HostBuilder();

    指定Host要使用的内容根目录

       1:  builder.UseContentRoot(Directory.GetCurrentDirectory());

    配置初始化(环境变量、appsettings.json、User Secrets)

       1:  builder.ConfigureHostConfiguration(config =>
       2:  {
       3:      config.AddEnvironmentVariables(prefix: "DOTNET_");
       4:      if (args != null)
       5:      {
       6:          config.AddCommandLine(args);
       7:      }
       8:  });
       9:   
      10:  builder.ConfigureAppConfiguration((hostingContext, config) =>
      11:  {
      12:      var env = hostingContext.HostingEnvironment;
      13:   
      14:      config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
      15:            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
      16:   
      17:      if (env.IsDevelopment() && !string.IsNullOrEmpty(env.ApplicationName))
      18:      {
      19:          var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
      20:          if (appAssembly != null)
      21:          {
      22:              config.AddUserSecrets(appAssembly, optional: true);
      23:          }
      24:      }
      25:   
      26:      config.AddEnvironmentVariables();
      27:   
      28:      if (args != null)
      29:      {
      30:          config.AddCommandLine(args);
      31:      }
      32:  })

    日志

       1:  .ConfigureLogging((hostingContext, logging) =>
       2:  {
       3:      logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
       4:      logging.AddConsole();
       5:      logging.AddDebug();
       6:      logging.AddEventSourceLogger();
       7:  })

    在开发环境模式下启用作用域验证

       1:  .UseDefaultServiceProvider((context, options) =>
       2:  {
       3:      var isDevelopment = context.HostingEnvironment.IsDevelopment();
       4:      options.ValidateScopes = isDevelopment;
       5:      options.ValidateOnBuild = isDevelopment;
       6:  });

    Build

    Build()方法是Microsoft.Extensions.Hosting中,并且该方法只会执行一次,当然这种一次只是在同一个实例里面

       1:  public IHost Build()
       2:  {
       3:      if (_hostBuilt)
       4:      {
       5:          throw new InvalidOperationException("Build can only be called once.");
       6:      }
       7:      _hostBuilt = true;
       8:   
       9:      BuildHostConfiguration();
      10:      CreateHostingEnvironment();
      11:      CreateHostBuilderContext();
      12:      BuildAppConfiguration();
      13:      CreateServiceProvider();
      14:   
      15:      return _appServices.GetRequiredService<IHost>();
      16:  }

    该方法主要是包括以下功能:

    创建HostingEnvironment

    创建HostBuilderContext

    配置初始化及格式标准化

    DI(创建IHostEnvironment、IHostApplicationLifetime、IHostLifetime、IHost)

    Run

    Run方法运行应用程序并阻止调用线程,直到主机关闭

       1:  public static void Run(this IHost host)
       2:  {
       3:      host.RunAsync().GetAwaiter().GetResult();
       4:  }

    以下是RunAsync的源码,此处可以通过设置CancellationToken的值,使应用程序自动关闭

       1:  public static async Task RunAsync(this IHost host, CancellationToken token = default)
       2:  {
       3:      try
       4:      {
       5:          await host.StartAsync(token);
       6:   
       7:          await host.WaitForShutdownAsync(token);
       8:      }
       9:      finally
      10:      {
      11:  #if DISPOSE_ASYNC
      12:          if (host is IAsyncDisposable asyncDisposable)
      13:          {
      14:              await asyncDisposable.DisposeAsync();
      15:          }
      16:          else
      17:  #endif
      18:          {
      19:              host.Dispose();
      20:          }
      21:   
      22:      }
      23:  }
  • 相关阅读:
    Java-IO之DeflaterOutputStream和InflaterOutputStream
    myeclipse 破解步骤
    通过Nginx,Tomcat访问日志(access log)记录请求耗时
    关于封装了gevent的request grequest库的使用与讨论
    关于python性能相关测试cProfile库
    python threading模块使用 以及python多线程操作的实践(使用Queue队列模块)
    python格式化字符串Type Error: Format Requires Mapping 的问题
    关于flask自带web应用服务器Werkzeug 使用requests请求时出现的错误。
    关于python 自带csv库的使用心得 附带操作实例以及excel下乱码的解决
    pycharm5.0 快捷键大全osx
  • 原文地址:https://www.cnblogs.com/edison0621/p/11025310.html
Copyright © 2011-2022 走看看