本节将分析
代码。
- WebHost.CreateDefaultBuilder(args).UseStartup<Startup>().Build();
源代码参考.NET Core 2.0.0
该方法为WebHost类的静态方法,内部创建1个WebHostBuilder。
- public static IWebHostBuilder CreateDefaultBuilder(string[] args)
- {
- var builder = new WebHostBuilder()
- .UseKestrel()
- .UseContentRoot(Directory.GetCurrentDirectory())
- .ConfigureAppConfiguration((hostingContext, config) =>
- {
- var env = hostingContext.HostingEnvironment;
- config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
- .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
- if (env.IsDevelopment())
- {
- var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
- if (appAssembly != null)
- {
- config.AddUserSecrets(appAssembly, optional: true);
- }
- }
- config.AddEnvironmentVariables();
- if (args != null)
- {
- config.AddCommandLine(args);
- }
- })
- .ConfigureLogging((hostingContext, logging) =>
- {
- logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
- logging.AddConsole();
- logging.AddDebug();
- })
- .UseIISIntegration()
- .UseDefaultServiceProvider((context, options) =>
- {
- options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
- });
- return builder;
- }
在
方法中,注册了3个服务到
- UseKestrel()
字段上。(以供后续注册)
- List<Action<WebHostBuilderContext, IServiceCollection>>
- public static IWebHostBuilder UseKestrel(this IWebHostBuilder hostBuilder) {
- return hostBuilder.ConfigureServices((Action < IServiceCollection > )(services = >{
- services.AddSingleton < ITransportFactory,
- LibuvTransportFactory > ();
- services.AddTransient < IConfigureOptions < KestrelServerOptions > ,
- KestrelServerOptionsSetup > ();
- services.AddSingleton < IServer,
- KestrelServer > ();
- }));
- }
- public IWebHostBuilder ConfigureServices(Action < WebHostBuilderContext, IServiceCollection > configureServices) {
- this._configureServicesDelegates.Add((_, services) = >configureServices(services));
- return (IWebHostBuilder) this;
- }
UseContentRoot方法则是添加到IConfiguration字段上,这个字段在构造函数初始化
- this._config = (IConfiguration) new ConfigurationBuilder().AddEnvironmentVariables("ASPNETCORE_").Build();
- public static IWebHostBuilder UseContentRoot(this IWebHostBuilder hostBuilder, string contentRoot)
- {
- if (contentRoot == null)
- throw new ArgumentNullException(nameof (contentRoot));
- return hostBuilder.UseSetting(WebHostDefaults.ContentRootKey, contentRoot);
- }
- public IWebHostBuilder UseSetting(string key, string value)
- {
- this._config[key] = value;
- return (IWebHostBuilder) this;
- }
ConfigureAppConfiguration方法是添加到
字段上 在外部添加了
- List<Action<WebHostBuilderContext, IConfigurationBuilder>>
、
- AddJsonFile("appsettings.json")
- AddJsonFile(string.Format("appsettings.{0}.json", (object) hostingEnvironment.EnvironmentName))
- AddEnvironmentVariables()
- AddCommandLine(args)
- public IWebHostBuilder ConfigureAppConfiguration(Action<WebHostBuilderContext, IConfigurationBuilder> configureDelegate)
- {
- this._configureAppConfigurationBuilderDelegates.Add(configureDelegate);
- return (IWebHostBuilder) this;
- }
ConfigureLogging注册Log到ServiceCollection上
在外部添加了3个ILoggerProvider
- logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
- logging.AddConsole();
- logging.AddDebug();
- public static IWebHostBuilder ConfigureLogging(this IWebHostBuilder hostBuilder, Action<WebHostBuilderContext, ILoggingBuilder> configureLogging)
- {
- return hostBuilder.ConfigureServices((context, services) => services.AddLogging(builder => configureLogging(context, builder));
- }
- public IWebHostBuilder ConfigureServices(Action<WebHostBuilderContext, IServiceCollection> configureServices)
- {
- this._configureServicesDelegates.Add(configureServices);
- return (IWebHostBuilder) this;
- }
UseDefaultServiceProvider配置和替换服务
- var options = new ServiceProviderOptions { ValidateScopes = context.HostingEnvironment.IsDevelopment()};
- services.Replace(ServiceDescriptor.Singleton<IServiceProviderFactory<IServiceCollection>>((IServiceProviderFactory<IServiceCollection>) new DefaultServiceProviderFactory(options)));
UseStartup相当于注册了一个IStartup服务。
- public static IWebHostBuilder UseStartup(this IWebHostBuilder hostBuilder, Type startupType)
- {
- string name = startupType.GetTypeInfo().Assembly.GetName().Name;
- return hostBuilder.UseSetting(WebHostDefaults.ApplicationKey, name).ConfigureServices((Action<IServiceCollection>) (services =>
- {
- if (typeof (IStartup).GetTypeInfo().IsAssignableFrom(startupType.GetTypeInfo()))
- ServiceCollectionServiceExtensions.AddSingleton(services, typeof (IStartup), startupType);
- else
- ServiceCollectionServiceExtensions.AddSingleton(services, typeof (IStartup), (Func<IServiceProvider, object>) (sp =>
- {
- IHostingEnvironment requiredService = sp.GetRequiredService<IHostingEnvironment>();
- return (object) new ConventionBasedStartup(StartupLoader.LoadMethods(sp, startupType, requiredService.EnvironmentName));
- }));
- }));
- }
根据Startup是否继承IStartup,来决定注册的方式。未继承的时候,会使用
来封装自定义的Startup。
- ConventionBasedStartup
Build方法是WebHostBuilder最终的目的,将构造一个WebHost返回。
同时初始化WebHost对象,WebHostBuilder.Build代码:
- public IWebHost Build()
- {
- var hostingServices = BuildCommonServices(out var hostingStartupErrors);
- var applicationServices = hostingServices.Clone();
- var hostingServiceProvider = hostingServices.BuildServiceProvider();
- AddApplicationServices(applicationServices, hostingServiceProvider);
- var host = new WebHost(
- applicationServices,
- hostingServiceProvider,
- _options,
- _config,
- hostingStartupErrors);
- host.Initialize();
- return host;
- }
在Build方法中,BuildCommonServices最为重要,将构造第一个ServiceCollection。这里我们称为
。 将包含hostEnv、Config、ApplicationBuilder、Logging、StartupFilter、Startup、Server。参考BuildCommonServices
- hostingServices
- private IServiceCollection BuildCommonServices(out AggregateException hostingStartupErrors)
- {
- if (!this._options.PreventHostingStartup)
- {
- foreach (string hostingStartupAssembly in (IEnumerable<string>) this._options.HostingStartupAssemblies)
- {
- foreach (HostingStartupAttribute customAttribute in Assembly.Load(new AssemblyName(hostingStartupAssembly)).GetCustomAttributes<HostingStartupAttribute>())
- ((IHostingStartup) Activator.CreateInstance(customAttribute.HostingStartupType)).Configure((IWebHostBuilder) this);
- }
- }
- ServiceCollection services = new ServiceCollection();
- // hostEnv
- _hostingEnvironment.Initialize(this._options.ApplicationName, this.ResolveContentRootPath(this._options.ContentRootPath, AppContext.BaseDirectory), this._options);
- services.AddSingleton<IHostingEnvironment>(this._hostingEnvironment);
- // config
- IConfigurationBuilder configurationBuilder = new ConfigurationBuilder().SetBasePath(this._hostingEnvironment.ContentRootPath).AddInMemoryCollection(this._config.AsEnumerable());
- foreach (Action<WebHostBuilderContext, IConfigurationBuilder> configurationBuilderDelegate in this._configureAppConfigurationBuilderDelegates)
- configurationBuilderDelegate(this._context, configurationBuilder);
- IConfigurationRoot configurationRoot = configurationBuilder.Build();
- services.AddSingleton<IConfiguration>((IConfiguration) configurationRoot);
- services.AddOptions();
- // application
- services.AddTransient<IApplicationBuilderFactory, ApplicationBuilderFactory>();
- services.AddTransient<IHttpContextFactory, HttpContextFactory>();
- services.AddScoped<IMiddlewareFactory, MiddlewareFactory>();
- // log
- services.AddLogging();
- services.AddTransient<IStartupFilter, AutoRequestServicesStartupFilter>();
- services.AddTransient<IServiceProviderFactory<IServiceCollection>, DefaultServiceProviderFactory>();
- // 配置的StartupType
- if (!string.IsNullOrEmpty(this._options.StartupAssembly))
- {
- Type startupType = StartupLoader.FindStartupType(this._options.StartupAssembly, this._hostingEnvironment.EnvironmentName);
- if (typeof (IStartup).GetTypeInfo().IsAssignableFrom(startupType.GetTypeInfo()))
- ServiceCollectionServiceExtensions.AddSingleton(services, typeof (IStartup), startupType);
- else
- ServiceCollectionServiceExtensions.AddSingleton(services, typeof (IStartup), new ConventionBasedStartup(StartupLoader.LoadMethods(startupType)));
- }
- // UseStartup、UseKestrel、ConfigureLogging
- foreach (Action<WebHostBuilderContext, IServiceCollection> servicesDelegate in this._configureServicesDelegates)
- servicesDelegate(this._context, (IServiceCollection) services);
- return (IServiceCollection) services;
- }
当
创建完成后,会马上拷贝一份
- hostingServices
提供给WebHost使用,同时创建第一个ServiceProvider
- applicationServices
。
- hostingServiceProvider
host.Initialize()该方法则是初始化WebHost
(微软的内部字段命名,感觉不太规范);
- _applicationServices
。
- RequestDelegate
- public void Initialize()
- {
- _startup = _hostingServiceProvider.GetService<IStartup>();
- _applicationServices = _startup.ConfigureServices(_applicationServiceCollection);
- EnsureServer();
- var builderFactory = _applicationServices.GetRequiredService<IApplicationBuilderFactory>();
- var builder = builderFactory.CreateBuilder(Server.Features);
- builder.ApplicationServices = _applicationServices;
- var startupFilters = _applicationServices.GetService<IEnumerable<IStartupFilter>>();
- Action<IApplicationBuilder> configure = _startup.Configure;
- foreach (var filter in startupFilters.Reverse())
- {
- configure = filter.Configure(configure);
- }
- configure(builder);
- this._application = builder.Build(); // RequestDelegate
- }
创建完 WebHost 之后,便调用它的 Run 方法,而 Run 方法会去调用 WebHost 的 StartAsync 方法
- public static void Run(this IWebHost host)
- {
- await host.RunAsync(cts.Token, "Application started. Press Ctrl+C to shut down.");
- }
- private static async Task RunAsync(this IWebHost host, CancellationToken token, string shutdownMessage)
- {
- await host.StartAsync(token);
- var hostingEnvironment = host.Services.GetService<IHostingEnvironment>();
- Console.WriteLine($"Hosting environment: {hostingEnvironment.EnvironmentName}");
- Console.WriteLine($"Content root path: {hostingEnvironment.ContentRootPath}");
- var serverAddresses = host.ServerFeatures.Get<IServerAddressesFeature>()?.Addresses;
- if (serverAddresses != null)
- foreach (var address in serverAddresses)
- Console.WriteLine($"Now listening on: {address}");
- if (!string.IsNullOrEmpty(shutdownMessage))
- Console.WriteLine(shutdownMessage);
- }
- public virtual async Task StartAsync(CancellationToken cancellationToken = default (CancellationToken))
- {
- Initialize();
- _applicationLifetime = _applicationServices.GetRequiredService<IApplicationLifetime>() as ApplicationLifetime;
- _hostedServiceExecutor = _applicationServices.GetRequiredService<HostedServiceExecutor>();
- var httpContextFactory = _applicationServices.GetRequiredService<IHttpContextFactory>();
- var hostingApp = new HostingApplication(_application, _logger, diagnosticSource, httpContextFactory);
- await Server.StartAsync(hostingApp, cancellationToken).ConfigureAwait(false);
- _applicationLifetime?.NotifyStarted();
- await _hostedServiceExecutor.StartAsync(cancellationToken).ConfigureAwait(false);
- }
(WebHostBuilder) 和
- hostingServices
(WebHost)。区别是_applicationServices中比hostingServices多处Startup方法注册的服务。
- _applicationServices
生成前,Configure在
- _applicationServices
生成后。
- _applicationServices
,使用在WebHost的
- UseKestrel
方法
- Run
- new WebHostBuilder().UseKestrel() // 使用Kestrel服务器
- .UseContentRoot(Directory.GetCurrentDirectory()) // 配置根目录 会在ConfigurationBuilder、 IHostingEnvironment(后续其他中间件) 和 WebHostOptions(WebHost)用到。
- .ConfigureAppConfiguration((context, builder) = >builder.AddJsonFile("appsetting.json", true, true)) // 添加配置源
- .ConfigureLogging(builder = >builder.AddConsole()) // 添加日志适配器
- .UseStartup < Startup > () // 选择Startup
- .Build().Run(); // 生成WebHost 并 启动
本文链接:http://neverc.cnblogs.com/p/7988226.html
来源: http://www.cnblogs.com/neverc/p/7988226.html