| File: ConfigureHostBuilder.cs | Web Access |
| Project: src\aspnetcore\src\DefaultBuilder\src\Microsoft.AspNetCore.csproj (Microsoft.AspNetCore) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting.Infrastructure; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; namespace Microsoft.AspNetCore.Builder; /// <summary> /// A non-buildable <see cref="IHostBuilder"/> for <see cref="WebApplicationBuilder"/>. /// Use <see cref="WebApplicationBuilder.Build"/> to build the <see cref="WebApplicationBuilder"/>. /// </summary> public sealed class ConfigureHostBuilder : IHostBuilder, ISupportsConfigureWebHost { private readonly ConfigurationManager _configuration; private readonly IServiceCollection _services; private readonly HostBuilderContext _context; private readonly List<Action<HostBuilderContext, object>> _configureContainerActions = new(); private IServiceProviderFactory<object>? _serviceProviderFactory; internal ConfigureHostBuilder( HostBuilderContext context, ConfigurationManager configuration, IServiceCollection services) { _configuration = configuration; _services = services; _context = context; } /// <inheritdoc /> public IDictionary<object, object> Properties => _context.Properties; IHost IHostBuilder.Build() { throw new NotSupportedException($"Call {nameof(WebApplicationBuilder)}.{nameof(WebApplicationBuilder.Build)}() instead."); } /// <inheritdoc /> public IHostBuilder ConfigureAppConfiguration(Action<HostBuilderContext, IConfigurationBuilder> configureDelegate) { // Run these immediately so that they are observable by the imperative code configureDelegate(_context, _configuration); return this; } /// <inheritdoc /> public IHostBuilder ConfigureContainer<TContainerBuilder>(Action<HostBuilderContext, TContainerBuilder> configureDelegate) { ArgumentNullException.ThrowIfNull(configureDelegate); _configureContainerActions.Add((context, containerBuilder) => configureDelegate(context, (TContainerBuilder)containerBuilder)); return this; } /// <inheritdoc /> public IHostBuilder ConfigureHostConfiguration(Action<IConfigurationBuilder> configureDelegate) { var previousApplicationName = _configuration[HostDefaults.ApplicationKey]; // Use the real content root so we can compare paths var previousContentRoot = HostingPathResolver.ResolvePath(_context.HostingEnvironment.ContentRootPath); var previousContentRootConfig = _configuration[HostDefaults.ContentRootKey]; var previousEnvironment = _configuration[HostDefaults.EnvironmentKey]; // Run these immediately so that they are observable by the imperative code configureDelegate(_configuration); // Disallow changing any host settings this late in the cycle, the reasoning is that we've already loaded the default configuration // and done other things based on environment name, application name or content root. if (!string.Equals(previousApplicationName, _configuration[HostDefaults.ApplicationKey], StringComparison.OrdinalIgnoreCase)) { throw new NotSupportedException($"The application name changed from \"{previousApplicationName}\" to \"{_configuration[HostDefaults.ApplicationKey]}\". Changing the host configuration using WebApplicationBuilder.Host is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead."); } if (!string.Equals(previousContentRootConfig, _configuration[HostDefaults.ContentRootKey], StringComparison.OrdinalIgnoreCase) && !string.Equals(previousContentRoot, HostingPathResolver.ResolvePath(_configuration[HostDefaults.ContentRootKey]), StringComparison.OrdinalIgnoreCase)) { throw new NotSupportedException($"The content root changed from \"{previousContentRoot}\" to \"{HostingPathResolver.ResolvePath(_configuration[HostDefaults.ContentRootKey])}\". Changing the host configuration using WebApplicationBuilder.Host is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead."); } if (!string.Equals(previousEnvironment, _configuration[HostDefaults.EnvironmentKey], StringComparison.OrdinalIgnoreCase)) { throw new NotSupportedException($"The environment changed from \"{previousEnvironment}\" to \"{_configuration[HostDefaults.EnvironmentKey]}\". Changing the host configuration using WebApplicationBuilder.Host is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead."); } return this; } /// <inheritdoc /> public IHostBuilder ConfigureServices(Action<HostBuilderContext, IServiceCollection> configureDelegate) { // Run these immediately so that they are observable by the imperative code configureDelegate(_context, _services); return this; } /// <inheritdoc /> public IHostBuilder UseServiceProviderFactory<TContainerBuilder>(IServiceProviderFactory<TContainerBuilder> factory) where TContainerBuilder : notnull { ArgumentNullException.ThrowIfNull(factory); _serviceProviderFactory = new ServiceProviderFactoryAdapter<TContainerBuilder>(factory); return this; } /// <inheritdoc /> public IHostBuilder UseServiceProviderFactory<TContainerBuilder>(Func<HostBuilderContext, IServiceProviderFactory<TContainerBuilder>> factory) where TContainerBuilder : notnull { return UseServiceProviderFactory(factory(_context)); } 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."); } internal void ApplyServiceProviderFactory(HostApplicationBuilder hostApplicationBuilder) { if (_serviceProviderFactory is null) { // No custom factory. Avoid calling hostApplicationBuilder.ConfigureContainer() which might override default validation options. // If there were any callbacks supplied to ConfigureHostBuilder.ConfigureContainer(), call those with the IServiceCollection. foreach (var action in _configureContainerActions) { action(_context, _services); } return; } void ConfigureContainerBuilderAdapter(object containerBuilder) { foreach (var action in _configureContainerActions) { action(_context, containerBuilder); } } hostApplicationBuilder.ConfigureContainer(_serviceProviderFactory, ConfigureContainerBuilderAdapter); } private sealed class ServiceProviderFactoryAdapter<TContainerBuilder> : IServiceProviderFactory<object> where TContainerBuilder : notnull { private readonly IServiceProviderFactory<TContainerBuilder> _serviceProviderFactory; public ServiceProviderFactoryAdapter(IServiceProviderFactory<TContainerBuilder> serviceProviderFactory) { _serviceProviderFactory = serviceProviderFactory; } public object CreateBuilder(IServiceCollection services) => _serviceProviderFactory.CreateBuilder(services); public IServiceProvider CreateServiceProvider(object containerBuilder) => _serviceProviderFactory.CreateServiceProvider((TContainerBuilder)containerBuilder); } }