.Net 6中WebApplicationBuilder先容 和用法 您所在的位置:网站首页 adskn .Net 6中WebApplicationBuilder先容 和用法

.Net 6中WebApplicationBuilder先容 和用法

2023-08-26 10:22| 来源: 网络整理| 查看: 265

马上注册加入论坛,获取更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x 目次 先容 正文ConfigureHostBuilderBootstrapHostBuilderWebApplicationBuilder构造函数WebApplicationBuilder.Build()

先容

.Net 6为我们带来的一种全新的引导程序启动的方式。与之前的拆分成Program.cs和Startup差别 ,整个引导启动代码都在Program.cs中。

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);复制代码在上篇文章中,我扼要 形貌 了如何使用 WebApplication和WebApplicationBuilder设置 ASP.NET Core 应用程序。在这篇文章中,我们来深入看下代码.

正文

我们示例程序的第一步是实行

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);复制代码创建一个WebApplicationBuilder复制代码实例。

从命令行中分配Args参数,并将选项对象传递给WebApplicationBuilder构造函数的WebApplicationOptions

/// /// Initializes a new instance of the class with preconfigured defaults. /// /// Command line arguments /// The . public static WebApplicationBuilder CreateBuilder(string[] args) => new(new() { Args = args });复制代码

WebApplicationOptions和WebApplicationBuilder背面 在讲

internal WebApplicationBuilder(WebApplicationOptions options, Action? configureDefaults = null) /// /// Options for configuing the behavior for . /// public class WebApplicationOptions { /// /// The command line arguments. /// public string[]? Args { get; init; } /// /// The environment name. /// public string? EnvironmentName { get; init; } /// /// The application name. /// public string? ApplicationName { get; init; } /// /// The content root path. /// public string? ContentRootPath { get; init; } /// /// The web root path. /// public string? WebRootPath { get; init; } }复制代码

WebApplicationBuilder由一堆只读属性和一个方法组成Build(),该方法创建了一个WebApplication. 我删除了部门 讲解用不到的代码。

假如 您熟悉 ASP.NET Core,那么此中 许多 属性都使用 从前 版本中的常见范例

IWebHostEnvironment: 用于检索环境 IServiceCollection: 用于向 DI 容器注册服务。 ConfigurationManager: 用于添加新设置 和检索设置 值。我在之前的文章有讲 ILoggingBuilder: 用于注册额外的日志提供程序

在WebHost和Host性质很有趣,由于 它们袒露出新的范例 ,ConfigureWebHostBuilder和ConfigureHostBuilder。这些范例 分别实现IWebHostBuilder和IHostBuilder。

公开IWebHostBuilder和IHostBuilder接口对于答应 从.NET 6 之前的应用程序迁移到新的最小托管,我们如何将的lambda风格设置 IHostBuilder与命令式风格的WebApplicationBuilder和谐 起来,这就是ConfigureHostBuilder和ConfigureWebHostBuilder与一些内部沿来IHostBuilder实现。

