.net core WebHostBuilder 都做了什么?

源码 

  1 File: WebHostBuilder.cs
  2 Web Access
  3 Project: src\src\Hosting\Hosting\src\Microsoft.AspNetCore.Hosting.csproj (Microsoft.AspNetCore.Hosting)
376 // Licensed to the .NET Foundation under one or more agreements.
377 // The .NET Foundation licenses this file to you under the MIT license.
378  
379 #nullable enable
380  
381 using System.Diagnostics;
382 using System.Diagnostics.CodeAnalysis;
383 using System.Reflection;
384 using System.Runtime.ExceptionServices;
385 using Microsoft.AspNetCore.Hosting.Builder;
386 using Microsoft.AspNetCore.Http;
387 using Microsoft.Extensions.Configuration;
388 using Microsoft.Extensions.DependencyInjection;
389 using Microsoft.Extensions.DependencyInjection.Extensions;
390 using Microsoft.Extensions.Hosting;
391 using Microsoft.Extensions.Logging;
392  
393 namespace Microsoft.AspNetCore.Hosting;
394  
395 /// <summary>
396 /// A builder for <see cref="IWebHost"/>
397 /// </summary>
398 public class WebHostBuilder : IWebHostBuilder
399 {
400     private readonly HostingEnvironment _hostingEnvironment;
401     private readonly IConfiguration _config;
402     private readonly WebHostBuilderContext _context;
403  
404     private WebHostOptions? _options;
405     private bool _webHostBuilt;
406     private Action<WebHostBuilderContext, IServiceCollection>? _configureServices;
407     private Action<WebHostBuilderContext, IConfigurationBuilder>? _configureAppConfigurationBuilder;
408  
409     /// <summary>
410     /// Initializes a new instance of the <see cref="WebHostBuilder"/> class.
411     /// </summary>
412     public WebHostBuilder()
413     {
414         _hostingEnvironment = new HostingEnvironment();
415  
416         _config = new ConfigurationBuilder()
417             .AddEnvironmentVariables(prefix: "ASPNETCORE_")
418             .Build();
419  
420         if (string.IsNullOrEmpty(GetSetting(WebHostDefaults.EnvironmentKey)))
421         {
422             // Try adding legacy environment keys, never remove these.
423             UseSetting(WebHostDefaults.EnvironmentKey, Environment.GetEnvironmentVariable("Hosting:Environment")
424                 ?? Environment.GetEnvironmentVariable("ASPNET_ENV"));
425         }
426  
427         if (string.IsNullOrEmpty(GetSetting(WebHostDefaults.ServerUrlsKey)))
428         {
429             // Try adding legacy url key, never remove this.
430             UseSetting(WebHostDefaults.ServerUrlsKey, Environment.GetEnvironmentVariable("ASPNETCORE_SERVER.URLS"));
431         }
432  
433         _context = new WebHostBuilderContext
434         {
435             Configuration = _config
436         };
437     }
438  
439     /// <summary>
440     /// Get the setting value from the configuration.
441     /// </summary>
442     /// <param name="key">The key of the setting to look up.</param>
443     /// <returns>The value the setting currently contains.</returns>
444     public string? GetSetting(string key)
445     {
446         return _config[key];
447     }
448  
449     /// <summary>
450     /// Add or replace a setting in the configuration.
451     /// </summary>
452     /// <param name="key">The key of the setting to add or replace.</param>
453     /// <param name="value">The value of the setting to add or replace.</param>
454     /// <returns>The <see cref="IWebHostBuilder"/>.</returns>
455     public IWebHostBuilder UseSetting(string key, string? value)
456     {
457         _config[key] = value;
458         return this;
459     }
460  
461     /// <summary>
462     /// Adds a delegate for configuring additional services for the host or web application. This may be called
463     /// multiple times.
464     /// </summary>
465     /// <param name="configureServices">A delegate for configuring the <see cref="IServiceCollection"/>.</param>
466     /// <returns>The <see cref="IWebHostBuilder"/>.</returns>
467     public IWebHostBuilder ConfigureServices(Action<IServiceCollection> configureServices)
468     {
469         ArgumentNullException.ThrowIfNull(configureServices);
470  
471         return ConfigureServices((_, services) => configureServices(services));
472     }
473  
474     /// <summary>
475     /// Adds a delegate for configuring additional services for the host or web application. This may be called
476     /// multiple times.
477     /// </summary>
478     /// <param name="configureServices">A delegate for configuring the <see cref="IServiceCollection"/>.</param>
479     /// <returns>The <see cref="IWebHostBuilder"/>.</returns>
480     public IWebHostBuilder ConfigureServices(Action<WebHostBuilderContext, IServiceCollection> configureServices)
481     {
482         _configureServices += configureServices;
483         return this;
484     }
485  
486     /// <summary>
487     /// Adds a delegate for configuring the <see cref="IConfigurationBuilder"/> that will construct an <see cref="IConfiguration"/>.
488     /// </summary>
489     /// <param name="configureDelegate">The delegate for configuring the <see cref="IConfigurationBuilder" /> that will be used to construct an <see cref="IConfiguration" />.</param>
490     /// <returns>The <see cref="IWebHostBuilder"/>.</returns>
491     /// <remarks>
492     /// The <see cref="IConfiguration"/> and <see cref="ILoggerFactory"/> on the <see cref="WebHostBuilderContext"/> are uninitialized at this stage.
493     /// The <see cref="IConfigurationBuilder"/> is pre-populated with the settings of the <see cref="IWebHostBuilder"/>.
494     /// </remarks>
495     public IWebHostBuilder ConfigureAppConfiguration(Action<WebHostBuilderContext, IConfigurationBuilder> configureDelegate)
496     {
497         _configureAppConfigurationBuilder += configureDelegate;
498         return this;
499     }
500  
501     /// <summary>
502     /// Builds the required services and an <see cref="IWebHost"/> which hosts a web application.
503     /// </summary>
504     public IWebHost Build()
505     {
506         if (_webHostBuilt)
507         {
508             throw new InvalidOperationException(Resources.WebHostBuilder_SingleInstance);
509         }
510         _webHostBuilt = true;
511  
512         var hostingServices = BuildCommonServices(out var hostingStartupErrors);
513         var applicationServices = hostingServices.Clone();
514         var hostingServiceProvider = GetProviderFromFactory(hostingServices);
515  
516         if (!_options.SuppressStatusMessages)
517         {
518             // Warn about deprecated environment variables
519             if (Environment.GetEnvironmentVariable("Hosting:Environment") != null)
520             {
521                 Console.WriteLine("The environment variable 'Hosting:Environment' is obsolete and has been replaced with 'ASPNETCORE_ENVIRONMENT'");
522             }
523  
524             if (Environment.GetEnvironmentVariable("ASPNET_ENV") != null)
525             {
526                 Console.WriteLine("The environment variable 'ASPNET_ENV' is obsolete and has been replaced with 'ASPNETCORE_ENVIRONMENT'");
527             }
528  
529             if (Environment.GetEnvironmentVariable("ASPNETCORE_SERVER.URLS") != null)
530             {
531                 Console.WriteLine("The environment variable 'ASPNETCORE_SERVER.URLS' is obsolete and has been replaced with 'ASPNETCORE_URLS'");
532             }
533         }
534  
535         AddApplicationServices(applicationServices, hostingServiceProvider);
536  
537         var host = new WebHost(
538             applicationServices,
539             hostingServiceProvider,
540             _options,
541             _config,
542             hostingStartupErrors);
543         try
544         {
545             host.Initialize();
546  
547             // resolve configuration explicitly once to mark it as resolved within the
548             // service provider, ensuring it will be properly disposed with the provider
549             _ = host.Services.GetService<IConfiguration>();
550  
551             var logger = host.Services.GetRequiredService<ILogger<WebHost>>();
552  
553             // Warn about duplicate HostingStartupAssemblies
554             var assemblyNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
555             foreach (var assemblyName in _options.GetFinalHostingStartupAssemblies())
556             {
557                 if (!assemblyNames.Add(assemblyName))
558                 {
559                     logger.LogWarning($"The assembly {assemblyName} was specified multiple times. Hosting startup assemblies should only be specified once.");
560                 }
561             }
562  
563             return host;
564         }
565         catch
566         {
567             // Dispose the host if there's a failure to initialize, this should dispose
568             // services that were constructed until the exception was thrown
569             host.Dispose();
570             throw;
571         }
572  
573         static IServiceProvider GetProviderFromFactory(IServiceCollection collection)
574         {
575             var provider = collection.BuildServiceProvider();
576             var factory = provider.GetService<IServiceProviderFactory<IServiceCollection>>();
577  
578             if (factory != null && factory is not DefaultServiceProviderFactory)
579             {
580                 using (provider)
581                 {
582                     return factory.CreateServiceProvider(factory.CreateBuilder(collection));
583                 }
584             }
585  
586             return provider;
587         }
588     }
589  
590     [MemberNotNull(nameof(_options))]
591     private IServiceCollection BuildCommonServices(out AggregateException? hostingStartupErrors)
592     {
593         hostingStartupErrors = null;
594  
595         _options = new WebHostOptions(_config);
596  
597         if (!_options.PreventHostingStartup)
598         {
599             var exceptions = new List<Exception>();
600             var processed = new HashSet<Assembly>();
601  
602             // Execute the hosting startup assemblies
603             foreach (var assemblyName in _options.GetFinalHostingStartupAssemblies())
604             {
605                 try
606                 {
607                     var assembly = Assembly.Load(new AssemblyName(assemblyName));
608  
609                     if (!processed.Add(assembly))
610                     {
611                         // Already processed, skip it
612                         continue;
613                     }
614  
615                     foreach (var attribute in assembly.GetCustomAttributes<HostingStartupAttribute>())
616                     {
617                         var hostingStartup = (IHostingStartup)Activator.CreateInstance(attribute.HostingStartupType)!;
618                         hostingStartup.Configure(this);
619                     }
620                 }
621                 catch (Exception ex)
622                 {
623                     // Capture any errors that happen during startup
624                     exceptions.Add(new InvalidOperationException($"Startup assembly {assemblyName} failed to execute. See the inner exception for more details.", ex));
625                 }
626             }
627  
628             if (exceptions.Count > 0)
629             {
630                 hostingStartupErrors = new AggregateException(exceptions);
631             }
632         }
633  
634         var contentRootPath = ResolveContentRootPath(_options.ContentRootPath, AppContext.BaseDirectory);
635  
636         // Initialize the hosting environment
637         ((IWebHostEnvironment)_hostingEnvironment).Initialize(contentRootPath, _options);
638         _context.HostingEnvironment = _hostingEnvironment;
639  
640         var services = new ServiceCollection();
641         services.AddSingleton(_options);
642         services.AddSingleton<IWebHostEnvironment>(_hostingEnvironment);
643         services.AddSingleton<IHostEnvironment>(_hostingEnvironment);
644 #pragma warning disable CS0618 // Type or member is obsolete
645         services.AddSingleton<AspNetCore.Hosting.IHostingEnvironment>(_hostingEnvironment);
646         services.AddSingleton<Extensions.Hosting.IHostingEnvironment>(_hostingEnvironment);
647 #pragma warning restore CS0618 // Type or member is obsolete
648         services.AddSingleton(_context);
649  
650         var builder = new ConfigurationBuilder()
651             .SetBasePath(_hostingEnvironment.ContentRootPath)
652             .AddConfiguration(_config, shouldDisposeConfiguration: true);
653  
654         _configureAppConfigurationBuilder?.Invoke(_context, builder);
655  
656         var configuration = builder.Build();
657         // register configuration as factory to make it dispose with the service provider
658         services.AddSingleton<IConfiguration>(_ => configuration);
659         _context.Configuration = configuration;
660  
661         services.TryAddSingleton(sp => new DiagnosticListener("Microsoft.AspNetCore"));
662         services.TryAddSingleton<DiagnosticSource>(sp => sp.GetRequiredService<DiagnosticListener>());
663         services.TryAddSingleton(sp => new ActivitySource("Microsoft.AspNetCore"));
664         services.TryAddSingleton(DistributedContextPropagator.Current);
665  
666         services.AddTransient<IApplicationBuilderFactory, ApplicationBuilderFactory>();
667         services.AddTransient<IHttpContextFactory, DefaultHttpContextFactory>();
668         services.AddScoped<IMiddlewareFactory, MiddlewareFactory>();
669         services.AddOptions();
670         services.AddLogging();
671  
672         services.AddTransient<IServiceProviderFactory<IServiceCollection>, DefaultServiceProviderFactory>();
673  
674         if (!string.IsNullOrEmpty(_options.StartupAssembly))
675         {
676             ScanAssemblyAndRegisterStartup(services, _options.StartupAssembly);
677         }
678  
679         _configureServices?.Invoke(_context, services);
680  
681         return services;
682     }
683  
684     [UnconditionalSuppressMessage("Trimmer", "IL2077", Justification = "Finding startup type in assembly requires unreferenced code. Surfaced to user in UseStartup(startupAssemblyName).")]
685     [UnconditionalSuppressMessage("Trimmer", "IL2072", Justification = "Finding startup type in assembly requires unreferenced code. Surfaced to user in UseStartup(startupAssemblyName).")]
686     private void ScanAssemblyAndRegisterStartup(ServiceCollection services, string startupAssemblyName)
687     {
688         try
689         {
690             var startupType = StartupLoader.FindStartupType(startupAssemblyName, _hostingEnvironment.EnvironmentName);
691  
692             if (typeof(IStartup).IsAssignableFrom(startupType))
693             {
694                 services.AddSingleton(typeof(IStartup), startupType);
695             }
696             else
697             {
698                 services.AddSingleton(typeof(IStartup), RegisterStartup);
699  
700                 [UnconditionalSuppressMessage("Trimmer", "IL2077", Justification = "Finding startup type in assembly requires unreferenced code. Surfaced to user in UseStartup(startupAssemblyName).")]
701                 object RegisterStartup(IServiceProvider serviceProvider)
702                 {
703                     var hostingEnvironment = serviceProvider.GetRequiredService<IHostEnvironment>();
704                     var methods = StartupLoader.LoadMethods(serviceProvider, startupType, hostingEnvironment.EnvironmentName);
705                     return new ConventionBasedStartup(methods);
706                 }
707             }
708         }
709         catch (Exception ex)
710         {
711             var capture = ExceptionDispatchInfo.Capture(ex);
712             services.AddSingleton<IStartup>(_ =>
713             {
714                 capture.Throw();
715                 return null;
716             });
717         }
718     }
719  
720     private static void AddApplicationServices(IServiceCollection services, IServiceProvider hostingServiceProvider)
721     {
722         // We are forwarding services from hosting container so hosting container
723         // can still manage their lifetime (disposal) shared instances with application services.
724         // NOTE: This code overrides original services lifetime. Instances would always be singleton in
725         // application container.
726         var listener = hostingServiceProvider.GetService<DiagnosticListener>();
727         services.Replace(ServiceDescriptor.Singleton(typeof(DiagnosticListener), listener!));
728         services.Replace(ServiceDescriptor.Singleton(typeof(DiagnosticSource), listener!));
729  
730         var activitySource = hostingServiceProvider.GetService<ActivitySource>();
731         services.Replace(ServiceDescriptor.Singleton(typeof(ActivitySource), activitySource!));
732     }
733  
734     private static string ResolveContentRootPath(string? contentRootPath, string basePath)
735     {
736         if (string.IsNullOrEmpty(contentRootPath))
737         {
738             return basePath;
739         }
740         if (Path.IsPathRooted(contentRootPath))
741         {
742             return contentRootPath;
743         }
744         return Path.Combine(Path.GetFullPath(basePath), contentRootPath);
745     }
746 }
747 Document OutlineProject ExplorerNamespace Explorer

 

posted on 2023-02-24 01:09  是水饺不是水饺  阅读(15)  评论(0编辑  收藏  举报

导航