Nuget包:以Microsoft.Extensins.Hosting开头的Nuget包
Github地址:https://github.com/dotnet/extensions/tree/master/src/Hosting
先看下几个重要的接口
IHostBuilder的实现类HostBuilder
/// <summary> /// A program initialization utility. /// </summary> public class HostBuilder : IHostBuilder { private List<Action<IConfigurationBuilder>> _configureHostConfigActions = new List<Action<IConfigurationBuilder>>(); private List<Action<HostBuilderContext, IConfigurationBuilder>> _configureAppConfigActions = new List<Action<HostBuilderContext, IConfigurationBuilder>>(); private List<Action<HostBuilderContext, IServiceCollection>> _configureServicesActions = new List<Action<HostBuilderContext, IServiceCollection>>(); private List<IConfigureContainerAdapter> _configureContainerActions = new List<IConfigureContainerAdapter>(); private IServiceFactoryAdapter _serviceProviderFactory = new ServiceFactoryAdapter<IServiceCollection>(new DefaultServiceProviderFactory()); private bool _hostBuilt; private IConfiguration _hostConfiguration; private IConfiguration _appConfiguration; private HostBuilderContext _hostBuilderContext; private HostingEnvironment _hostingEnvironment; private IServiceProvider _appServices; /// <summary> /// A central location for sharing state between components during the host building process. /// </summary> public IDictionary<object, object> Properties { get; } = new Dictionary<object, object>(); /// <summary> /// Set up the configuration for the builder itself. This will be used to initialize the <see cref="IHostEnvironment"/> /// for use later in the build process. This can be called multiple times and the results will be additive. /// </summary> /// <param name="configureDelegate">The delegate for configuring the <see cref="IConfigurationBuilder"/> that will be used /// to construct the <see cref="IConfiguration"/> for the host.</param> /// <returns>The same instance of the <see cref="IHostBuilder"/> for chaining.</returns> public IHostBuilder ConfigureHostConfiguration(Action<IConfigurationBuilder> configureDelegate) { _configureHostConfigActions.Add(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate))); return this; } /// <summary> /// Sets up the configuration for the remainder of the build process and application. This can be called multiple times and /// the results will be additive. The results will be available at <see cref="HostBuilderContext.Configuration"/> for /// subsequent operations, as well as in <see cref="IHost.Services"/>. /// </summary> /// <param name="configureDelegate">The delegate for configuring the <see cref="IConfigurationBuilder"/> that will be used /// to construct the <see cref="IConfiguration"/> for the host.</param> /// <returns>The same instance of the <see cref="IHostBuilder"/> for chaining.</returns> public IHostBuilder ConfigureAppConfiguration(Action<HostBuilderContext, IConfigurationBuilder> configureDelegate) { _configureAppConfigActions.Add(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate))); return this; } /// <summary> /// Adds services to the container. This can be called multiple times and the results will be additive. /// </summary> /// <param name="configureDelegate">The delegate for configuring the <see cref="IConfigurationBuilder"/> that will be used /// to construct the <see cref="IConfiguration"/> for the host.</param> /// <returns>The same instance of the <see cref="IHostBuilder"/> for chaining.</returns> public IHostBuilder ConfigureServices(Action<HostBuilderContext, IServiceCollection> configureDelegate) { _configureServicesActions.Add(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate))); return this; } /// <summary> /// Overrides the factory used to create the service provider. /// </summary> /// <typeparam name="TContainerBuilder">The type of the builder to create.</typeparam> /// <param name="factory">A factory used for creating service providers.</param> /// <returns>The same instance of the <see cref="IHostBuilder"/> for chaining.</returns> public IHostBuilder UseServiceProviderFactory<TContainerBuilder>(IServiceProviderFactory<TContainerBuilder> factory) { _serviceProviderFactory = new ServiceFactoryAdapter<TContainerBuilder>(factory ?? throw new ArgumentNullException(nameof(factory))); return this; } /// <summary> /// Overrides the factory used to create the service provider. /// </summary> /// <param name="factory">A factory used for creating service providers.</param> /// <typeparam name="TContainerBuilder">The type of the builder to create.</typeparam> /// <returns>The same instance of the <see cref="IHostBuilder"/> for chaining.</returns> public IHostBuilder UseServiceProviderFactory<TContainerBuilder>(Func<HostBuilderContext, IServiceProviderFactory<TContainerBuilder>> factory) { _serviceProviderFactory = new ServiceFactoryAdapter<TContainerBuilder>(() => _hostBuilderContext, factory ?? throw new ArgumentNullException(nameof(factory))); return this; } /// <summary> /// Enables configuring the instantiated dependency container. This can be called multiple times and /// the results will be additive. /// </summary> /// <typeparam name="TContainerBuilder">The type of the builder to create.</typeparam> /// <param name="configureDelegate">The delegate for configuring the <see cref="IConfigurationBuilder"/> that will be used /// to construct the <see cref="IConfiguration"/> for the host.</param> /// <returns>The same instance of the <see cref="IHostBuilder"/> for chaining.</returns> public IHostBuilder ConfigureContainer<TContainerBuilder>(Action<HostBuilderContext, TContainerBuilder> configureDelegate) { _configureContainerActions.Add(new ConfigureContainerAdapter<TContainerBuilder>(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate)))); return this; } /// <summary> /// Run the given actions to initialize the host. This can only be called once. /// </summary> /// <returns>An initialized <see cref="IHost"/></returns> public IHost Build() { if (_hostBuilt) { throw new InvalidOperationException("Build can only be called once."); } _hostBuilt = true; BuildHostConfiguration(); CreateHostingEnvironment(); CreateHostBuilderContext(); BuildAppConfiguration(); CreateServiceProvider(); return _appServices.GetRequiredService<IHost>(); } private void BuildHostConfiguration() { var configBuilder = new ConfigurationBuilder() .AddInMemoryCollection(); // Make sure there's some default storage since there are no default providers foreach (var buildAction in _configureHostConfigActions) { buildAction(configBuilder); } _hostConfiguration = configBuilder.Build(); } private void CreateHostingEnvironment() { _hostingEnvironment = new HostingEnvironment() { ApplicationName = _hostConfiguration[HostDefaults.ApplicationKey], EnvironmentName = _hostConfiguration[HostDefaults.EnvironmentKey] ?? Environments.Production, ContentRootPath = ResolveContentRootPath(_hostConfiguration[HostDefaults.ContentRootKey], AppContext.BaseDirectory), }; if (string.IsNullOrEmpty(_hostingEnvironment.ApplicationName)) { // Note GetEntryAssembly returns null for the net4x console test runner. _hostingEnvironment.ApplicationName = Assembly.GetEntryAssembly()?.GetName().Name; } _hostingEnvironment.ContentRootFileProvider = new PhysicalFileProvider(_hostingEnvironment.ContentRootPath); } 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); } private void CreateHostBuilderContext() { _hostBuilderContext = new HostBuilderContext(Properties) { HostingEnvironment = _hostingEnvironment, Configuration = _hostConfiguration }; } private void BuildAppConfiguration() { var configBuilder = new ConfigurationBuilder() .SetBasePath(_hostingEnvironment.ContentRootPath) .AddConfiguration(_hostConfiguration, shouldDisposeConfiguration: true); foreach (var buildAction in _configureAppConfigActions) { buildAction(_hostBuilderContext, configBuilder); } _appConfiguration = configBuilder.Build(); _hostBuilderContext.Configuration = _appConfiguration; } private void CreateServiceProvider() { var services = new ServiceCollection(); #pragma warning disable CS0618 // Type or member is obsolete services.AddSingleton<IHostingEnvironment>(_hostingEnvironment); #pragma warning restore CS0618 // Type or member is obsolete services.AddSingleton<IHostEnvironment>(_hostingEnvironment); services.AddSingleton(_hostBuilderContext); // register configuration as factory to make it dispose with the service provider services.AddSingleton(_ => _appConfiguration); #pragma warning disable CS0618 // Type or member is obsolete services.AddSingleton<IApplicationLifetime>(s => (IApplicationLifetime)s.GetService<IHostApplicationLifetime>()); #pragma warning restore CS0618 // Type or member is obsolete services.AddSingleton<IHostApplicationLifetime, ApplicationLifetime>(); services.AddSingleton<IHostLifetime, ConsoleLifetime>(); services.AddSingleton<IHost, Internal.Host>(); services.AddOptions(); services.AddLogging(); foreach (var configureServicesAction in _configureServicesActions) { configureServicesAction(_hostBuilderContext, services); } var containerBuilder = _serviceProviderFactory.CreateBuilder(services); foreach (var containerAction in _configureContainerActions) { containerAction.ConfigureContainer(_hostBuilderContext, containerBuilder); } _appServices = _serviceProviderFactory.CreateServiceProvider(containerBuilder); if (_appServices == null) { throw new InvalidOperationException($"The IServiceProviderFactory returned a null IServiceProvider."); } // resolve configuration explicitly once to mark it as resolved within the // service provider, ensuring it will be properly disposed with the provider _ = _appServices.GetService<IConfiguration>(); } }
HostBuilder中的几个重要字段
_configureHostConfigActions:主机配置的委托列表
_configureAppConfigActions:应用配置的委托列表
_configureServicesActions:服务注册的委托列表
_configureContainerActions:配置依赖注入容器
_serviceProviderFactory:服务提供工厂(默认实现new ServiceFactoryAdapter<IServiceCollection>(new DefaultServiceProviderFactory());)
方法ConfigureHostConfiguration和ConfigureAppConfiguration分别向_configureHostConfigActions和_configureAppConfigActions列表中添加配置的委托
方法ConfigureServices向_configureServicesActions添加服务
方法UseServiceProviderFactory重新定义_serviceProviderFactory
方法ConfigureContainer向_configureContainerActions添加容器的配置
再看下HostBuilder的Build()方法是如何重建一个IHost出来的
public IHost Build() { if (_hostBuilt) { throw new InvalidOperationException("Build can only be called once."); } _hostBuilt = true; BuildHostConfiguration(); CreateHostingEnvironment(); CreateHostBuilderContext(); BuildAppConfiguration(); CreateServiceProvider(); return _appServices.GetRequiredService<IHost>(); }
BuildHostConfiguration方法的实现
private void BuildHostConfiguration() { var configBuilder = new ConfigurationBuilder() .AddInMemoryCollection(); // Make sure there's some default storage since there are no default providers foreach (var buildAction in _configureHostConfigActions) { buildAction(configBuilder); } _hostConfiguration = configBuilder.Build(); }
创建ConfigurationBuilder,并调用_configureHostConfigActions列表进行配置的初始化,构建IConfiguration赋值给字段_hostConfiguration
CreateHostingEnvironment方法实现
private void CreateHostingEnvironment() { _hostingEnvironment = new HostingEnvironment() { ApplicationName = _hostConfiguration[HostDefaults.ApplicationKey], EnvironmentName = _hostConfiguration[HostDefaults.EnvironmentKey] ?? Environments.Production, ContentRootPath = ResolveContentRootPath(_hostConfiguration[HostDefaults.ContentRootKey], AppContext.BaseDirectory), }; if (string.IsNullOrEmpty(_hostingEnvironment.ApplicationName)) { // Note GetEntryAssembly returns null for the net4x console test runner. _hostingEnvironment.ApplicationName = Assembly.GetEntryAssembly()?.GetName().Name; } _hostingEnvironment.ContentRootFileProvider = new PhysicalFileProvider(_hostingEnvironment.ContentRootPath); }
构建HostingEnvironment对象,从配置中获取key为applicationName、environment的应用名称和环境名称,key为contentRoot应用路径
CreateHostBuilderContext方法实现
private void CreateHostBuilderContext() { _hostBuilderContext = new HostBuilderContext(Properties) { HostingEnvironment = _hostingEnvironment, Configuration = _hostConfiguration }; }
HostBuilderContext宿主上下文,保存HostingEnvironment、Configuration和宿主的一些自定义属性
BuildAppConfiguration的方法实现
private void BuildAppConfiguration() { var configBuilder = new ConfigurationBuilder() .SetBasePath(_hostingEnvironment.ContentRootPath) .AddConfiguration(_hostConfiguration, shouldDisposeConfiguration: true); foreach (var buildAction in _configureAppConfigActions) { buildAction(_hostBuilderContext, configBuilder); } _appConfiguration = configBuilder.Build(); _hostBuilderContext.Configuration = _appConfiguration; }
重新构建ConfigurationBuilder,并合并之前的_hostConfiguration,调用_configureAppConfigActions列表初始化应用配置
CreateServiceProvider方法的实现
private void CreateServiceProvider() { var services = new ServiceCollection(); #pragma warning disable CS0618 // Type or member is obsolete services.AddSingleton<IHostingEnvironment>(_hostingEnvironment); #pragma warning restore CS0618 // Type or member is obsolete services.AddSingleton<IHostEnvironment>(_hostingEnvironment); services.AddSingleton(_hostBuilderContext); // register configuration as factory to make it dispose with the service provider services.AddSingleton(_ => _appConfiguration); #pragma warning disable CS0618 // Type or member is obsolete services.AddSingleton<IApplicationLifetime>(s => (IApplicationLifetime)s.GetService<IHostApplicationLifetime>()); #pragma warning restore CS0618 // Type or member is obsolete services.AddSingleton<IHostApplicationLifetime, ApplicationLifetime>(); services.AddSingleton<IHostLifetime, ConsoleLifetime>(); services.AddSingleton<IHost, Internal.Host>(); services.AddOptions(); services.AddLogging(); foreach (var configureServicesAction in _configureServicesActions) { configureServicesAction(_hostBuilderContext, services); } var containerBuilder = _serviceProviderFactory.CreateBuilder(services); foreach (var containerAction in _configureContainerActions) { containerAction.ConfigureContainer(_hostBuilderContext, containerBuilder); } _appServices = _serviceProviderFactory.CreateServiceProvider(containerBuilder); if (_appServices == null) { throw new InvalidOperationException($"The IServiceProviderFactory returned a null IServiceProvider."); } // resolve configuration explicitly once to mark it as resolved within the // service provider, ensuring it will be properly disposed with the provider _ = _appServices.GetService<IConfiguration>(); }
方法的第一行创建了一个服务容器,并添加IHostingEnvironment、IHostEnvironment、HostBuilderContext、IConfiguration、IHostApplicationLifetime、IHostLifetime等服务
最后注册IHost,IHost的默认实现是一个内部类Host,下一章再介绍
调用_configureServicesActions列表把其他服务注册进来
看下IServiceFactoryAdapter和IServiceProviderFactory<TContainerBuilder>
internal interface IServiceFactoryAdapter { object CreateBuilder(IServiceCollection services); IServiceProvider CreateServiceProvider(object containerBuilder); }
public interface IServiceProviderFactory<TContainerBuilder> { /// <summary> /// Creates a container builder from an <see cref="IServiceCollection"/>. /// </summary> /// <param name="services">The collection of services</param> /// <returns>A container builder that can be used to create an <see cref="IServiceProvider"/>.</returns> TContainerBuilder CreateBuilder(IServiceCollection services); /// <summary> /// Creates an <see cref="IServiceProvider"/> from the container builder. /// </summary> /// <param name="containerBuilder">The container builder</param> /// <returns>An <see cref="IServiceProvider"/></returns> IServiceProvider CreateServiceProvider(TContainerBuilder containerBuilder); }
CreateBuilder方法创建一个依赖注入容器,CreateServiceProvider方法根据CreateBuilder创建IServiceProvider
IServiceFactoryAdapter的默认实现
internal class ServiceFactoryAdapter<TContainerBuilder> : IServiceFactoryAdapter { private IServiceProviderFactory<TContainerBuilder> _serviceProviderFactory; private readonly Func<HostBuilderContext> _contextResolver; private Func<HostBuilderContext, IServiceProviderFactory<TContainerBuilder>> _factoryResolver; public ServiceFactoryAdapter(IServiceProviderFactory<TContainerBuilder> serviceProviderFactory) { _serviceProviderFactory = serviceProviderFactory ?? throw new ArgumentNullException(nameof(serviceProviderFactory)); } public ServiceFactoryAdapter(Func<HostBuilderContext> contextResolver, Func<HostBuilderContext, IServiceProviderFactory<TContainerBuilder>> factoryResolver) { _contextResolver = contextResolver ?? throw new ArgumentNullException(nameof(contextResolver)); _factoryResolver = factoryResolver ?? throw new ArgumentNullException(nameof(factoryResolver)); } public object CreateBuilder(IServiceCollection services) { if (_serviceProviderFactory == null) { _serviceProviderFactory = _factoryResolver(_contextResolver()); if (_serviceProviderFactory == null) { throw new InvalidOperationException("The resolver returned a null IServiceProviderFactory"); } } return _serviceProviderFactory.CreateBuilder(services); } public IServiceProvider CreateServiceProvider(object containerBuilder) { if (_serviceProviderFactory == null) { throw new InvalidOperationException("CreateBuilder must be called before CreateServiceProvider"); } return _serviceProviderFactory.CreateServiceProvider((TContainerBuilder)containerBuilder); } }
IServiceProviderFactory<TContainerBuilder>的默认实现
/// <summary> /// Default implementation of <see cref="IServiceProviderFactory{TContainerBuilder}"/>. /// </summary> public class DefaultServiceProviderFactory : IServiceProviderFactory<IServiceCollection> { private readonly ServiceProviderOptions _options; /// <summary> /// Initializes a new instance of the <see cref="DefaultServiceProviderFactory"/> class /// with default options. /// </summary> /// <seealso cref="ServiceProviderOptions.Default"/> public DefaultServiceProviderFactory() : this(ServiceProviderOptions.Default) { } /// <summary> /// Initializes a new instance of the <see cref="DefaultServiceProviderFactory"/> class /// with the specified <paramref name="options"/>. /// </summary> /// <param name="options">The options to use for this instance.</param> public DefaultServiceProviderFactory(ServiceProviderOptions options) { if (options == null) { throw new ArgumentNullException(nameof(options)); } _options = options; } /// <inheritdoc /> public IServiceCollection CreateBuilder(IServiceCollection services) { return services; } /// <inheritdoc /> public IServiceProvider CreateServiceProvider(IServiceCollection containerBuilder) { return containerBuilder.BuildServiceProvider(_options); } }
最后看下Build()方法的返回值
return _appServices.GetRequiredService<IHost>();
可以看到是在服务容器中解析出IHost出来的
以上就是IHostBuilder创建IHost的过程,下篇再看下IHost的具体实现