public sealed class WebApplicationBuilder { private const string EndpointRouteBuilderKey = "__EndpointRouteBuilder"; private readonly HostBuilder _hostBuilder = new(); private readonly BootstrapHostBuilder _bootstrapHostBuilder; private readonly WebApplicationServiceCollection _services = new(); private readonly List _hostConfigurationValues; private WebApplication? _builtApplication; /// /// Provides information about the web hosting environment an application is running. /// public IWebHostEnvironment Environment { get; } /// /// A collection of services for the application to compose. This is useful for adding user provided or framework provided services. /// public IServiceCollection Services { get; } /// /// A collection of configuration providers for the application to compose. This is useful for adding new configuration sources and providers. /// public ConfigurationManager Configuration { get; } /// /// A collection of logging providers for the application to compose. This is useful for adding new logging providers. /// public ILoggingBuilder Logging { get; } /// /// An for configuring server specific properties, but not building. /// To build after configuration, call . /// public ConfigureWebHostBuilder WebHost { get; } /// /// An for configuring host specific properties, but not building. /// To build after configuration, call . /// public ConfigureHostBuilder Host { get; } /// /// Builds the . /// /// A configured . public WebApplication Build() { // Wire up the host configuration here. We don't try to preserve the configuration // source itself here since we don't support mutating the host values after creating the builder. _hostBuilder.ConfigureHostConfiguration(builder => { builder.AddInMemoryCollection(_hostConfigurationValues); }); var chainedConfigSource = new TrackingChainedConfigurationSource(Configuration); // Wire up the application configuration by copying the already built configuration providers over to final configuration builder. // We wrap the existing provider in a configuration source to avoid re-bulding the already added configuration sources. _hostBuilder.ConfigureAppConfiguration(builder => { builder.Add(chainedConfigSource); foreach (var (key, value) in ((IConfigurationBuilder)Configuration).Properties) { builder.Properties[key] = value; } }); // This needs to go here to avoid adding the IHostedService that boots the server twice (the GenericWebHostService). // Copy the services that were added via WebApplicationBuilder.Services into the final IServiceCollection _hostBuilder.ConfigureServices((context, services) => { // We've only added services configured by the GenericWebHostBuilder and WebHost.ConfigureWebDefaults // at this point. HostBuilder news up a new ServiceCollection in HostBuilder.Build() we haven't seen // until now, so we cannot clear these services even though some are redundant because // we called ConfigureWebHostDefaults on both the _deferredHostBuilder and _hostBuilder. foreach (var s in _services) { services.Add(s); } // Add the hosted services that were initially added last // this makes sure any hosted services that are added run after the initial set // of hosted services. This means hosted services run before the web host starts. foreach (var s in _services.HostedServices) { services.Add(s); } // Clear the hosted services list out _services.HostedServices.Clear(); // Add any services to the user visible service collection so that they are observable // just in case users capture the Services property. Orchard does this to get a "blueprint" // of the service collection // Drop the reference to the existing collection and set the inner collection // to the new one. This allows code that has references to the service collection to still function. _services.InnerCollection = services; var hostBuilderProviders = ((IConfigurationRoot)context.Configuration).Providers; if (!hostBuilderProviders.Contains(chainedConfigSource.BuiltProvider)) { // Something removed the _hostBuilder's TrackingChainedConfigurationSource pointing back to the ConfigurationManager. // This is likely a test using WebApplicationFactory. Replicate the effect by clearing the ConfingurationManager sources. ((IConfigurationBuilder)Configuration).Sources.Clear(); } // Make builder.Configuration match the final configuration. To do that, we add the additional // providers in the inner _hostBuilders's Configuration to the ConfigurationManager. foreach (var provider in hostBuilderProviders) { if (!ReferenceEquals(provider, chainedConfigSource.BuiltProvider)) { ((IConfigurationBuilder)Configuration).Add(new ConfigurationProviderSource(provider)); } } }); // Run the other callbacks on the final host builder Host.RunDeferredCallbacks(_hostBuilder); _builtApplication = new WebApplication(_hostBuilder.Build()); // Mark the service collection as read-only to prevent future modifications _services.IsReadOnly = true; // Resolve both the _hostBuilder's Configuration and builder.Configuration to mark both as resolved within the // service provider ensuring both will be properly disposed with the provider. _ = _builtApplication.Services.GetService(); return _builtApplication; } private void ConfigureApplication(WebHostBuilderContext context, IApplicationBuilder app) { Debug.Assert(_builtApplication is not null); // UseRouting called before WebApplication such as in a StartupFilter // lets remove the property and reset it at the end so we don't mess with the routes in the filter if (app.Properties.TryGetValue(EndpointRouteBuilderKey, out var priorRouteBuilder)) { app.Properties.Remove(EndpointRouteBuilderKey); } if (context.HostingEnvironment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } // Wrap the entire destination pipeline in UseRouting() and UseEndpoints(), essentially: // destination.UseRouting() // destination.Run(source) // destination.UseEndpoints() // Set the route builder so that UseRouting will use the WebApplication as the IEndpointRouteBuilder for route matching app.Properties.Add(WebApplication.GlobalEndpointRouteBuilderKey, _builtApplication); // Only call UseRouting() if there are endpoints configured and UseRouting() wasn't called on the global route builder already if (_builtApplication.DataSources.Count > 0) { // If this is set, someone called UseRouting() when a global route builder was already set if (!_builtApplication.Properties.TryGetValue(EndpointRouteBuilderKey, out var localRouteBuilder)) { app.UseRouting(); } else { // UseEndpoints will be looking for the RouteBuilder so make sure it's set app.Properties[EndpointRouteBuilderKey] = localRouteBuilder; } } // Wire the source pipeline to run in the destination pipeline app.Use(next => { _builtApplication.Run(next); return _builtApplication.BuildRequestDelegate(); }); if (_builtApplication.DataSources.Count > 0) { // We don't know if user code called UseEndpoints(), so we will call it just in case, UseEndpoints() will ignore duplicate DataSources app.UseEndpoints(_ => { }); } // Copy the properties to the destination app builder foreach (var item in _builtApplication.Properties) { app.Properties[item.Key] = item.Value; } // Remove the route builder to clean up the properties, we're done adding routes to the pipeline app.Properties.Remove(WebApplication.GlobalEndpointRouteBuilderKey); // reset route builder if it existed, this is needed for StartupFilters if (priorRouteBuilder is not null) { app.Properties[EndpointRouteBuilderKey] = priorRouteBuilder; } } private sealed class LoggingBuilder : ILoggingBuilder { public LoggingBuilder(IServiceCollection services) { Services = services; } public IServiceCollection Services { get; } } }复制代码

ConfigureHostBuilder public sealed class ConfigureHostBuilder : IHostBuilder, ISupportsConfigureWebHost IHostBuilder ISupportsConfigureWebHost.ConfigureWebHost(Action configure, Action configureOptions) { throw new NotSupportedException("ConfigureWebHost() is not supported by WebApplicationBuilder.Host. Use the WebApplication returned by WebApplicationBuilder.Build() instead."); }复制代码

ConfigureHostBuilder实现IHostBuilder和ISupportsConfigureWebHost,但 ISupportsConfigureWebHost 的实现是假的什么意思呢?

这意味着虽然以下代码可以编译,但是会在运行时抛出异常。

WebApplicationBuilder builder = WebApplication.CreateBuilder(args); builder.Host.ConfigureWebHost(webBuilder => { webBuilder.UseStartup(); });复制代码

ConfigureServices(),该方法Action使用 IServiceCollection从WebApplicationBuilder. 以是 以下两个调用在功能上是类似 的:

后一种方法显然不值得在正常实践中使用 ,但仍然 可以使用 依赖于这种方法的现有代码,

public IHostBuilder ConfigureAppConfiguration(Action configureDelegate) { // Run these immediately so that they are observable by the imperative code configureDelegate(_context, _configuration); return this; } public IHostBuilder ConfigureServices(Action configureDelegate) { // Run these immediately so that they are observable by the imperative code configureDelegate(_context, _services); return this; }复制代码 builder.Services.AddSingleton(); builder.Host.ConfigureServices((ctx, services) => services.AddSingleton());复制代码

并非全部 委托ConfigureHostBuilder都立刻 传递给运行中的方法。比方 UseServiceProviderFactory()保存在列表中,稍后在调用WebApplicationBuilder.Build()

public IHostBuilder UseServiceProviderFactory(IServiceProviderFactory factory) where TContainerBuilder : notnull { if (factory is null) { throw new ArgumentNullException(nameof(factory)); } _operations.Add(b => b.UseServiceProviderFactory(factory)); return this; }复制代码

BootstrapHostBuilder

回到ConfigureHostBuilder我们看内部的BootstrapHostBuilder,它纪录 了IHostBuilder收到的全部 调用。比方 ConfigureHostConfiguration()和ConfigureServices(), 这与ConfigureHostBuilder立刻 实行 提供的委托相比,BootstrapHostBuilder的保存将委托提供给稍后实行 的列表。这类似 于泛型的HostBuilder工作方式。但请留意 ,这BootstrapHostBuilder调用Build()会引发异常

internal class BootstrapHostBuilder : IHostBuilder { private readonly IServiceCollection _services; private readonly List _configureHostActions = new(); private readonly List _configureAppActions = new(); private readonly List _configureServicesActions = new(); public IHost Build() { // HostingHostBuilderExtensions.ConfigureDefaults should never call this. throw new InvalidOperationException(); } public IHostBuilder ConfigureHostConfiguration(Action configureDelegate) { _configureHostActions.Add(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate))); return this; } public IHostBuilder ConfigureServices(Action configureDelegate) { // HostingHostBuilderExtensions.ConfigureDefaults calls this via ConfigureLogging _configureServicesActions.Add(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate))); return this; } // ..... }复制代码

WebApplicationBuilder构造函数

最后我们来看WebApplicationBuilder构造函数,表明 都给各人 翻译了

internal WebApplicationBuilder(WebApplicationOptions options, Action? configureDefaults = null) { Services = _services; var args = options.Args; //尽早运行方法配置通用和web主机默认值,以从appsettings.json填充配置 //要预填充的环境变量(以DOTNET和ASPNETCORE为前缀)和其他可能的默认源 //正确的默认值。 _bootstrapHostBuilder = new BootstrapHostBuilder(Services, _hostBuilder.Properties); //不要在这里指定参数,因为我们希望稍后应用它们,以便 //可以覆盖ConfigureWebHostDefaults指定的默认值 _bootstrapHostBuilder.ConfigureDefaults(args: null); // This is for testing purposes configureDefaults?.Invoke(_bootstrapHostBuilder); //我们上次在这里指定了命令行,因为我们跳过了对ConfigureDefaults的调用中的命令行。 //args可以包含主机和应用程序设置,因此我们要确保 //我们适当地订购这些配置提供程序,而不复制它们 if (args is { Length: > 0 }) { _bootstrapHostBuilder.ConfigureAppConfiguration(config => { config.AddCommandLine(args); }); } // .... }复制代码 // 自ConfigureWebHostDefaults覆盖特定于主机的设置(应用程序名称)以来,上次将参数应用于主机配置。 _bootstrapHostBuilder.ConfigureHostConfiguration(config => { if (args is { Length: > 0 }) { config.AddCommandLine(args); } // Apply the options after the args options.ApplyHostConfiguration(config); });复制代码

到此你大概 都非常疑惑 这玩意到底在干嘛。只要能看明白 下面代码就好了,调用BootstrapHostBuilder.RunDefaultCallbacks(), 它以精确 的序次 运行我们迄今为止积聚 的全部 存储的回调,以构建HostBuilderContext. 该HostBuilderContext则是用来终极 设定的剩余性能WebApplicationBuilder。

完成特定于应用程序的设置 后,在由我们手动调用Build()创建一个WebApplication实例。

Configuration = new(); // Collect the hosted services separately since we want those to run after the user's hosted services _services.TrackHostedServices = true; // This is the application configuration var (hostContext, hostConfiguration) = _bootstrapHostBuilder.RunDefaultCallbacks(Configuration, _hostBuilder); // Stop tracking here _services.TrackHostedServices = false; // Capture the host configuration values here. We capture the values so that // changes to the host configuration have no effect on the final application. The // host configuration is immutable at this point. _hostConfigurationValues = new(hostConfiguration.AsEnumerable()); // Grab the WebHostBuilderContext from the property bag to use in the ConfigureWebHostBuilder var webHostContext = (WebHostBuilderContext)hostContext.Properties[typeof(WebHostBuilderContext)]; // Grab the IWebHostEnvironment from the webHostContext. This also matches the instance in the IServiceCollection. Environment = webHostContext.HostingEnvironment; Logging = new LoggingBuilder(Services); Host = new ConfigureHostBuilder(hostContext, Configuration, Services); WebHost = new ConfigureWebHostBuilder(webHostContext, Configuration, Services);复制代码

WebApplicationBuilder.Build()

该Build()方法不黑白 常复杂,起首 是将设置 的设置 源复制到_hostBuilder的ConfigurationBuilder实现中。调用此方法时,builder它最初为空,因此这将添补 由默认构建器扩展方法添加的全部 源,以及您随后设置 的额外源。

// source itself here since we don't support mutating the host values after creating the builder. _hostBuilder.ConfigureHostConfiguration(builder => { builder.AddInMemoryCollection(_hostConfigurationValues); }); _hostBuilder.ConfigureAppConfiguration(builder => { builder.Add(chainedConfigSource); foreach (var (key, value) in ((IConfigurationBuilder)Configuration).Properties) { builder.Properties[key] = value; } });复制代码

接下来,是一样的事变 IServiceCollection,将它们从_services实例复制到_hostBuilder的聚集 中。

// This needs to go here to avoid adding the IHostedService that boots the server twice (the GenericWebHostService). // Copy the services that were added via WebApplicationBuilder.Services into the final IServiceCollection _hostBuilder.ConfigureServices((context, services) => { // We've only added services configured by the GenericWebHostBuilder and WebHost.ConfigureWebDefaults // at this point. HostBuilder news up a new ServiceCollection in HostBuilder.Build() we haven't seen // until now, so we cannot clear these services even though some are redundant because // we called ConfigureWebHostDefaults on both the _deferredHostBuilder and _hostBuilder. foreach (var s in _services) { services.Add(s); } // Add the hosted services that were initially added last // this makes sure any hosted services that are added run after the initial set // of hosted services. This means hosted services run before the web host starts. foreach (var s in _services.HostedServices) { services.Add(s); } // Clear the hosted services list out _services.HostedServices.Clear(); // Add any services to the user visible service collection so that they are observable // just in case users capture the Services property. Orchard does this to get a "blueprint" // of the service collection // Drop the reference to the existing collection and set the inner collection // to the new one. This allows code that has references to the service collection to still function. _services.InnerCollection = services; var hostBuilderProviders = ((IConfigurationRoot)context.Configuration).Providers; if (!hostBuilderProviders.Contains(chainedConfigSource.BuiltProvider)) { // Something removed the _hostBuilder's TrackingChainedConfigurationSource pointing back to the ConfigurationManager. // This is likely a test using WebApplicationFactory. Replicate the effect by clearing the ConfingurationManager sources. ((IConfigurationBuilder)Configuration).Sources.Clear(); } // Make builder.Configuration match the final configuration. To do that, we add the additional // providers in the inner _hostBuilders's Configuration to the ConfigurationManager. foreach (var provider in hostBuilderProviders) { if (!ReferenceEquals(provider, chainedConfigSource.BuiltProvider)) { ((IConfigurationBuilder)Configuration).Add(new ConfigurationProviderSource(provider)); } } });复制代码

接下来运行我们在ConfigureHostBuilder属性中收集的任何回调

// Run the other callbacks on the final host builder Host.RunDeferredCallbacks(_hostBuilder);复制代码

最后我们调用_hostBuilder.Build()构建Host实例,并将其传递给 的新实例WebApplication。调用_hostBuilder.Build()是调用全部 注册回调的地方。

_builtApplication = new WebApplication(_hostBuilder.Build());复制代码

最后,为了保持齐备 一致ConfigurationManager实例被扫除 ,并链接到存储在WebApplication. 此外IServiceCollectiononWebApplicationBuilder被标记为只读,因此在调用后实验 添加服务WebApplicationBuilder将抛出一个InvalidOperationException. 最后WebApplication返回。

// Mark the service collection as read-only to prevent future modifications _services.IsReadOnly = true; // Resolve both the _hostBuilder's Configuration and builder.Configuration to mark both as resolved within the // service provider ensuring both will be properly disposed with the provider. _ = _builtApplication.Services.GetService(); return _builtApplication;复制代码

差不多就是这样.

到此这篇关于.Net 6中WebApplicationBuilder先容 和用法的文章就先容 到这了。希望对各人 的学习有所资助,也希望各人 多多支持脚本之家。

来源:https://www.jb51.net/article/232772.htm免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有