zoukankan      html  css  js  c++  java
  • asp.net core 3.1 源码学习(一)

    WebHost主机

    /// <summary>
        /// A builder for <see cref="IWebHost"/>
        /// </summary>
        public class WebHostBuilder : IWebHostBuilder
        {
            private readonly HostingEnvironment _hostingEnvironment;
            private Action<WebHostBuilderContext, IServiceCollection> _configureServices;
    
            private IConfiguration _config;
            private WebHostOptions _options;
            private WebHostBuilderContext _context;
            private bool _webHostBuilt;
            private Action<WebHostBuilderContext, IConfigurationBuilder> _configureAppConfigurationBuilder;
    
            /// <summary>
            /// Initializes a new instance of the <see cref="WebHostBuilder"/> class.
            /// </summary>
            public WebHostBuilder()
            {
                _hostingEnvironment = new HostingEnvironment();
    
                _config = new ConfigurationBuilder()
                    .AddEnvironmentVariables(prefix: "ASPNETCORE_")
                    .Build();
    
                if (string.IsNullOrEmpty(GetSetting(WebHostDefaults.EnvironmentKey)))
                {
                    // Try adding legacy environment keys, never remove these.
                    UseSetting(WebHostDefaults.EnvironmentKey, Environment.GetEnvironmentVariable("Hosting:Environment")
                        ?? Environment.GetEnvironmentVariable("ASPNET_ENV"));
                }
    
                if (string.IsNullOrEmpty(GetSetting(WebHostDefaults.ServerUrlsKey)))
                {
                    // Try adding legacy url key, never remove this.
                    UseSetting(WebHostDefaults.ServerUrlsKey, Environment.GetEnvironmentVariable("ASPNETCORE_SERVER.URLS"));
                }
    
                _context = new WebHostBuilderContext
                {
                    Configuration = _config
                };
            }
    
            /// <summary>
            /// Get the setting value from the configuration.
            /// </summary>
            /// <param name="key">The key of the setting to look up.</param>
            /// <returns>The value the setting currently contains.</returns>
            public string GetSetting(string key)
            {
                return _config[key];
            }
    
            /// <summary>
            /// Add or replace a setting in the configuration.
            /// </summary>
            /// <param name="key">The key of the setting to add or replace.</param>
            /// <param name="value">The value of the setting to add or replace.</param>
            /// <returns>The <see cref="IWebHostBuilder"/>.</returns>
            public IWebHostBuilder UseSetting(string key, string value)
            {
                _config[key] = value;
                return this;
            }
    
            /// <summary>
            /// Adds a delegate for configuring additional services for the host or web application. This may be called
            /// multiple times.
            /// </summary>
            /// <param name="configureServices">A delegate for configuring the <see cref="IServiceCollection"/>.</param>
            /// <returns>The <see cref="IWebHostBuilder"/>.</returns>
            public IWebHostBuilder ConfigureServices(Action<IServiceCollection> configureServices)
            {
                if (configureServices == null)
                {
                    throw new ArgumentNullException(nameof(configureServices));
                }
    
                return ConfigureServices((_, services) => configureServices(services));
            }
    
            /// <summary>
            /// Adds a delegate for configuring additional services for the host or web application. This may be called
            /// multiple times.
            /// </summary>
            /// <param name="configureServices">A delegate for configuring the <see cref="IServiceCollection"/>.</param>
            /// <returns>The <see cref="IWebHostBuilder"/>.</returns>
            public IWebHostBuilder ConfigureServices(Action<WebHostBuilderContext, IServiceCollection> configureServices)
            {
                _configureServices += configureServices;
                return this;
            }
    
            /// <summary>
            /// Adds a delegate for configuring the <see cref="IConfigurationBuilder"/> that will construct an <see cref="IConfiguration"/>.
            /// </summary>
            /// <param name="configureDelegate">The delegate for configuring the <see cref="IConfigurationBuilder" /> that will be used to construct an <see cref="IConfiguration" />.</param>
            /// <returns>The <see cref="IWebHostBuilder"/>.</returns>
            /// <remarks>
            /// The <see cref="IConfiguration"/> and <see cref="ILoggerFactory"/> on the <see cref="WebHostBuilderContext"/> are uninitialized at this stage.
            /// The <see cref="IConfigurationBuilder"/> is pre-populated with the settings of the <see cref="IWebHostBuilder"/>.
            /// </remarks>
            public IWebHostBuilder ConfigureAppConfiguration(Action<WebHostBuilderContext, IConfigurationBuilder> configureDelegate)
            {
                _configureAppConfigurationBuilder += configureDelegate;
                return this;
            }
    
            /// <summary>
            /// Builds the required services and an <see cref="IWebHost"/> which hosts a web application.
            /// </summary>
            public IWebHost Build()
            {
                if (_webHostBuilt)
                {
                    throw new InvalidOperationException(Resources.WebHostBuilder_SingleInstance);
                }
                _webHostBuilt = true;
    
                var hostingServices = BuildCommonServices(out var hostingStartupErrors);
                var applicationServices = hostingServices.Clone();
                var hostingServiceProvider = GetProviderFromFactory(hostingServices);
    
                if (!_options.SuppressStatusMessages)
                {
                    // Warn about deprecated environment variables
                    if (Environment.GetEnvironmentVariable("Hosting:Environment") != null)
                    {
                        Console.WriteLine("The environment variable 'Hosting:Environment' is obsolete and has been replaced with 'ASPNETCORE_ENVIRONMENT'");
                    }
    
                    if (Environment.GetEnvironmentVariable("ASPNET_ENV") != null)
                    {
                        Console.WriteLine("The environment variable 'ASPNET_ENV' is obsolete and has been replaced with 'ASPNETCORE_ENVIRONMENT'");
                    }
    
                    if (Environment.GetEnvironmentVariable("ASPNETCORE_SERVER.URLS") != null)
                    {
                        Console.WriteLine("The environment variable 'ASPNETCORE_SERVER.URLS' is obsolete and has been replaced with 'ASPNETCORE_URLS'");
                    }
                }
    
                AddApplicationServices(applicationServices, hostingServiceProvider);
    
                var host = new WebHost(
                    applicationServices,
                    hostingServiceProvider,
                    _options,
                    _config,
                    hostingStartupErrors);
                try
                {
                    host.Initialize();
    
                    // resolve configuration explicitly once to mark it as resolved within the
                    // service provider, ensuring it will be properly disposed with the provider
                    _ = host.Services.GetService<IConfiguration>();
    
                    var logger = host.Services.GetRequiredService<ILogger<WebHost>>();
    
                    // Warn about duplicate HostingStartupAssemblies
                    foreach (var assemblyName in _options.GetFinalHostingStartupAssemblies().GroupBy(a => a, StringComparer.OrdinalIgnoreCase).Where(g => g.Count() > 1))
                    {
                        logger.LogWarning($"The assembly {assemblyName} was specified multiple times. Hosting startup assemblies should only be specified once.");
                    }
    
                    return host;
                }
                catch
                {
                    // Dispose the host if there's a failure to initialize, this should dispose
                    // services that were constructed until the exception was thrown
                    host.Dispose();
                    throw;
                }
    
                IServiceProvider GetProviderFromFactory(IServiceCollection collection)
                {
                    var provider = collection.BuildServiceProvider();
                    var factory = provider.GetService<IServiceProviderFactory<IServiceCollection>>();
    
                    if (factory != null && !(factory is DefaultServiceProviderFactory))
                    {
                        using (provider)
                        {
                            return factory.CreateServiceProvider(factory.CreateBuilder(collection));
                        }
                    }
    
                    return provider;
                }
            }
    
            private IServiceCollection BuildCommonServices(out AggregateException hostingStartupErrors)
            {
                hostingStartupErrors = null;
    
                _options = new WebHostOptions(_config, Assembly.GetEntryAssembly()?.GetName().Name);
    
                if (!_options.PreventHostingStartup)
                {
                    var exceptions = new List<Exception>();
    
                    // Execute the hosting startup assemblies
                    foreach (var assemblyName in _options.GetFinalHostingStartupAssemblies().Distinct(StringComparer.OrdinalIgnoreCase))
                    {
                        try
                        {
                            var assembly = Assembly.Load(new AssemblyName(assemblyName));
    
                            foreach (var attribute in assembly.GetCustomAttributes<HostingStartupAttribute>())
                            {
                                var hostingStartup = (IHostingStartup)Activator.CreateInstance(attribute.HostingStartupType);
                                hostingStartup.Configure(this);
                            }
                        }
                        catch (Exception ex)
                        {
                            // Capture any errors that happen during startup
                            exceptions.Add(new InvalidOperationException($"Startup assembly {assemblyName} failed to execute. See the inner exception for more details.", ex));
                        }
                    }
    
                    if (exceptions.Count > 0)
                    {
                        hostingStartupErrors = new AggregateException(exceptions);
                    }
                }
    
                var contentRootPath = ResolveContentRootPath(_options.ContentRootPath, AppContext.BaseDirectory);
    
                // Initialize the hosting environment
                ((IWebHostEnvironment)_hostingEnvironment).Initialize(contentRootPath, _options);
                _context.HostingEnvironment = _hostingEnvironment;
    
                var services = new ServiceCollection();
                services.AddSingleton(_options);
                services.AddSingleton<IWebHostEnvironment>(_hostingEnvironment);
                services.AddSingleton<IHostEnvironment>(_hostingEnvironment);
    #pragma warning disable CS0618 // Type or member is obsolete
                services.AddSingleton<AspNetCore.Hosting.IHostingEnvironment>(_hostingEnvironment);
                services.AddSingleton<Extensions.Hosting.IHostingEnvironment>(_hostingEnvironment);
    #pragma warning restore CS0618 // Type or member is obsolete
                services.AddSingleton(_context);
    
                var builder = new ConfigurationBuilder()
                    .SetBasePath(_hostingEnvironment.ContentRootPath)
                    .AddConfiguration(_config, shouldDisposeConfiguration: true);
    
                _configureAppConfigurationBuilder?.Invoke(_context, builder);
    
                var configuration = builder.Build();
                // register configuration as factory to make it dispose with the service provider
                services.AddSingleton<IConfiguration>(_ => configuration);
                _context.Configuration = configuration;
    
                var listener = new DiagnosticListener("Microsoft.AspNetCore");
                services.AddSingleton<DiagnosticListener>(listener);
                services.AddSingleton<DiagnosticSource>(listener);
    
                services.AddTransient<IApplicationBuilderFactory, ApplicationBuilderFactory>();
                services.AddTransient<IHttpContextFactory, DefaultHttpContextFactory>();
                services.AddScoped<IMiddlewareFactory, MiddlewareFactory>();
                services.AddOptions();
                services.AddLogging();
    
                services.AddTransient<IServiceProviderFactory<IServiceCollection>, DefaultServiceProviderFactory>();
    
                if (!string.IsNullOrEmpty(_options.StartupAssembly))
                {
                    try
                    {
                        var startupType = StartupLoader.FindStartupType(_options.StartupAssembly, _hostingEnvironment.EnvironmentName);
    
                        if (typeof(IStartup).GetTypeInfo().IsAssignableFrom(startupType.GetTypeInfo()))
                        {
                            services.AddSingleton(typeof(IStartup), startupType);
                        }
                        else
                        {
                            services.AddSingleton(typeof(IStartup), sp =>
                            {
                                var hostingEnvironment = sp.GetRequiredService<IHostEnvironment>();
                                var methods = StartupLoader.LoadMethods(sp, startupType, hostingEnvironment.EnvironmentName);
                                return new ConventionBasedStartup(methods);
                            });
                        }
                    }
                    catch (Exception ex)
                    {
                        var capture = ExceptionDispatchInfo.Capture(ex);
                        services.AddSingleton<IStartup>(_ =>
                        {
                            capture.Throw();
                            return null;
                        });
                    }
                }
    
                _configureServices?.Invoke(_context, services);
    
                return services;
            }
    
            private void AddApplicationServices(IServiceCollection services, IServiceProvider hostingServiceProvider)
            {
                // We are forwarding services from hosting container so hosting container
                // can still manage their lifetime (disposal) shared instances with application services.
                // NOTE: This code overrides original services lifetime. Instances would always be singleton in
                // application container.
                var listener = hostingServiceProvider.GetService<DiagnosticListener>();
                services.Replace(ServiceDescriptor.Singleton(typeof(DiagnosticListener), listener));
                services.Replace(ServiceDescriptor.Singleton(typeof(DiagnosticSource), listener));
            }
    
            private string ResolveContentRootPath(string contentRootPath, string basePath)
            {
                if (string.IsNullOrEmpty(contentRootPath))
                {
                    return basePath;
                }
                if (Path.IsPathRooted(contentRootPath))
                {
                    return contentRootPath;
                }
                return Path.Combine(Path.GetFullPath(basePath), contentRootPath);
            }
        }

    看下WebHostBuilder是如何构建WebHost的

    核心方法:BuildCommonServices

    从程序集中找到实现有HostingStartupAttribute的特性,创建IHostingStartup对象,配置当前的WebHostBuilder

    初始化IWebHostEnvironment,指定FileProvider

    hostingEnvironment.ContentRootFileProvider = new PhysicalFileProvider(hostingEnvironment.ContentRootPath);
    
                var webRoot = options.WebRoot;
                if (webRoot == null)
                {
                    // Default to /wwwroot if it exists.
                    var wwwroot = Path.Combine(hostingEnvironment.ContentRootPath, "wwwroot");
                    if (Directory.Exists(wwwroot))
                    {
                        hostingEnvironment.WebRootPath = wwwroot;
                    }
                }
                else
                {
                    hostingEnvironment.WebRootPath = Path.Combine(hostingEnvironment.ContentRootPath, webRoot);
                }
    
                if (!string.IsNullOrEmpty(hostingEnvironment.WebRootPath))
                {
                    hostingEnvironment.WebRootPath = Path.GetFullPath(hostingEnvironment.WebRootPath);
                    if (!Directory.Exists(hostingEnvironment.WebRootPath))
                    {
                        Directory.CreateDirectory(hostingEnvironment.WebRootPath);
                    }
                    hostingEnvironment.WebRootFileProvider = new PhysicalFileProvider(hostingEnvironment.WebRootPath);
                }
                else
                {
                    hostingEnvironment.WebRootFileProvider = new NullFileProvider();
                }

    接下来创建应用的配置和注入指定的服务

    var services = new ServiceCollection();
                services.AddSingleton(_options);
                services.AddSingleton<IWebHostEnvironment>(_hostingEnvironment);
                services.AddSingleton<IHostEnvironment>(_hostingEnvironment);
    #pragma warning disable CS0618 // Type or member is obsolete
                services.AddSingleton<AspNetCore.Hosting.IHostingEnvironment>(_hostingEnvironment);
                services.AddSingleton<Extensions.Hosting.IHostingEnvironment>(_hostingEnvironment);
    #pragma warning restore CS0618 // Type or member is obsolete
                services.AddSingleton(_context);
    
                var builder = new ConfigurationBuilder()
                    .SetBasePath(_hostingEnvironment.ContentRootPath)
                    .AddConfiguration(_config, shouldDisposeConfiguration: true);
    
                _configureAppConfigurationBuilder?.Invoke(_context, builder);
    
                var configuration = builder.Build();
                // register configuration as factory to make it dispose with the service provider
                services.AddSingleton<IConfiguration>(_ => configuration);
                _context.Configuration = configuration;
    
                var listener = new DiagnosticListener("Microsoft.AspNetCore");
                services.AddSingleton<DiagnosticListener>(listener);
                services.AddSingleton<DiagnosticSource>(listener);
    
                services.AddTransient<IApplicationBuilderFactory, ApplicationBuilderFactory>();
                services.AddTransient<IHttpContextFactory, DefaultHttpContextFactory>();
                services.AddScoped<IMiddlewareFactory, MiddlewareFactory>();
                services.AddOptions();
                services.AddLogging();
    
                services.AddTransient<IServiceProviderFactory<IServiceCollection>, DefaultServiceProviderFactory>();

    几个重要的服务:IApplicationBuilderFactory、IHttpContextFactory、IMiddlewareFactory、IServiceProviderFactory<IServiceCollection>

    如果_options.StartupAssembly指定了值,则从该程序集中获取名字为Startup的类型,如果该类型实现IStartup,则直接注册,

    否则找到该类型下面的Configure{0}、Configure{0}Container、Configure{0}Services方法,其中{0}是环境名称占位符

    internal class StartupLoader
        {
            // Creates an <see cref="StartupMethods"/> instance with the actions to run for configuring the application services and the
            // request pipeline of the application.
            // When using convention based startup, the process for initializing the services is as follows:
            // The host looks for a method with the signature <see cref="IServiceProvider"/> ConfigureServices(<see cref="IServiceCollection"/> services).
            // If it can't find one, it looks for a method with the signature <see cref="void"/> ConfigureServices(<see cref="IServiceCollection"/> services).
            // When the configure services method is void returning, the host builds a services configuration function that runs all the <see cref="IStartupConfigureServicesFilter"/>
            // instances registered on the host, along with the ConfigureServices method following a decorator pattern.
            // Additionally to the ConfigureServices method, the Startup class can define a <see cref="void"/> ConfigureContainer&lt;TContainerBuilder&gt;(TContainerBuilder builder)
            // method that further configures services into the container. If the ConfigureContainer method is defined, the services configuration function
            // creates a TContainerBuilder <see cref="IServiceProviderFactory{TContainerBuilder}"/> and runs all the <see cref="IStartupConfigureContainerFilter{TContainerBuilder}"/>
            // instances registered on the host, along with the ConfigureContainer method following a decorator pattern.
            // For example:
            // StartupFilter1
            //   StartupFilter2
            //     ConfigureServices
            //   StartupFilter2
            // StartupFilter1
            // ConfigureContainerFilter1
            //   ConfigureContainerFilter2
            //     ConfigureContainer
            //   ConfigureContainerFilter2
            // ConfigureContainerFilter1
            // 
            // If the Startup class ConfigureServices returns an <see cref="IServiceProvider"/> and there is at least an <see cref="IStartupConfigureServicesFilter"/> registered we
            // throw as the filters can't be applied.
            public static StartupMethods LoadMethods(IServiceProvider hostingServiceProvider, Type startupType, string environmentName)
            {
                var configureMethod = FindConfigureDelegate(startupType, environmentName);
    
                var servicesMethod = FindConfigureServicesDelegate(startupType, environmentName);
                var configureContainerMethod = FindConfigureContainerDelegate(startupType, environmentName);
    
                object instance = null;
                if (!configureMethod.MethodInfo.IsStatic || (servicesMethod != null && !servicesMethod.MethodInfo.IsStatic))
                {
                    instance = ActivatorUtilities.GetServiceOrCreateInstance(hostingServiceProvider, startupType);
                }
    
                // The type of the TContainerBuilder. If there is no ConfigureContainer method we can just use object as it's not
                // going to be used for anything.
                var type = configureContainerMethod.MethodInfo != null ? configureContainerMethod.GetContainerType() : typeof(object);
    
                var builder = (ConfigureServicesDelegateBuilder) Activator.CreateInstance(
                    typeof(ConfigureServicesDelegateBuilder<>).MakeGenericType(type),
                    hostingServiceProvider,
                    servicesMethod,
                    configureContainerMethod,
                    instance);
    
                return new StartupMethods(instance, configureMethod.Build(instance), builder.Build());
            }
    
            private abstract class ConfigureServicesDelegateBuilder
            {
                public abstract Func<IServiceCollection, IServiceProvider> Build();
            }
    
            private class ConfigureServicesDelegateBuilder<TContainerBuilder> : ConfigureServicesDelegateBuilder
            {
                public ConfigureServicesDelegateBuilder(
                    IServiceProvider hostingServiceProvider,
                    ConfigureServicesBuilder configureServicesBuilder,
                    ConfigureContainerBuilder configureContainerBuilder,
                    object instance)
                {
                    HostingServiceProvider = hostingServiceProvider;
                    ConfigureServicesBuilder = configureServicesBuilder;
                    ConfigureContainerBuilder = configureContainerBuilder;
                    Instance = instance;
                }
    
                public IServiceProvider HostingServiceProvider { get; }
                public ConfigureServicesBuilder ConfigureServicesBuilder { get; }
                public ConfigureContainerBuilder ConfigureContainerBuilder { get; }
                public object Instance { get; }
    
                public override Func<IServiceCollection, IServiceProvider> Build()
                {
                    ConfigureServicesBuilder.StartupServiceFilters = BuildStartupServicesFilterPipeline;
                    var configureServicesCallback = ConfigureServicesBuilder.Build(Instance);
    
                    ConfigureContainerBuilder.ConfigureContainerFilters = ConfigureContainerPipeline;
                    var configureContainerCallback = ConfigureContainerBuilder.Build(Instance);
    
                    return ConfigureServices(configureServicesCallback, configureContainerCallback);
    
                    Action<object> ConfigureContainerPipeline(Action<object> action)
                    {
                        return Target;
    
                        // The ConfigureContainer pipeline needs an Action<TContainerBuilder> as source, so we just adapt the
                        // signature with this function.
                        void Source(TContainerBuilder containerBuilder) => 
                            action(containerBuilder);
    
                        // The ConfigureContainerBuilder.ConfigureContainerFilters expects an Action<object> as value, but our pipeline
                        // produces an Action<TContainerBuilder> given a source, so we wrap it on an Action<object> that internally casts
                        // the object containerBuilder to TContainerBuilder to match the expected signature of our ConfigureContainer pipeline.
                        void Target(object containerBuilder) => 
                            BuildStartupConfigureContainerFiltersPipeline(Source)((TContainerBuilder)containerBuilder);
                    }
                }
    
                Func<IServiceCollection, IServiceProvider> ConfigureServices(
                    Func<IServiceCollection, IServiceProvider> configureServicesCallback,
                    Action<object> configureContainerCallback)
                {
                    return ConfigureServicesWithContainerConfiguration;
    
                    IServiceProvider ConfigureServicesWithContainerConfiguration(IServiceCollection services)
                    {
                        // Call ConfigureServices, if that returned an IServiceProvider, we're done
                        IServiceProvider applicationServiceProvider = configureServicesCallback.Invoke(services);
    
                        if (applicationServiceProvider != null)
                        {
                            return applicationServiceProvider;
                        }
    
                        // If there's a ConfigureContainer method
                        if (ConfigureContainerBuilder.MethodInfo != null)
                        {
                            var serviceProviderFactory = HostingServiceProvider.GetRequiredService<IServiceProviderFactory<TContainerBuilder>>();
                            var builder = serviceProviderFactory.CreateBuilder(services);
                            configureContainerCallback(builder);
                            applicationServiceProvider = serviceProviderFactory.CreateServiceProvider(builder);
                        }
                        else
                        {
                            // Get the default factory
                            var serviceProviderFactory = HostingServiceProvider.GetRequiredService<IServiceProviderFactory<IServiceCollection>>();
                            var builder = serviceProviderFactory.CreateBuilder(services);
                            applicationServiceProvider = serviceProviderFactory.CreateServiceProvider(builder);
                        }
    
                        return applicationServiceProvider ?? services.BuildServiceProvider();
                    }
                }
    
                private Func<IServiceCollection, IServiceProvider> BuildStartupServicesFilterPipeline(Func<IServiceCollection, IServiceProvider> startup)
                {
                    return RunPipeline;
    
                    IServiceProvider RunPipeline(IServiceCollection services)
                    {
    #pragma warning disable CS0612 // Type or member is obsolete
                        var filters = HostingServiceProvider.GetRequiredService<IEnumerable<IStartupConfigureServicesFilter>>().Reverse().ToArray();
    #pragma warning restore CS0612 // Type or member is obsolete
    
                        // If there are no filters just run startup (makes IServiceProvider ConfigureServices(IServiceCollection services) work.
                        if (filters.Length == 0)
                        {
                            return startup(services);
                        }
    
                        Action<IServiceCollection> pipeline = InvokeStartup;
                        for (int i = 0; i < filters.Length; i++)
                        {
                            pipeline = filters[i].ConfigureServices(pipeline);
                        }
    
                        pipeline(services);
    
                        // We return null so that the host here builds the container (same result as void ConfigureServices(IServiceCollection services);
                        return null;
    
                        void InvokeStartup(IServiceCollection serviceCollection)
                        {
                            var result = startup(serviceCollection);
                            if (filters.Length > 0 && result != null)
                            {
                                // public IServiceProvider ConfigureServices(IServiceCollection serviceCollection) is not compatible with IStartupServicesFilter;
    #pragma warning disable CS0612 // Type or member is obsolete
                                var message = $"A ConfigureServices method that returns an {nameof(IServiceProvider)} is " +
                                    $"not compatible with the use of one or more {nameof(IStartupConfigureServicesFilter)}. " +
                                    $"Use a void returning ConfigureServices method instead or a ConfigureContainer method.";
    #pragma warning restore CS0612 // Type or member is obsolete
                                throw new InvalidOperationException(message);
                            };
                        }
                    }
                }
    
                private Action<TContainerBuilder> BuildStartupConfigureContainerFiltersPipeline(Action<TContainerBuilder> configureContainer)
                {
                    return RunPipeline;
    
                    void RunPipeline(TContainerBuilder containerBuilder)
                    {
                        var filters = HostingServiceProvider
    #pragma warning disable CS0612 // Type or member is obsolete
                            .GetRequiredService<IEnumerable<IStartupConfigureContainerFilter<TContainerBuilder>>>()
    #pragma warning restore CS0612 // Type or member is obsolete
                            .Reverse()
                            .ToArray();
    
                        Action<TContainerBuilder> pipeline = InvokeConfigureContainer;
                        for (int i = 0; i < filters.Length; i++)
                        {
                            pipeline = filters[i].ConfigureContainer(pipeline);
                        }
    
                        pipeline(containerBuilder);
    
                        void InvokeConfigureContainer(TContainerBuilder builder) => configureContainer(builder);
                    }
                }
            }
    
            public static Type FindStartupType(string startupAssemblyName, string environmentName)
            {
                if (string.IsNullOrEmpty(startupAssemblyName))
                {
                    throw new ArgumentException(
                        string.Format("A startup method, startup type or startup assembly is required. If specifying an assembly, '{0}' cannot be null or empty.",
                        nameof(startupAssemblyName)),
                        nameof(startupAssemblyName));
                }
    
                var assembly = Assembly.Load(new AssemblyName(startupAssemblyName));
                if (assembly == null)
                {
                    throw new InvalidOperationException(String.Format("The assembly '{0}' failed to load.", startupAssemblyName));
                }
    
                var startupNameWithEnv = "Startup" + environmentName;
                var startupNameWithoutEnv = "Startup";
    
                // Check the most likely places first
                var type =
                    assembly.GetType(startupNameWithEnv) ??
                    assembly.GetType(startupAssemblyName + "." + startupNameWithEnv) ??
                    assembly.GetType(startupNameWithoutEnv) ??
                    assembly.GetType(startupAssemblyName + "." + startupNameWithoutEnv);
    
                if (type == null)
                {
                    // Full scan
                    var definedTypes = assembly.DefinedTypes.ToList();
    
                    var startupType1 = definedTypes.Where(info => info.Name.Equals(startupNameWithEnv, StringComparison.OrdinalIgnoreCase));
                    var startupType2 = definedTypes.Where(info => info.Name.Equals(startupNameWithoutEnv, StringComparison.OrdinalIgnoreCase));
    
                    var typeInfo = startupType1.Concat(startupType2).FirstOrDefault();
                    if (typeInfo != null)
                    {
                        type = typeInfo.AsType();
                    }
                }
    
                if (type == null)
                {
                    throw new InvalidOperationException(String.Format("A type named '{0}' or '{1}' could not be found in assembly '{2}'.",
                        startupNameWithEnv,
                        startupNameWithoutEnv,
                        startupAssemblyName));
                }
    
                return type;
            }
    
            internal static ConfigureBuilder FindConfigureDelegate(Type startupType, string environmentName)
            {
                var configureMethod = FindMethod(startupType, "Configure{0}", environmentName, typeof(void), required: true);
                return new ConfigureBuilder(configureMethod);
            }
    
            internal static ConfigureContainerBuilder FindConfigureContainerDelegate(Type startupType, string environmentName)
            {
                var configureMethod = FindMethod(startupType, "Configure{0}Container", environmentName, typeof(void), required: false);
                return new ConfigureContainerBuilder(configureMethod);
            }
    
            internal static bool HasConfigureServicesIServiceProviderDelegate(Type startupType, string environmentName)
            {
                return null != FindMethod(startupType, "Configure{0}Services", environmentName, typeof(IServiceProvider), required: false);
            }
    
            internal static ConfigureServicesBuilder FindConfigureServicesDelegate(Type startupType, string environmentName)
            {
                var servicesMethod = FindMethod(startupType, "Configure{0}Services", environmentName, typeof(IServiceProvider), required: false)
                    ?? FindMethod(startupType, "Configure{0}Services", environmentName, typeof(void), required: false);
                return new ConfigureServicesBuilder(servicesMethod);
            }
    
            private static MethodInfo FindMethod(Type startupType, string methodName, string environmentName, Type returnType = null, bool required = true)
            {
                var methodNameWithEnv = string.Format(CultureInfo.InvariantCulture, methodName, environmentName);
                var methodNameWithNoEnv = string.Format(CultureInfo.InvariantCulture, methodName, "");
    
                var methods = startupType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
                var selectedMethods = methods.Where(method => method.Name.Equals(methodNameWithEnv, StringComparison.OrdinalIgnoreCase)).ToList();
                if (selectedMethods.Count > 1)
                {
                    throw new InvalidOperationException(string.Format("Having multiple overloads of method '{0}' is not supported.", methodNameWithEnv));
                }
                if (selectedMethods.Count == 0)
                {
                    selectedMethods = methods.Where(method => method.Name.Equals(methodNameWithNoEnv, StringComparison.OrdinalIgnoreCase)).ToList();
                    if (selectedMethods.Count > 1)
                    {
                        throw new InvalidOperationException(string.Format("Having multiple overloads of method '{0}' is not supported.", methodNameWithNoEnv));
                    }
                }
    
                var methodInfo = selectedMethods.FirstOrDefault();
                if (methodInfo == null)
                {
                    if (required)
                    {
                        throw new InvalidOperationException(string.Format("A public method named '{0}' or '{1}' could not be found in the '{2}' type.",
                            methodNameWithEnv,
                            methodNameWithNoEnv,
                            startupType.FullName));
    
                    }
                    return null;
                }
                if (returnType != null && methodInfo.ReturnType != returnType)
                {
                    if (required)
                    {
                        throw new InvalidOperationException(string.Format("The '{0}' method in the type '{1}' must have a return type of '{2}'.",
                            methodInfo.Name,
                            startupType.FullName,
                            returnType.Name));
                    }
                    return null;
                }
                return methodInfo;
            }
        }

    创建IServiceProvider

    IServiceProvider GetProviderFromFactory(IServiceCollection collection)
                {
                    var provider = collection.BuildServiceProvider();
                    var factory = provider.GetService<IServiceProviderFactory<IServiceCollection>>();
    
                    if (factory != null && !(factory is DefaultServiceProviderFactory))
                    {
                        using (provider)
                        {
                            return factory.CreateServiceProvider(factory.CreateBuilder(collection));
                        }
                    }
    
                    return provider;
                }

    最后创建WebHost

    var host = new WebHost(
                    applicationServices,
                    hostingServiceProvider,
                    _options,
                    _config,
                    hostingStartupErrors);
                try
                {
                    host.Initialize();
    
                    // resolve configuration explicitly once to mark it as resolved within the
                    // service provider, ensuring it will be properly disposed with the provider
                    _ = host.Services.GetService<IConfiguration>();
    
                    var logger = host.Services.GetRequiredService<ILogger<WebHost>>();
    
                    // Warn about duplicate HostingStartupAssemblies
                    foreach (var assemblyName in _options.GetFinalHostingStartupAssemblies().GroupBy(a => a, StringComparer.OrdinalIgnoreCase).Where(g => g.Count() > 1))
                    {
                        logger.LogWarning($"The assembly {assemblyName} was specified multiple times. Hosting startup assemblies should only be specified once.");
                    }
    
                    return host;
                }
                catch
                {
                    // Dispose the host if there's a failure to initialize, this should dispose
                    // services that were constructed until the exception was thrown
                    host.Dispose();
                    throw;
                }
  • 相关阅读:
    OC 属性关键字
    OC NSArray数组排序
    OC NSNumber和NSValue和NSDate和NSData
    OC Foundation框架—字符串操作方法及习题
    OC 类对象和类加载
    OC Xcode中常见的错误
    OC self注意事项
    OC 弱语法
    OC 对象和函数
    [Android算法] bitmap 将图片压缩到指定的大小
  • 原文地址:https://www.cnblogs.com/lanpingwang/p/12560313.html
Copyright © 2011-2022 走看看