.net core WebApplication.CreateBuilder(args) 都做了什么?
var builder = WebApplication.CreateBuilder(args);
WebApplication 源码
主要 调用
357 public static WebApplicationBuilder CreateBuilder(string[] args) =>
358 new(new() { Args = args });
1 File: WebApplication.cs
2 Web Access
3 Project: src\src\DefaultBuilder\src\Microsoft.AspNetCore.csproj (Microsoft.AspNetCore)
245 // Licensed to the .NET Foundation under one or more agreements.
246 // The .NET Foundation licenses this file to you under the MIT license.
247
248 using System.Diagnostics.CodeAnalysis;
249 using Microsoft.AspNetCore.Hosting;
250 using Microsoft.AspNetCore.Hosting.Server;
251 using Microsoft.AspNetCore.Hosting.Server.Features;
252 using Microsoft.AspNetCore.Http;
253 using Microsoft.AspNetCore.Http.Features;
254 using Microsoft.AspNetCore.Routing;
255 using Microsoft.Extensions.Configuration;
256 using Microsoft.Extensions.DependencyInjection;
257 using Microsoft.Extensions.Hosting;
258 using Microsoft.Extensions.Logging;
259
260 namespace Microsoft.AspNetCore.Builder;
261
262 /// <summary>
263 /// The web application used to configure the HTTP pipeline, and routes.
264 /// </summary>
265 public sealed class WebApplication : IHost, IApplicationBuilder, IEndpointRouteBuilder, IAsyncDisposable
266 {
267 internal const string GlobalEndpointRouteBuilderKey = "__GlobalEndpointRouteBuilder";
268
269 private readonly IHost _host;
270 private readonly List<EndpointDataSource> _dataSources = new();
271
272 internal WebApplication(IHost host)
273 {
274 _host = host;
275 ApplicationBuilder = new ApplicationBuilder(host.Services, ServerFeatures);
276 Logger = host.Services.GetRequiredService<ILoggerFactory>().CreateLogger(Environment.ApplicationName ?? nameof(WebApplication));
277
278 Properties[GlobalEndpointRouteBuilderKey] = this;
279 }
280
281 /// <summary>
282 /// The application's configured services.
283 /// </summary>
284 public IServiceProvider Services => _host.Services;
285
286 /// <summary>
287 /// The application's configured <see cref="IConfiguration"/>.
288 /// </summary>
289 public IConfiguration Configuration => _host.Services.GetRequiredService<IConfiguration>();
290
291 /// <summary>
292 /// The application's configured <see cref="IWebHostEnvironment"/>.
293 /// </summary>
294 public IWebHostEnvironment Environment => _host.Services.GetRequiredService<IWebHostEnvironment>();
295
296 /// <summary>
297 /// Allows consumers to be notified of application lifetime events.
298 /// </summary>
299 public IHostApplicationLifetime Lifetime => _host.Services.GetRequiredService<IHostApplicationLifetime>();
300
301 /// <summary>
302 /// The default logger for the application.
303 /// </summary>
304 public ILogger Logger { get; }
305
306 /// <summary>
307 /// The list of URLs that the HTTP server is bound to.
308 /// </summary>
309 public ICollection<string> Urls => ServerFeatures.GetRequiredFeature<IServerAddressesFeature>().Addresses;
310
311 IServiceProvider IApplicationBuilder.ApplicationServices
312 {
313 get => ApplicationBuilder.ApplicationServices;
314 set => ApplicationBuilder.ApplicationServices = value;
315 }
316
317 internal IFeatureCollection ServerFeatures => _host.Services.GetRequiredService<IServer>().Features;
318 IFeatureCollection IApplicationBuilder.ServerFeatures => ServerFeatures;
319
320 internal IDictionary<string, object?> Properties => ApplicationBuilder.Properties;
321 IDictionary<string, object?> IApplicationBuilder.Properties => Properties;
322
323 internal ICollection<EndpointDataSource> DataSources => _dataSources;
324 ICollection<EndpointDataSource> IEndpointRouteBuilder.DataSources => DataSources;
325
326 internal ApplicationBuilder ApplicationBuilder { get; }
327
328 IServiceProvider IEndpointRouteBuilder.ServiceProvider => Services;
329
330 /// <summary>
331 /// Initializes a new instance of the <see cref="WebApplication"/> class with preconfigured defaults.
332 /// </summary>
333 /// <param name="args">The command line arguments.</param>
334 /// <returns>The <see cref="WebApplication"/>.</returns>
335 public static WebApplication Create(string[]? args = null) =>
336 new WebApplicationBuilder(new() { Args = args }).Build();
337
338 /// <summary>
339 /// Initializes a new instance of the <see cref="WebApplicationBuilder"/> class with preconfigured defaults.
340 /// </summary>
341 /// <returns>The <see cref="WebApplicationBuilder"/>.</returns>
342 public static WebApplicationBuilder CreateBuilder() =>
343 new(new());
344
345 /// <summary>
346 /// Initializes a new instance of the <see cref="WebApplicationBuilder"/> class with minimal defaults.
347 /// </summary>
348 /// <returns>The <see cref="WebApplicationBuilder"/>.</returns>
349 public static WebApplicationBuilder CreateSlimBuilder() =>
350 new(new(), slim: true);
351
352 /// <summary>
353 /// Initializes a new instance of the <see cref="WebApplicationBuilder"/> class with preconfigured defaults.
354 /// </summary>
355 /// <param name="args">The command line arguments.</param>
356 /// <returns>The <see cref="WebApplicationBuilder"/>.</returns>
357 public static WebApplicationBuilder CreateBuilder(string[] args) =>
358 new(new() { Args = args });
359
360 /// <summary>
361 /// Initializes a new instance of the <see cref="WebApplicationBuilder"/> class with minimal defaults.
362 /// </summary>
363 /// <param name="args">The command line arguments.</param>
364 /// <returns>The <see cref="WebApplicationBuilder"/>.</returns>
365 public static WebApplicationBuilder CreateSlimBuilder(string[] args) =>
366 new(new() { Args = args }, slim: true);
367
368 /// <summary>
369 /// Initializes a new instance of the <see cref="WebApplicationBuilder"/> class with preconfigured defaults.
370 /// </summary>
371 /// <param name="options">The <see cref="WebApplicationOptions"/> to configure the <see cref="WebApplicationBuilder"/>.</param>
372 /// <returns>The <see cref="WebApplicationBuilder"/>.</returns>
373 public static WebApplicationBuilder CreateBuilder(WebApplicationOptions options) =>
374 new(options);
375
376 /// <summary>
377 /// Initializes a new instance of the <see cref="WebApplicationBuilder"/> class with minimal defaults.
378 /// </summary>
379 /// <param name="options">The <see cref="WebApplicationOptions"/> to configure the <see cref="WebApplicationBuilder"/>.</param>
380 /// <returns>The <see cref="WebApplicationBuilder"/>.</returns>
381 public static WebApplicationBuilder CreateSlimBuilder(WebApplicationOptions options) =>
382 new(options, slim: true);
383
384 /// <summary>
385 /// Start the application.
386 /// </summary>
387 /// <param name="cancellationToken"></param>
388 /// <returns>
389 /// A <see cref="Task"/> that represents the startup of the <see cref="WebApplication"/>.
390 /// Successful completion indicates the HTTP server is ready to accept new requests.
391 /// </returns>
392 public Task StartAsync(CancellationToken cancellationToken = default) =>
393 _host.StartAsync(cancellationToken);
394
395 /// <summary>
396 /// Shuts down the application.
397 /// </summary>
398 /// <param name="cancellationToken"></param>
399 /// <returns>
400 /// A <see cref="Task"/> that represents the shutdown of the <see cref="WebApplication"/>.
401 /// Successful completion indicates that all the HTTP server has stopped.
402 /// </returns>
403 public Task StopAsync(CancellationToken cancellationToken = default) =>
404 _host.StopAsync(cancellationToken);
405
406 /// <summary>
407 /// Runs an application and returns a Task that only completes when the token is triggered or shutdown is triggered.
408 /// </summary>
409 /// <param name="url">The URL to listen to if the server hasn't been configured directly.</param>
410 /// <returns>
411 /// A <see cref="Task"/> that represents the entire runtime of the <see cref="WebApplication"/> from startup to shutdown.
412 /// </returns>
413 public Task RunAsync([StringSyntax(StringSyntaxAttribute.Uri)] string? url = null)
414 {
415 Listen(url);
416 return HostingAbstractionsHostExtensions.RunAsync(this);
417 }
418
419 /// <summary>
420 /// Runs an application and block the calling thread until host shutdown.
421 /// </summary>
422 /// <param name="url">The URL to listen to if the server hasn't been configured directly.</param>
423 public void Run([StringSyntax(StringSyntaxAttribute.Uri)] string? url = null)
424 {
425 Listen(url);
426 HostingAbstractionsHostExtensions.Run(this);
427 }
428
429 /// <summary>
430 /// Disposes the application.
431 /// </summary>
432 void IDisposable.Dispose() => _host.Dispose();
433
434 /// <summary>
435 /// Disposes the application.
436 /// </summary>
437 public ValueTask DisposeAsync() => ((IAsyncDisposable)_host).DisposeAsync();
438
439 internal RequestDelegate BuildRequestDelegate() => ApplicationBuilder.Build();
440 RequestDelegate IApplicationBuilder.Build() => BuildRequestDelegate();
441
442 // REVIEW: Should this be wrapping another type?
443 IApplicationBuilder IApplicationBuilder.New()
444 {
445 var newBuilder = ApplicationBuilder.New();
446 // Remove the route builder so branched pipelines have their own routing world
447 newBuilder.Properties.Remove(GlobalEndpointRouteBuilderKey);
448 return newBuilder;
449 }
450
451 /// <summary>
452 /// Adds the middleware to the application request pipeline.
453 /// </summary>
454 /// <param name="middleware">The middleware.</param>
455 /// <returns>An instance of <see cref="IApplicationBuilder"/> after the operation has completed.</returns>
456 public IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)
457 {
458 ApplicationBuilder.Use(middleware);
459 return this;
460 }
461
462 IApplicationBuilder IEndpointRouteBuilder.CreateApplicationBuilder() => ((IApplicationBuilder)this).New();
463
464 private void Listen(string? url)
465 {
466 if (url is null)
467 {
468 return;
469 }
470
471 var addresses = ServerFeatures.Get<IServerAddressesFeature>()?.Addresses;
472 if (addresses is null)
473 {
474 throw new InvalidOperationException($"Changing the URL is not supported because no valid {nameof(IServerAddressesFeature)} was found.");
475 }
476 if (addresses.IsReadOnly)
477 {
478 throw new InvalidOperationException($"Changing the URL is not supported because {nameof(IServerAddressesFeature.Addresses)} {nameof(ICollection<string>.IsReadOnly)}.");
479 }
480
481 addresses.Clear();
482 addresses.Add(url);
483 }
484 }
485 Document OutlineProject ExplorerNamespace Explorer
CreateBuilder
主要构建了以下属性
596 public IWebHostEnvironment Environment { get; }
601 public IServiceCollection Services => _hostApplicationBuilder.Services;
606 public ConfigurationManager Configuration => _hostApplicationBuilder.Configuration;
611 public ILoggingBuilder Logging => _hostApplicationBuilder.Logging;
617 public ConfigureWebHostBuilder WebHost { get; }
623 public ConfigureHostBuilder Host { get; }
这三个是由 HostApplicationBuilder _hostApplicationBuilder 构建
601 public IServiceCollection Services => _hostApplicationBuilder.Services;
606 public ConfigurationManager Configuration => _hostApplicationBuilder.Configuration;
611 public ILoggingBuilder Logging => _hostApplicationBuilder.Logging;
1 File: WebApplicationBuilder.cs
2 Web Access
3 Project: src\src\DefaultBuilder\src\Microsoft.AspNetCore.csproj (Microsoft.AspNetCore)
378 // Licensed to the .NET Foundation under one or more agreements.
379 // The .NET Foundation licenses this file to you under the MIT license.
380
381 using System.Diagnostics;
382 using Microsoft.AspNetCore.Authentication;
383 using Microsoft.AspNetCore.Authorization;
384 using Microsoft.AspNetCore.Hosting;
385 using Microsoft.Extensions.Configuration;
386 using Microsoft.Extensions.DependencyInjection;
387 using Microsoft.Extensions.Hosting;
388 using Microsoft.Extensions.Logging;
389
390 namespace Microsoft.AspNetCore.Builder;
391
392 /// <summary>
393 /// A builder for web applications and services.
394 /// </summary>
395 public sealed class WebApplicationBuilder
396 {
397 private const string EndpointRouteBuilderKey = "__EndpointRouteBuilder";
398 private const string AuthenticationMiddlewareSetKey = "__AuthenticationMiddlewareSet";
399 private const string AuthorizationMiddlewareSetKey = "__AuthorizationMiddlewareSet";
400 private const string UseRoutingKey = "__UseRouting";
401
402 private readonly HostApplicationBuilder _hostApplicationBuilder;
403 private readonly ServiceDescriptor _genericWebHostServiceDescriptor;
404
405 private WebApplication? _builtApplication;
406
407 internal WebApplicationBuilder(WebApplicationOptions options, Action<IHostBuilder>? configureDefaults = null)
408 {
409 var configuration = new ConfigurationManager();
410
411 configuration.AddEnvironmentVariables(prefix: "ASPNETCORE_");
412
413 _hostApplicationBuilder = new HostApplicationBuilder(new HostApplicationBuilderSettings
414 {
415 Args = options.Args,
416 ApplicationName = options.ApplicationName,
417 EnvironmentName = options.EnvironmentName,
418 ContentRootPath = options.ContentRootPath,
419 Configuration = configuration,
420 });
421
422 // Set WebRootPath if necessary
423 if (options.WebRootPath is not null)
424 {
425 Configuration.AddInMemoryCollection(new[]
426 {
427 new KeyValuePair<string, string?>(WebHostDefaults.WebRootKey, options.WebRootPath),
428 });
429 }
430
431 // Run methods to configure web host defaults early to populate services
432 var bootstrapHostBuilder = new BootstrapHostBuilder(_hostApplicationBuilder);
433
434 // This is for testing purposes
435 configureDefaults?.Invoke(bootstrapHostBuilder);
436
437 bootstrapHostBuilder.ConfigureWebHostDefaults(webHostBuilder =>
438 {
439 // Runs inline.
440 webHostBuilder.Configure(ConfigureApplication);
441
442 webHostBuilder.UseSetting(WebHostDefaults.ApplicationKey, _hostApplicationBuilder.Environment.ApplicationName ?? "");
443 webHostBuilder.UseSetting(WebHostDefaults.PreventHostingStartupKey, Configuration[WebHostDefaults.PreventHostingStartupKey]);
444 webHostBuilder.UseSetting(WebHostDefaults.HostingStartupAssembliesKey, Configuration[WebHostDefaults.HostingStartupAssembliesKey]);
445 webHostBuilder.UseSetting(WebHostDefaults.HostingStartupExcludeAssembliesKey, Configuration[WebHostDefaults.HostingStartupExcludeAssembliesKey]);
446 },
447 options =>
448 {
449 // We've already applied "ASPNETCORE_" environment variables to hosting config
450 options.SuppressEnvironmentConfiguration = true;
451 });
452
453 // This applies the config from ConfigureWebHostDefaults
454 // Grab the GenericWebHostService ServiceDescriptor so we can append it after any user-added IHostedServices during Build();
455 _genericWebHostServiceDescriptor = bootstrapHostBuilder.RunDefaultCallbacks();
456
457 // Grab the WebHostBuilderContext from the property bag to use in the ConfigureWebHostBuilder. Then
458 // grab the IWebHostEnvironment from the webHostContext. This also matches the instance in the IServiceCollection.
459 var webHostContext = (WebHostBuilderContext)bootstrapHostBuilder.Properties[typeof(WebHostBuilderContext)];
460 Environment = webHostContext.HostingEnvironment;
461
462 Host = new ConfigureHostBuilder(bootstrapHostBuilder.Context, Configuration, Services);
463 WebHost = new ConfigureWebHostBuilder(webHostContext, Configuration, Services);
464 }
465
466 internal WebApplicationBuilder(WebApplicationOptions options, bool slim, Action<IHostBuilder>? configureDefaults = null)
467 {
468 Debug.Assert(slim, "should only be called with slim: true");
469
470 var configuration = new ConfigurationManager();
471
472 configuration.AddEnvironmentVariables(prefix: "ASPNETCORE_");
473
474 // SetDefaultContentRoot needs to be added between 'ASPNETCORE_' and 'DOTNET_' in order to match behavior of the non-slim WebApplicationBuilder.
475 SetDefaultContentRoot(options, configuration);
476
477 // Add the default host environment variable configuration source.
478 // This won't be added by CreateEmptyApplicationBuilder.
479 configuration.AddEnvironmentVariables(prefix: "DOTNET_");
480
481 _hostApplicationBuilder = Microsoft.Extensions.Hosting.Host.CreateEmptyApplicationBuilder(new HostApplicationBuilderSettings
482 {
483 Args = options.Args,
484 ApplicationName = options.ApplicationName,
485 EnvironmentName = options.EnvironmentName,
486 ContentRootPath = options.ContentRootPath,
487 Configuration = configuration,
488 });
489
490 // Ensure the same behavior of the non-slim WebApplicationBuilder by adding the default "app" Configuration sources
491 ApplyDefaultAppConfiguration(options, configuration);
492
493 // configure the ServiceProviderOptions here since CreateEmptyApplicationBuilder won't.
494 var serviceProviderFactory = GetServiceProviderFactory(_hostApplicationBuilder);
495 _hostApplicationBuilder.ConfigureContainer(serviceProviderFactory);
496
497 // Set WebRootPath if necessary
498 if (options.WebRootPath is not null)
499 {
500 Configuration.AddInMemoryCollection(new[]
501 {
502 new KeyValuePair<string, string?>(WebHostDefaults.WebRootKey, options.WebRootPath),
503 });
504 }
505
506 // Run methods to configure web host defaults early to populate services
507 var bootstrapHostBuilder = new BootstrapHostBuilder(_hostApplicationBuilder);
508
509 // This is for testing purposes
510 configureDefaults?.Invoke(bootstrapHostBuilder);
511
512 bootstrapHostBuilder.ConfigureSlimWebHost(
513 webHostBuilder =>
514 {
515 AspNetCore.WebHost.ConfigureWebDefaultsCore(webHostBuilder);
516
517 webHostBuilder.Configure(ConfigureEmptyApplication);
518
519 webHostBuilder.UseSetting(WebHostDefaults.ApplicationKey, _hostApplicationBuilder.Environment.ApplicationName ?? "");
520 webHostBuilder.UseSetting(WebHostDefaults.PreventHostingStartupKey, Configuration[WebHostDefaults.PreventHostingStartupKey]);
521 webHostBuilder.UseSetting(WebHostDefaults.HostingStartupAssembliesKey, Configuration[WebHostDefaults.HostingStartupAssembliesKey]);
522 webHostBuilder.UseSetting(WebHostDefaults.HostingStartupExcludeAssembliesKey, Configuration[WebHostDefaults.HostingStartupExcludeAssembliesKey]);
523 },
524 options =>
525 {
526 // We've already applied "ASPNETCORE_" environment variables to hosting config
527 options.SuppressEnvironmentConfiguration = true;
528 });
529
530 // This applies the config from ConfigureWebHostDefaults
531 // Grab the GenericWebHostService ServiceDescriptor so we can append it after any user-added IHostedServices during Build();
532 _genericWebHostServiceDescriptor = bootstrapHostBuilder.RunDefaultCallbacks();
533
534 // Grab the WebHostBuilderContext from the property bag to use in the ConfigureWebHostBuilder. Then
535 // grab the IWebHostEnvironment from the webHostContext. This also matches the instance in the IServiceCollection.
536 var webHostContext = (WebHostBuilderContext)bootstrapHostBuilder.Properties[typeof(WebHostBuilderContext)];
537 Environment = webHostContext.HostingEnvironment;
538
539 Host = new ConfigureHostBuilder(bootstrapHostBuilder.Context, Configuration, Services);
540 WebHost = new ConfigureWebHostBuilder(webHostContext, Configuration, Services);
541 }
542
543 private static DefaultServiceProviderFactory GetServiceProviderFactory(HostApplicationBuilder hostApplicationBuilder)
544 {
545 if (hostApplicationBuilder.Environment.IsDevelopment())
546 {
547 return new DefaultServiceProviderFactory(
548 new ServiceProviderOptions
549 {
550 ValidateScopes = true,
551 ValidateOnBuild = true,
552 });
553 }
554
555 return new DefaultServiceProviderFactory();
556 }
557
558 private static void SetDefaultContentRoot(WebApplicationOptions options, ConfigurationManager configuration)
559 {
560 if (options.ContentRootPath is null && configuration[HostDefaults.ContentRootKey] is null)
561 {
562 // Logic taken from https://github.com/dotnet/runtime/blob/78ed4438a42acab80541e9bde1910abaa8841db2/src/libraries/Microsoft.Extensions.Hosting/src/HostingHostBuilderExtensions.cs#L209-L227
563
564 // If we're running anywhere other than C:\Windows\system32, we default to using the CWD for the ContentRoot.
565 // However, since many things like Windows services and MSIX installers have C:\Windows\system32 as there CWD which is not likely
566 // to really be the home for things like appsettings.json, we skip changing the ContentRoot in that case. The non-"default" initial
567 // value for ContentRoot is AppContext.BaseDirectory (e.g. the executable path) which probably makes more sense than the system32.
568
569 // In my testing, both Environment.CurrentDirectory and Environment.GetFolderPath(Environment.SpecialFolder.System) return the path without
570 // any trailing directory separator characters. I'm not even sure the casing can ever be different from these APIs, but I think it makes sense to
571 // ignore case for Windows path comparisons given the file system is usually (always?) going to be case insensitive for the system path.
572 string cwd = System.Environment.CurrentDirectory;
573 if (!OperatingSystem.IsWindows() || !string.Equals(cwd, System.Environment.GetFolderPath(System.Environment.SpecialFolder.System), StringComparison.OrdinalIgnoreCase))
574 {
575 configuration.AddInMemoryCollection(new[]
576 {
577 new KeyValuePair<string, string?>(HostDefaults.ContentRootKey, cwd),
578 });
579 }
580 }
581 }
582
583 private static void ApplyDefaultAppConfiguration(WebApplicationOptions options, ConfigurationManager configuration)
584 {
585 configuration.AddEnvironmentVariables();
586
587 if (options.Args is { Length: > 0 } args)
588 {
589 configuration.AddCommandLine(args);
590 }
591 }
592
593 /// <summary>
594 /// Provides information about the web hosting environment an application is running.
595 /// </summary>
596 public IWebHostEnvironment Environment { get; }
597
598 /// <summary>
599 /// A collection of services for the application to compose. This is useful for adding user provided or framework provided services.
600 /// </summary>
601 public IServiceCollection Services => _hostApplicationBuilder.Services;
602
603 /// <summary>
604 /// A collection of configuration providers for the application to compose. This is useful for adding new configuration sources and providers.
605 /// </summary>
606 public ConfigurationManager Configuration => _hostApplicationBuilder.Configuration;
607
608 /// <summary>
609 /// A collection of logging providers for the application to compose. This is useful for adding new logging providers.
610 /// </summary>
611 public ILoggingBuilder Logging => _hostApplicationBuilder.Logging;
612
613 /// <summary>
614 /// An <see cref="IWebHostBuilder"/> for configuring server specific properties, but not building.
615 /// To build after configuration, call <see cref="Build"/>.
616 /// </summary>
617 public ConfigureWebHostBuilder WebHost { get; }
618
619 /// <summary>
620 /// An <see cref="IHostBuilder"/> for configuring host specific properties, but not building.
621 /// To build after configuration, call <see cref="Build"/>.
622 /// </summary>
623 public ConfigureHostBuilder Host { get; }
624
625 /// <summary>
626 /// Builds the <see cref="WebApplication"/>.
627 /// </summary>
628 /// <returns>A configured <see cref="WebApplication"/>.</returns>
629 public WebApplication Build()
630 {
631 // ConfigureContainer callbacks run after ConfigureServices callbacks including the one that adds GenericWebHostService by default.
632 // One nice side effect is this gives a way to configure an IHostedService that starts after the server and stops beforehand.
633 _hostApplicationBuilder.Services.Add(_genericWebHostServiceDescriptor);
634 Host.ApplyServiceProviderFactory(_hostApplicationBuilder);
635 _builtApplication = new WebApplication(_hostApplicationBuilder.Build());
636 return _builtApplication;
637 }
638
639 private void ConfigureApplication(WebHostBuilderContext context, IApplicationBuilder app)
640 {
641 ConfigureApplicationCore(
642 context,
643 app,
644 processAuthMiddlewares: () =>
645 {
646 Debug.Assert(_builtApplication is not null);
647
648 // Process authorization and authentication middlewares independently to avoid
649 // registering middlewares for services that do not exist
650 var serviceProviderIsService = _builtApplication.Services.GetService<IServiceProviderIsService>();
651 if (serviceProviderIsService?.IsService(typeof(IAuthenticationSchemeProvider)) is true)
652 {
653 // Don't add more than one instance of the middleware
654 if (!_builtApplication.Properties.ContainsKey(AuthenticationMiddlewareSetKey))
655 {
656 // The Use invocations will set the property on the outer pipeline,
657 // but we want to set it on the inner pipeline as well.
658 _builtApplication.Properties[AuthenticationMiddlewareSetKey] = true;
659 app.UseAuthentication();
660 }
661 }
662
663 if (serviceProviderIsService?.IsService(typeof(IAuthorizationHandlerProvider)) is true)
664 {
665 if (!_builtApplication.Properties.ContainsKey(AuthorizationMiddlewareSetKey))
666 {
667 _builtApplication.Properties[AuthorizationMiddlewareSetKey] = true;
668 app.UseAuthorization();
669 }
670 }
671 });
672 }
673
674 private void ConfigureEmptyApplication(WebHostBuilderContext context, IApplicationBuilder app)
675 {
676 ConfigureApplicationCore(context, app, processAuthMiddlewares: null);
677 }
678
679 private void ConfigureApplicationCore(WebHostBuilderContext context, IApplicationBuilder app, Action? processAuthMiddlewares)
680 {
681 Debug.Assert(_builtApplication is not null);
682
683 // UseRouting called before WebApplication such as in a StartupFilter
684 // lets remove the property and reset it at the end so we don't mess with the routes in the filter
685 if (app.Properties.TryGetValue(EndpointRouteBuilderKey, out var priorRouteBuilder))
686 {
687 app.Properties.Remove(EndpointRouteBuilderKey);
688 }
689
690 if (context.HostingEnvironment.IsDevelopment())
691 {
692 app.UseDeveloperExceptionPage();
693 }
694
695 // Wrap the entire destination pipeline in UseRouting() and UseEndpoints(), essentially:
696 // destination.UseRouting()
697 // destination.Run(source)
698 // destination.UseEndpoints()
699
700 // Set the route builder so that UseRouting will use the WebApplication as the IEndpointRouteBuilder for route matching
701 app.Properties.Add(WebApplication.GlobalEndpointRouteBuilderKey, _builtApplication);
702
703 // Only call UseRouting() if there are endpoints configured and UseRouting() wasn't called on the global route builder already
704 if (_builtApplication.DataSources.Count > 0)
705 {
706 // If this is set, someone called UseRouting() when a global route builder was already set
707 if (!_builtApplication.Properties.TryGetValue(EndpointRouteBuilderKey, out var localRouteBuilder))
708 {
709 app.UseRouting();
710 // Middleware the needs to re-route will use this property to call UseRouting()
711 _builtApplication.Properties[UseRoutingKey] = app.Properties[UseRoutingKey];
712 }
713 else
714 {
715 // UseEndpoints will be looking for the RouteBuilder so make sure it's set
716 app.Properties[EndpointRouteBuilderKey] = localRouteBuilder;
717 }
718 }
719
720 processAuthMiddlewares?.Invoke();
721
722 // Wire the source pipeline to run in the destination pipeline
723 app.Use(next =>
724 {
725 _builtApplication.Run(next);
726 return _builtApplication.BuildRequestDelegate();
727 });
728
729 if (_builtApplication.DataSources.Count > 0)
730 {
731 // We don't know if user code called UseEndpoints(), so we will call it just in case, UseEndpoints() will ignore duplicate DataSources
732 app.UseEndpoints(_ => { });
733 }
734
735 // Copy the properties to the destination app builder
736 foreach (var item in _builtApplication.Properties)
737 {
738 app.Properties[item.Key] = item.Value;
739 }
740
741 // Remove the route builder to clean up the properties, we're done adding routes to the pipeline
742 app.Properties.Remove(WebApplication.GlobalEndpointRouteBuilderKey);
743
744 // reset route builder if it existed, this is needed for StartupFilters
745 if (priorRouteBuilder is not null)
746 {
747 app.Properties[EndpointRouteBuilderKey] = priorRouteBuilder;
748 }
749 }
750 }
751 Document OutlineProject ExplorerNamespace Explorer
HostApplicationBuilder 源码
440 private readonly HostBuilderContext _hostBuilderContext;
441 private readonly ServiceCollection _serviceCollection = new();
442 private readonly IHostEnvironment _environment;
443 private readonly LoggingBuilder _logging;
关键方法
1 private void Initialize(HostApplicationBuilderSettings settings, out HostBuilderContext hostBuilderContext, out IHostEnvironment environment, out LoggingBuilder logging)
2 {
3 // Command line args are added even when settings.DisableDefaults == true. If the caller didn't want settings.Args applied,
4 // they wouldn't have set them on the settings.
5 HostingHostBuilderExtensions.AddCommandLineConfig(Configuration, settings.Args);
6
7 // HostApplicationBuilderSettings override all other config sources.
8 List<KeyValuePair<string, string?>>? optionList = null;
9 if (settings.ApplicationName is not null)
10 {
11 optionList ??= new List<KeyValuePair<string, string?>>();
12 optionList.Add(new KeyValuePair<string, string?>(HostDefaults.ApplicationKey, settings.ApplicationName));
13 }
14 if (settings.EnvironmentName is not null)
15 {
16 optionList ??= new List<KeyValuePair<string, string?>>();
17 optionList.Add(new KeyValuePair<string, string?>(HostDefaults.EnvironmentKey, settings.EnvironmentName));
18 }
19 if (settings.ContentRootPath is not null)
20 {
21 optionList ??= new List<KeyValuePair<string, string?>>();
22 optionList.Add(new KeyValuePair<string, string?>(HostDefaults.ContentRootKey, settings.ContentRootPath));
23 }
24 if (optionList is not null)
25 {
26 Configuration.AddInMemoryCollection(optionList);
27 }
28
29 (HostingEnvironment hostingEnvironment, PhysicalFileProvider physicalFileProvider) = HostBuilder.CreateHostingEnvironment(Configuration);
30
31 Configuration.SetFileProvider(physicalFileProvider);
32
33 hostBuilderContext = new HostBuilderContext(new Dictionary<object, object>())
34 {
35 HostingEnvironment = hostingEnvironment,
36 Configuration = Configuration,
37 };
38
39 environment = hostingEnvironment;
40
41 HostBuilder.PopulateServiceCollection(
42 Services,
43 hostBuilderContext,
44 hostingEnvironment,
45 physicalFileProvider,
46 Configuration,
47 () => _appServices!);
48
49 logging = new LoggingBuilder(Services);
50 }
以下是全部源码
1 File: HostApplicationBuilder.cs
2 Web Access
3 Project: src\src\libraries\Microsoft.Extensions.Hosting\src\Microsoft.Extensions.Hosting.csproj (Microsoft.Extensions.Hosting)
420 // Licensed to the .NET Foundation under one or more agreements.
421 // The .NET Foundation licenses this file to you under the MIT license.
422
423 using System;
424 using System.Collections.Generic;
425 using System.Diagnostics;
426 using System.IO;
427 using Microsoft.Extensions.Configuration;
428 using Microsoft.Extensions.DependencyInjection;
429 using Microsoft.Extensions.FileProviders;
430 using Microsoft.Extensions.Hosting.Internal;
431 using Microsoft.Extensions.Logging;
432
433 namespace Microsoft.Extensions.Hosting
434 {
435 /// <summary>
436 /// A builder for hosted applications and services which helps manage configuration, logging, lifetime and more.
437 /// </summary>
438 public sealed class HostApplicationBuilder
439 {
440 private readonly HostBuilderContext _hostBuilderContext;
441 private readonly ServiceCollection _serviceCollection = new();
442 private readonly IHostEnvironment _environment;
443 private readonly LoggingBuilder _logging;
444
445 private Func<IServiceProvider> _createServiceProvider;
446 private Action<object> _configureContainer = _ => { };
447 private HostBuilderAdapter? _hostBuilderAdapter;
448
449 private IServiceProvider? _appServices;
450 private bool _hostBuilt;
451
452 /// <summary>
453 /// Initializes a new instance of the <see cref="HostApplicationBuilder"/> class with preconfigured defaults.
454 /// </summary>
455 /// <remarks>
456 /// The following defaults are applied to the returned <see cref="HostApplicationBuilder"/>:
457 /// <list type="bullet">
458 /// <item><description>set the <see cref="IHostEnvironment.ContentRootPath"/> to the result of <see cref="Directory.GetCurrentDirectory()"/></description></item>
459 /// <item><description>load host <see cref="IConfiguration"/> from "DOTNET_" prefixed environment variables</description></item>
460 /// <item><description>load host <see cref="IConfiguration"/> from supplied command line args</description></item>
461 /// <item><description>load app <see cref="IConfiguration"/> from 'appsettings.json' and 'appsettings.[<see cref="IHostEnvironment.EnvironmentName"/>].json'</description></item>
462 /// <item><description>load app <see cref="IConfiguration"/> from User Secrets when <see cref="IHostEnvironment.EnvironmentName"/> is 'Development' using the entry assembly</description></item>
463 /// <item><description>load app <see cref="IConfiguration"/> from environment variables</description></item>
464 /// <item><description>load app <see cref="IConfiguration"/> from supplied command line args</description></item>
465 /// <item><description>configure the <see cref="ILoggerFactory"/> to log to the console, debug, and event source output</description></item>
466 /// <item><description>enables scope validation on the dependency injection container when <see cref="IHostEnvironment.EnvironmentName"/> is 'Development'</description></item>
467 /// </list>
468 /// </remarks>
469 public HostApplicationBuilder()
470 : this(args: null)
471 {
472 }
473
474 /// <summary>
475 /// Initializes a new instance of the <see cref="HostApplicationBuilder"/> class with preconfigured defaults.
476 /// </summary>
477 /// <remarks>
478 /// The following defaults are applied to the returned <see cref="HostApplicationBuilder"/>:
479 /// <list type="bullet">
480 /// <item><description>set the <see cref="IHostEnvironment.ContentRootPath"/> to the result of <see cref="Directory.GetCurrentDirectory()"/></description></item>
481 /// <item><description>load host <see cref="IConfiguration"/> from "DOTNET_" prefixed environment variables</description></item>
482 /// <item><description>load host <see cref="IConfiguration"/> from supplied command line args</description></item>
483 /// <item><description>load app <see cref="IConfiguration"/> from 'appsettings.json' and 'appsettings.[<see cref="IHostEnvironment.EnvironmentName"/>].json'</description></item>
484 /// <item><description>load app <see cref="IConfiguration"/> from User Secrets when <see cref="IHostEnvironment.EnvironmentName"/> is 'Development' using the entry assembly</description></item>
485 /// <item><description>load app <see cref="IConfiguration"/> from environment variables</description></item>
486 /// <item><description>load app <see cref="IConfiguration"/> from supplied command line args</description></item>
487 /// <item><description>configure the <see cref="ILoggerFactory"/> to log to the console, debug, and event source output</description></item>
488 /// <item><description>enables scope validation on the dependency injection container when <see cref="IHostEnvironment.EnvironmentName"/> is 'Development'</description></item>
489 /// </list>
490 /// </remarks>
491 /// <param name="args">The command line args.</param>
492 public HostApplicationBuilder(string[]? args)
493 : this(new HostApplicationBuilderSettings { Args = args })
494 {
495 }
496
497 /// <summary>
498 /// Initializes a new instance of the <see cref="HostApplicationBuilder"/>.
499 /// </summary>
500 /// <param name="settings">Settings controlling initial configuration and whether default settings should be used.</param>
501 public HostApplicationBuilder(HostApplicationBuilderSettings? settings)
502 {
503 settings ??= new HostApplicationBuilderSettings();
504 Configuration = settings.Configuration ?? new ConfigurationManager();
505
506 if (!settings.DisableDefaults)
507 {
508 if (settings.ContentRootPath is null && Configuration[HostDefaults.ContentRootKey] is null)
509 {
510 HostingHostBuilderExtensions.SetDefaultContentRoot(Configuration);
511 }
512
513 Configuration.AddEnvironmentVariables(prefix: "DOTNET_");
514 }
515
516 Initialize(settings, out _hostBuilderContext, out _environment, out _logging);
517
518 ServiceProviderOptions? serviceProviderOptions = null;
519 if (!settings.DisableDefaults)
520 {
521 HostingHostBuilderExtensions.ApplyDefaultAppConfiguration(_hostBuilderContext, Configuration, settings.Args);
522 HostingHostBuilderExtensions.AddDefaultServices(_hostBuilderContext, Services);
523 serviceProviderOptions = HostingHostBuilderExtensions.CreateDefaultServiceProviderOptions(_hostBuilderContext);
524 }
525
526 _createServiceProvider = () =>
527 {
528 // Call _configureContainer in case anyone adds callbacks via HostBuilderAdapter.ConfigureContainer<IServiceCollection>() during build.
529 // Otherwise, this no-ops.
530 _configureContainer(Services);
531 return serviceProviderOptions is null ? Services.BuildServiceProvider() : Services.BuildServiceProvider(serviceProviderOptions);
532 };
533 }
534
535 internal HostApplicationBuilder(HostApplicationBuilderSettings? settings, bool empty)
536 {
537 Debug.Assert(empty, "should only be called with empty: true");
538
539 settings ??= new HostApplicationBuilderSettings();
540 Configuration = settings.Configuration ?? new ConfigurationManager();
541
542 Initialize(settings, out _hostBuilderContext, out _environment, out _logging);
543
544 _createServiceProvider = () =>
545 {
546 // Call _configureContainer in case anyone adds callbacks via HostBuilderAdapter.ConfigureContainer<IServiceCollection>() during build.
547 // Otherwise, this no-ops.
548 _configureContainer(Services);
549 return Services.BuildServiceProvider();
550 };
551 }
552
553 private void Initialize(HostApplicationBuilderSettings settings, out HostBuilderContext hostBuilderContext, out IHostEnvironment environment, out LoggingBuilder logging)
554 {
555 // Command line args are added even when settings.DisableDefaults == true. If the caller didn't want settings.Args applied,
556 // they wouldn't have set them on the settings.
557 HostingHostBuilderExtensions.AddCommandLineConfig(Configuration, settings.Args);
558
559 // HostApplicationBuilderSettings override all other config sources.
560 List<KeyValuePair<string, string?>>? optionList = null;
561 if (settings.ApplicationName is not null)
562 {
563 optionList ??= new List<KeyValuePair<string, string?>>();
564 optionList.Add(new KeyValuePair<string, string?>(HostDefaults.ApplicationKey, settings.ApplicationName));
565 }
566 if (settings.EnvironmentName is not null)
567 {
568 optionList ??= new List<KeyValuePair<string, string?>>();
569 optionList.Add(new KeyValuePair<string, string?>(HostDefaults.EnvironmentKey, settings.EnvironmentName));
570 }
571 if (settings.ContentRootPath is not null)
572 {
573 optionList ??= new List<KeyValuePair<string, string?>>();
574 optionList.Add(new KeyValuePair<string, string?>(HostDefaults.ContentRootKey, settings.ContentRootPath));
575 }
576 if (optionList is not null)
577 {
578 Configuration.AddInMemoryCollection(optionList);
579 }
580
581 (HostingEnvironment hostingEnvironment, PhysicalFileProvider physicalFileProvider) = HostBuilder.CreateHostingEnvironment(Configuration);
582
583 Configuration.SetFileProvider(physicalFileProvider);
584
585 hostBuilderContext = new HostBuilderContext(new Dictionary<object, object>())
586 {
587 HostingEnvironment = hostingEnvironment,
588 Configuration = Configuration,
589 };
590
591 environment = hostingEnvironment;
592
593 HostBuilder.PopulateServiceCollection(
594 Services,
595 hostBuilderContext,
596 hostingEnvironment,
597 physicalFileProvider,
598 Configuration,
599 () => _appServices!);
600
601 logging = new LoggingBuilder(Services);
602 }
603
604 /// <summary>
605 /// Provides information about the hosting environment an application is running in.
606 /// </summary>
607 public IHostEnvironment Environment => _environment;
608
609 /// <summary>
610 /// A collection of services for the application to compose. This is useful for adding user provided or framework provided services.
611 /// </summary>
612 public ConfigurationManager Configuration { get; }
613
614 /// <summary>
615 /// A collection of services for the application to compose. This is useful for adding user provided or framework provided services.
616 /// </summary>
617 public IServiceCollection Services => _serviceCollection;
618
619 /// <summary>
620 /// A collection of logging providers for the application to compose. This is useful for adding new logging providers.
621 /// </summary>
622 public ILoggingBuilder Logging => _logging;
623
624 /// <summary>
625 /// Registers a <see cref="IServiceProviderFactory{TContainerBuilder}" /> instance to be used to create the <see cref="IServiceProvider" />.
626 /// </summary>
627 /// <param name="factory">The <see cref="IServiceProviderFactory{TContainerBuilder}" />.</param>
628 /// <param name="configure">
629 /// A delegate used to configure the <typeparamref T="TContainerBuilder" />. This can be used to configure services using
630 /// APIS specific to the <see cref="IServiceProviderFactory{TContainerBuilder}" /> implementation.
631 /// </param>
632 /// <typeparam name="TContainerBuilder">The type of builder provided by the <see cref="IServiceProviderFactory{TContainerBuilder}" />.</typeparam>
633 /// <remarks>
634 /// <para>
635 /// <see cref="ConfigureContainer{TContainerBuilder}(IServiceProviderFactory{TContainerBuilder}, Action{TContainerBuilder})"/> is called by <see cref="Build"/>
636 /// and so the delegate provided by <paramref name="configure"/> will run after all other services have been registered.
637 /// </para>
638 /// <para>
639 /// Multiple calls to <see cref="ConfigureContainer{TContainerBuilder}(IServiceProviderFactory{TContainerBuilder}, Action{TContainerBuilder})"/> will replace
640 /// the previously stored <paramref name="factory"/> and <paramref name="configure"/> delegate.
641 /// </para>
642 /// </remarks>
643 public void ConfigureContainer<TContainerBuilder>(IServiceProviderFactory<TContainerBuilder> factory, Action<TContainerBuilder>? configure = null) where TContainerBuilder : notnull
644 {
645 _createServiceProvider = () =>
646 {
647 TContainerBuilder containerBuilder = factory.CreateBuilder(Services);
648 // Call _configureContainer in case anyone adds more callbacks via HostBuilderAdapter.ConfigureContainer<TContainerBuilder>() during build.
649 // Otherwise, this is equivalent to configure?.Invoke(containerBuilder).
650 _configureContainer(containerBuilder);
651 return factory.CreateServiceProvider(containerBuilder);
652 };
653
654 // Store _configureContainer separately so it can replaced individually by the HostBuilderAdapter.
655 _configureContainer = containerBuilder => configure?.Invoke((TContainerBuilder)containerBuilder);
656 }
657
658 /// <summary>
659 /// Build the host. This can only be called once.
660 /// </summary>
661 /// <returns>An initialized <see cref="IHost"/>.</returns>
662 public IHost Build()
663 {
664 if (_hostBuilt)
665 {
666 throw new InvalidOperationException(SR.BuildCalled);
667 }
668 _hostBuilt = true;
669
670 using DiagnosticListener diagnosticListener = HostBuilder.LogHostBuilding(this);
671 _hostBuilderAdapter?.ApplyChanges();
672
673 _appServices = _createServiceProvider();
674
675 // Prevent further modification of the service collection now that the provider is built.
676 _serviceCollection.MakeReadOnly();
677
678 return HostBuilder.ResolveHost(_appServices, diagnosticListener);
679 }
680
681 // Lazily allocate HostBuilderAdapter so the allocations can be avoided if there's nothing observing the events.
682 internal IHostBuilder AsHostBuilder() => _hostBuilderAdapter ??= new HostBuilderAdapter(this);
683
684 private sealed class HostBuilderAdapter : IHostBuilder
685 {
686 private readonly HostApplicationBuilder _hostApplicationBuilder;
687
688 private readonly List<Action<IConfigurationBuilder>> _configureHostConfigActions = new();
689 private readonly List<Action<HostBuilderContext, IConfigurationBuilder>> _configureAppConfigActions = new();
690 private readonly List<IConfigureContainerAdapter> _configureContainerActions = new();
691 private readonly List<Action<HostBuilderContext, IServiceCollection>> _configureServicesActions = new();
692
693 private IServiceFactoryAdapter? _serviceProviderFactory;
694
695 public HostBuilderAdapter(HostApplicationBuilder hostApplicationBuilder)
696 {
697 _hostApplicationBuilder = hostApplicationBuilder;
698 }
699
700 public void ApplyChanges()
701 {
702 ConfigurationManager config = _hostApplicationBuilder.Configuration;
703
704 if (_configureHostConfigActions.Count > 0)
705 {
706 string? previousApplicationName = config[HostDefaults.ApplicationKey];
707 string? previousEnvironment = config[HostDefaults.EnvironmentKey];
708 string? previousContentRootConfig = config[HostDefaults.ContentRootKey];
709 string previousContentRootPath = _hostApplicationBuilder._hostBuilderContext.HostingEnvironment.ContentRootPath;
710
711 foreach (Action<IConfigurationBuilder> configureHostAction in _configureHostConfigActions)
712 {
713 configureHostAction(config);
714 }
715
716 // Disallow changing any host settings this late in the cycle. The reasoning is that we've already loaded the default configuration
717 // and done other things based on environment name, application name or content root.
718 if (!string.Equals(previousApplicationName, config[HostDefaults.ApplicationKey], StringComparison.OrdinalIgnoreCase))
719 {
720 throw new NotSupportedException(SR.Format(SR.ApplicationNameChangeNotSupported, previousApplicationName, config[HostDefaults.ApplicationKey]));
721 }
722 if (!string.Equals(previousEnvironment, config[HostDefaults.EnvironmentKey], StringComparison.OrdinalIgnoreCase))
723 {
724 throw new NotSupportedException(SR.Format(SR.EnvironmentNameChangeNotSupoprted, previousEnvironment, config[HostDefaults.EnvironmentKey]));
725 }
726 // It's okay if the ConfigureHostConfiguration callbacks either left the config unchanged or set it back to the real ContentRootPath.
727 // Setting it to anything else indicates code intends to change the content root via HostFactoryResolver which is unsupported.
728 string? currentContentRootConfig = config[HostDefaults.ContentRootKey];
729 if (!string.Equals(previousContentRootConfig, currentContentRootConfig, StringComparison.OrdinalIgnoreCase) &&
730 !string.Equals(previousContentRootPath, HostBuilder.ResolveContentRootPath(currentContentRootConfig, AppContext.BaseDirectory), StringComparison.OrdinalIgnoreCase))
731 {
732 throw new NotSupportedException(SR.Format(SR.ContentRootChangeNotSupported, previousContentRootConfig, currentContentRootConfig));
733 }
734 }
735
736 foreach (Action<HostBuilderContext, IConfigurationBuilder> configureAppAction in _configureAppConfigActions)
737 {
738 configureAppAction(_hostApplicationBuilder._hostBuilderContext, config);
739 }
740 foreach (Action<HostBuilderContext, IServiceCollection> configureServicesAction in _configureServicesActions)
741 {
742 configureServicesAction(_hostApplicationBuilder._hostBuilderContext, _hostApplicationBuilder.Services);
743 }
744
745 if (_configureContainerActions.Count > 0)
746 {
747 Action<object> previousConfigureContainer = _hostApplicationBuilder._configureContainer;
748
749 _hostApplicationBuilder._configureContainer = containerBuilder =>
750 {
751 previousConfigureContainer(containerBuilder);
752
753 foreach (IConfigureContainerAdapter containerAction in _configureContainerActions)
754 {
755 containerAction.ConfigureContainer(_hostApplicationBuilder._hostBuilderContext, containerBuilder);
756 }
757 };
758 }
759 if (_serviceProviderFactory is not null)
760 {
761 _hostApplicationBuilder._createServiceProvider = () =>
762 {
763 object containerBuilder = _serviceProviderFactory.CreateBuilder(_hostApplicationBuilder.Services);
764 _hostApplicationBuilder._configureContainer(containerBuilder);
765 return _serviceProviderFactory.CreateServiceProvider(containerBuilder);
766 };
767 }
768 }
769
770 public IDictionary<object, object> Properties => _hostApplicationBuilder._hostBuilderContext.Properties;
771
772 public IHost Build() => throw new NotSupportedException();
773
774 public IHostBuilder ConfigureHostConfiguration(Action<IConfigurationBuilder> configureDelegate)
775 {
776 ThrowHelper.ThrowIfNull(configureDelegate);
777
778 _configureHostConfigActions.Add(configureDelegate);
779 return this;
780 }
781
782 public IHostBuilder ConfigureAppConfiguration(Action<HostBuilderContext, IConfigurationBuilder> configureDelegate)
783 {
784 ThrowHelper.ThrowIfNull(configureDelegate);
785
786 _configureAppConfigActions.Add(configureDelegate);
787 return this;
788 }
789
790 public IHostBuilder ConfigureServices(Action<HostBuilderContext, IServiceCollection> configureDelegate)
791 {
792 ThrowHelper.ThrowIfNull(configureDelegate);
793
794 _configureServicesActions.Add(configureDelegate);
795 return this;
796 }
797
798 public IHostBuilder UseServiceProviderFactory<TContainerBuilder>(IServiceProviderFactory<TContainerBuilder> factory) where TContainerBuilder : notnull
799 {
800 ThrowHelper.ThrowIfNull(factory);
801
802 _serviceProviderFactory = new ServiceFactoryAdapter<TContainerBuilder>(factory);
803 return this;
804
805 }
806
807 public IHostBuilder UseServiceProviderFactory<TContainerBuilder>(Func<HostBuilderContext, IServiceProviderFactory<TContainerBuilder>> factory) where TContainerBuilder : notnull
808 {
809 ThrowHelper.ThrowIfNull(factory);
810
811 _serviceProviderFactory = new ServiceFactoryAdapter<TContainerBuilder>(() => _hostApplicationBuilder._hostBuilderContext, factory);
812 return this;
813 }
814
815 public IHostBuilder ConfigureContainer<TContainerBuilder>(Action<HostBuilderContext, TContainerBuilder> configureDelegate)
816 {
817 ThrowHelper.ThrowIfNull(configureDelegate);
818
819 _configureContainerActions.Add(new ConfigureContainerAdapter<TContainerBuilder>(configureDelegate));
820 return this;
821 }
822 }
823
824 private sealed class LoggingBuilder : ILoggingBuilder
825 {
826 public LoggingBuilder(IServiceCollection services)
827 {
828 Services = services;
829 }
830
831 public IServiceCollection Services { get; }
832 }
833 }
834 }
835 Document OutlineProject ExplorerNamespace Explorer