91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

.Net?6中WebApplicationBuilder原理和用法是什么

發布時間:2021-12-24 09:04:46 來源:億速云 閱讀:412 作者:柒染 欄目:開發技術

這篇文章將為大家詳細講解有關.Net 6中WebApplicationBuilder原理和用法是什么,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

介紹

.Net 6為我們帶來的一種全新的引導程序啟動的方式。與之前的拆分成Program.cs和Startup不同,整個引導啟動代碼都在Program.cs中。

我們示例程序的第一步是執行WebApplicationBuilder builder = WebApplication.CreateBuilder(args);創建一個WebApplicationBuilder實例。

從命令行中分配Args參數,并將選項對象傳遞給WebApplicationBuilder構造函數的WebApplicationOptions

  /// <summary>
        /// Initializes a new instance of the <see cref="WebApplicationBuilder"/> class with preconfigured defaults.
        /// </summary>
        /// <param name="args">Command line arguments</param>
        /// <returns>The <see cref="WebApplicationBuilder"/>.</returns>
        public static WebApplicationBuilder CreateBuilder(string[] args) =>
            new(new() { Args = args });

WebApplicationOptions和WebApplicationBuilder后面在講

internal WebApplicationBuilder(WebApplicationOptions options, Action<IHostBuilder>? configureDefaults = null)

    /// <summary>
    /// Options for configuing the behavior for <see cref="WebApplication.CreateBuilder(WebApplicationOptions)"/>.
    /// </summary>
    public class WebApplicationOptions
    {
        /// <summary>
        /// The command line arguments.
        /// </summary>
        public string[]? Args { get; init; }

        /// <summary>
        /// The environment name.
        /// </summary>
        public string? EnvironmentName { get; init; }

        /// <summary>
        /// The application name.
        /// </summary>
        public string? ApplicationName { get; init; }

        /// <summary>
        /// The content root path.
        /// </summary>
        public string? ContentRootPath { get; init; }

        /// <summary>
        /// The web root path.
        /// </summary>
        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<KeyValuePair<string, string>> _hostConfigurationValues;

        private WebApplication? _builtApplication;

        /// <summary>
        /// Provides information about the web hosting environment an application is running.
        /// </summary>
        public IWebHostEnvironment Environment { get; }

        /// <summary>
        /// A collection of services for the application to compose. This is useful for adding user provided or framework provided services.
        /// </summary>
        public IServiceCollection Services { get; }

        /// <summary>
        /// A collection of configuration providers for the application to compose. This is useful for adding new configuration sources and providers.
        /// </summary>
        public ConfigurationManager Configuration { get; }

        /// <summary>
        /// A collection of logging providers for the application to compose. This is useful for adding new logging providers.
        /// </summary>
        public ILoggingBuilder Logging { get; }

        /// <summary>
        /// An <see cref="IWebHostBuilder"/> for configuring server specific properties, but not building.
        /// To build after configuration, call <see cref="Build"/>.
        /// </summary>
        public ConfigureWebHostBuilder WebHost { get; }

        /// <summary>
        /// An <see cref="IHostBuilder"/> for configuring host specific properties, but not building.
        /// To build after configuration, call <see cref="Build"/>.
        /// </summary>
        public ConfigureHostBuilder Host { get; }

        /// <summary>
        /// Builds the <see cref="WebApplication"/>.
        /// </summary>
        /// <returns>A configured <see cref="WebApplication"/>.</returns>
        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<IEnumerable<IConfiguration>>();

            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<IWebHostBuilder> configure, Action<WebHostBuilderOptions> 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<Startup>();
});

ConfigureServices(),該方法Action<>使用IServiceCollection從WebApplicationBuilder. 所以以下兩個調用在功能上是相同的:

后一種方法顯然不值得在正常實踐中使用,但仍然可以使用依賴于這種方法的現有代碼,

 public IHostBuilder ConfigureAppConfiguration(Action<HostBuilderContext, IConfigurationBuilder> configureDelegate)
    {
        // Run these immediately so that they are observable by the imperative code
        configureDelegate(_context, _configuration);
        return this;
    }

    public IHostBuilder ConfigureServices(Action<HostBuilderContext, IServiceCollection> configureDelegate)
    {
        // Run these immediately so that they are observable by the imperative code
        configureDelegate(_context, _services);
        return this;
    }
builder.Services.AddSingleton<MyImplementation>();


builder.Host.ConfigureServices((ctx, services) => services.AddSingleton<MyImplementation>());

并非所有委托ConfigureHostBuilder都立即傳遞給運行中的方法。例如UseServiceProviderFactory()保存在列表中,稍后在調用WebApplicationBuilder.Build()

  public IHostBuilder UseServiceProviderFactory<TContainerBuilder>(IServiceProviderFactory<TContainerBuilder> 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<Action<IConfigurationBuilder>> _configureHostActions = new();
        private readonly List<Action<HostBuilderContext, IConfigurationBuilder>> _configureAppActions = new();
        private readonly List<Action<HostBuilderContext, IServiceCollection>> _configureServicesActions = new();

        public IHost Build()
        {
            // HostingHostBuilderExtensions.ConfigureDefaults should never call this.
            throw new InvalidOperationException();
        }
        public IHostBuilder ConfigureHostConfiguration(Action<IConfigurationBuilder> configureDelegate)
        {
            _configureHostActions.Add(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate)));
            return this;
        }

        public IHostBuilder ConfigureServices(Action<HostBuilderContext, IServiceCollection> configureDelegate)
        {
            // HostingHostBuilderExtensions.ConfigureDefaults calls this via ConfigureLogging
            _configureServicesActions.Add(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate)));
            return this;
        }
        // .....
    }

WebApplicationBuilder構造函數

最后我們來看WebApplicationBuilder構造函數,注釋都給大家翻譯了

internal WebApplicationBuilder(WebApplicationOptions options, Action<IHostBuilder>? 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<IEnumerable<IConfiguration>>();

            return _builtApplication;

關于.Net 6中WebApplicationBuilder原理和用法是什么就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

乌兰察布市| 德令哈市| 平原县| 沁水县| 曲阳县| 保山市| 泸西县| 克东县| 松潘县| 仙居县| 习水县| 元谋县| 天津市| 富阳市| 涡阳县| 宜阳县| 婺源县| 鹿邑县| 岳西县| 东宁县| 喀喇沁旗| 云和县| 阿拉尔市| 枣强县| 富民县| 武穴市| 东海县| 神木县| 依安县| 香格里拉县| 凤冈县| 贡山| 麻城市| 新源县| 金溪县| 合作市| 建阳市| 泾源县| 广宗县| 肥西县| 平顶山市|