[ASP.NET Core 3框架揭秘]服务承载系统[6]: 承载服务启动流程[下篇]
2021-04-07 23:29
标签:cell ima cep net htm ring 验证 如何 settings 实际上HostBuilder对象并没有在实现的Build方法中调用构造函数来创建Host对象,该对象利用作为依赖注入容器的IServiceProvider对象创建的。为了可以采用依赖注入框架来提供构建的Host对象,HostBuilder必须完成前期的服务注册工作。总地来说,HostBuilder针对Host对象的构建大体可以划分为如下5个步骤: 由于很多依赖服务都是针对当前承载上下文进行注册的,所以Build方法首要的任务就是创建出作为承载上下文的HostBuilderContext对象。一个HostBuilderContext对象由承载针对宿主配置的IConfiguration对象和描述当前承载环境的IHostEnvironment对象组成,但是后者提供的环境名称、应用名称和内容文件根目录路径可以通过前者来指定,具体配置项名称定义在如下这个静态类型HostDefaults中。 接下来我们通过一个简单的实例来演示如何利用配置的方式来指定上述三个与承载环境相关的属性。我们定义了如下一个名为FakeHostedService的承载服务,并在构造函数中注入IHostEnvironment对象。在实现的StartAsync方法中,我们将与承载环境相关的环境名称、应用名称和内容文件根目录路径输出到控制台上。 FakeHostedService采用如下的形式承载于当前应用程序中。如下面的代码片段所示,在创建作为宿主构建者的HostBuilder之后,我们调用了它的ConfigureHostConfiguration方法注册了基于命令行参数作为配置源,意味着我们可以利用命令行参数的形式来初始化相应的配置。 我们采用命令行的方式启动这个演示程序,并利用传入的命令行参数指定环境名称、应用名称和内容文件根目录路径(确保路径确实存在)。从如图10-11所示的输出结果表明应用程序当前的承载环境确实与基于宿主的配置一致。(S1009) HostBuilder针对HostBuilderContext对象的创建体现在如下所示的CreateBuilderContext方法中。如下面的代码片段所示,该方法创建了一个ConfigurationBuilder对象并调用AddInMemoryCollection扩展方法注册了针对内存变量的配置源。HostBuilder接下来会将这个ConfigurationBuilder对象作为参数调用ConfigureHostConfiguration方法注册的所有Action 在创建出HostBuilderContext对象的配置之后,HostBuilder会根据配置创建出代表承载环境的HostingEnvironment对象。如果不存在针对应用名称的配置项,应用名称将会设置为当前入口程序集的名称。如果内容文件根目录路径对应的配置项不存在,当前应用的基础路径(AppContext.BaseDirectory)将会作为内容文件根目录路径。如果指定的是一个相对路径,HostBuilder会根据基础路径生成一个绝对路径作为内容文件根目录路径。CreateBuilderContext方法最终会根据创建的这个HostingEnvironment对象和之前创建的IConfiguration创建出代表承载上下文的BuilderContext对象。 到目前为止,作为承载上下文的BuilderContext对象携带的是通过调用ConfigureHostConfiguration方法初始化的配置,接下来通过调用ConfigureAppConfiguration方法初始化的配置将会与之合并,具体的逻辑体现在如下所示的BuildAppConfiguration方法上。 如下面的代码片段所示,BuildAppConfigration方法会创建一个ConfigurationBuilder对象,并调用其AddConfiguration方法将现有的配置合并进来。于此同时,内容文件根目录的路径将会作为配置文件所在目录的基础路径。HostBuilder最后会将之前创建的HostBuilderContext 对象和这个ConfigurationBuilder对象作为参数调用在ConfigureAppConfiguration方法注册的每一个Action 当作为承载上下文的HostBuilderContext对象创建出来并完成被初始化后,HostBuilder需要完成服务注册工作,这一实现体现在如下所示的ConfigureAllServices方法中。如下面的代码片段所示,ConfigureAllServices方法在将代表承载上下文的HostBuilderContext对象和创建的ServiceCollection对象作为参数调用ConfigureServices方法中注册的每一个Action 对于ConfigureAllServices方法默认注册的这些服务,如果我们自定义的承载服务需要使用到它们,可以直接采用构造器注入的方式对它们进行消费。由于其中包含了针对Host的服务注册,所有由所有服务注册构建的IServiceProvider对象可以提供最终构建的Host对象。 目前我们已经拥有了所有的服务注册,接下来的任务就是利用它创建出作为依赖注入容器的IServiceProvider对象并利用它提供构建的Host对象。针对IServiceProvider的创建体现在如下所示的CreateServiceProvider方法中。如下面的代码片段所示,CreateServiceProvider方法会先得到_serviceProviderFactory字段表示的IServiceFactoryAdapter对象,该对象是根据UseServiceProviderFactory 接下来我们将这个TContainerBuilder对象作为参数调用_configureContainerActions字段中的每个IConfigureContainerAdapter对象的ConfigureContainer方法,这里的每个IConfigureContainerAdapter对象都是根据ConfigureContainer 当目前为止,我们演示的实例都是直接创建HostBuilder对象来创建作为服务宿主的IHost对象。如果直接利用模板来创建一个ASP.NET Core应用,我们会发现生成的程序会采用如下的服务承载方式。具体来说,用来创建宿主的IHostBuilder对象是间接地调用静态类型Host的CreateDefaultBuilder方法创建出来的,那么这个方法究竟会提供创建一个IHostBuilder对象呢。 如下所示的是定义在静态类型Host中的两个CreateDefaultBuilder方法重载的定义的,我们会发现它们最终提供的仍旧是一个HostBuilder对象,但是在返回该对象之前,该方法会帮助我们做一些初始化工作。如下面的代码片段所示,当CreateDefaultBuilder方法创建出HostBuilder对象之后,它会自动将当前目录所在的路径作为内容文件根目录的路径。接下来,该方法还会调用HostBuilder对象的ConfigureHostConfiguration方法注册针对环境变量的配置源,对应环境变量名称前缀被设置为“DOTNET_”。如果提供了代表命令行参数的字符串数组,CreateDefaultBuilder方法还会注册针对命令行参数的配置源。 在设置了针对宿主的配置之后,CreateDefaultBuilder调用了HostBuilder的ConfigureAppConfiguration方法设置针对应用的配置,具体的配置源包括针对Json文件“appsettings.json”和“appsettings.{environment}.json”、环境变量(没有前缀限制)和命令行参数(如果提供了表示命令航参数的字符串数组)。 在完成了针对配置的设置之后,CreateDefaultBuilder方法还会调用HostBuilder的ConfigureLogging扩展方法作一些与日志相关的设置,其中包括应用日志相关的配置(对应配置节名称为“Logging”)和注册针对控制台、调试器和EventSource的日志输出渠道。在此之后,它还会调用UseDefaultServiceProvider方法让针对服务范围的验证在开发环境下被自动开启。 服务承载系统[1]: 承载长时间运行的服务[上篇] [ASP.NET Core 3框架揭秘]服务承载系统[6]: 承载服务启动流程[下篇] 标签:cell ima cep net htm ring 验证 如何 settings 原文地址:https://www.cnblogs.com/artech/p/inside-asp-net-core-09-06.html
步骤一、创建HostBuilderContext
public static class HostDefaults
{
public static readonly string EnvironmentKey = "environment";
public static readonly string ContentRootKey = "contentRoot";
public static readonly string ApplicationKey = "applicationName";
}
public class FakeHostedService : IHostedService
{
private readonly IHostEnvironment _environment;
public FakeHostedService(IHostEnvironment environment) => _environment = environment;
public Task StartAsync(CancellationToken cancellationToken)
{
Console.WriteLine("{0,-15}:{1}", nameof(_environment.EnvironmentName), _environment.EnvironmentName);
Console.WriteLine("{0,-15}:{1}", nameof(_environment.ApplicationName), _environment.ApplicationName);
Console.WriteLine("{0,-15}:{1}", nameof(_environment.ContentRootPath), _environment.ContentRootPath);
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
class Program
{
static void Main(string[] args)
{
new HostBuilder()
.ConfigureHostConfiguration(builder => builder.AddCommandLine(args))
.ConfigureServices(svcs => svcs.AddHostedService
public class HostBuilder : IHostBuilder
{
private List
步骤二、构建针对应用的配置
public class HostBuilder: IHostBuilder
{
private List
步骤三、依赖服务注册
public class HostBuilder: IHostBuilder
{
private List
步骤四、创建IServiceProvider对象
public class HostBuilder : IHostBuilder
{
private List
静态类型Host
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
public static class Host
{
public static IHostBuilder CreateDefaultBuilder() => CreateDefaultBuilder(args: null);
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) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddConsole();
logging.AddDebug();
logging.AddEventSourceLogger();
})
.UseDefaultServiceProvider((context, options) =>
{
options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
});
return builder;
}
}
服务承载系统[2]: 承载长时间运行的服务[下篇]
服务承载系统[3]: 总体设计[上篇]
服务承载系统[4]: 总体设计[下篇]
服务承载系统[5]: 承载服务启动流程[上篇]
服务承载系统[6]: 承载服务启动流程[下篇]
文章标题:[ASP.NET Core 3框架揭秘]服务承载系统[6]: 承载服务启动流程[下篇]
文章链接:http://soscw.com/essay/72616.html