netcore优势
- 优秀开发模式
- 性能/稳定
- IOC容器本身就是个对象
- 注册类型/功能解析/某个类所依赖的类的对象
程序启动流程
- 创建主机与主机配置
- 依赖注入、服务、管道、中间件、应用配置、多环境、日志、路由、异常处理、静态文件、部署
主机是什么?
Host:主机实际就是一个封装了应用资源的对象。
主机的作用是什么?
主机负责应用程序的启动、生命周期的管理、配置服务和请求处理管道等
详细启动流程
可以看出WebApi的启动,其实就是控制台程序启动
1. Host.CreateDefaultBuilder方法
public static IHostBuilder CreateDefaultBuilder(string[] args)
{
// 实例化一个HostBuilder
var builder = new HostBuilder();
// 设置根目录
builder.UseContentRoot(Directory.GetCurrentDirectory());
// 设置 Host相关配置的配置源
builder.ConfigureHostConfiguration(config =>
{
// 从环境变量中获取,前缀名为DOTNET_
config.AddEnvironmentVariables(prefix: "DOTNET_");
// 如果命令行中有参数,可从命令行中读取
if (args != null)
{
config.AddCommandLine(args);
}
});
// 设置应用程序配置的配置源
builder.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() && !string.IsNullOrEmpty(env.ApplicationName))
{
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) =>
{
//判断操作系统
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
// 如果是Windows系统,配置对应的显示级别
// IMPORTANT: This needs to be added *before* configuration is loaded, this lets
// the defaults be overridden by the configuration.
if (isWindows)
{
// Default the EventLogLoggerProvider to warning or above
logging.AddFilter<EventLogLoggerProvider>(level => level >= LogLevel.Warning);
}
//获取配置文件中Logging 段相关的配置信息添加到日志配置中
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
// 在控制台输出,所以启动程序的时候就看见输出日志
logging.AddConsole();
// 在Debug窗口输出
logging.AddDebug();
logging.AddEventSourceLogger();
// 如果是Windows系统,可以在系统日志中输出日志
if (isWindows)
{
// Add the EventLogLoggerProvider on windows machines
logging.AddEventLog();
}
})//使用默认的依赖注入容器
.UseDefaultServiceProvider((context, options) =>
{
var isDevelopment = context.HostingEnvironment.IsDevelopment();
options.ValidateScopes = isDevelopment;
options.ValidateOnBuild = isDevelopment;
});
return builder;
}
2. ConfigureWebHostDefaults 方法
public static IHostBuilder ConfigureWebHostDefaults(this IHostBuilder builder, Action<IWebHostBuilder> configure)
{
return builder.ConfigureWebHost(webHostBuilder =>
{
//指定是用的服务器及集成一些默认管道
WebHost.ConfigureWebDefaults(webHostBuilder);
// 调用传入的委托,这里是外部指定Startup类做服务注册和管道配置
configure(webHostBuilder);
});
}
2.1 WebHost.ConfigureWebDefaults方法
internal static void ConfigureWebDefaults(IWebHostBuilder builder)
{
builder.ConfigureAppConfiguration((ctx, cb) =>
{
if (ctx.HostingEnvironment.IsDevelopment())
{
//静态文件环境的配置启用
StaticWebAssetsLoader.UseStaticWebAssets(ctx.HostingEnvironment, ctx.Configuration);
}
});
// 指定Kestrel作为默认的Web服务器
builder.UseKestrel((builderContext, options) =>
{
options.Configure(builderContext.Configuration.GetSection("Kestrel"));
})// 服务中间的注册,包含路的中间件注册
.ConfigureServices((hostingContext, services) =>
{
// 针对配置节点AllowedHosts改变时的回调
// Fallback
services.PostConfigure<HostFilteringOptions>(options =>
{
if (options.AllowedHosts == null || options.AllowedHosts.Count == 0)
{
// "AllowedHosts": "localhost;127.0.0.1;[::1]"
var hosts = hostingContext.Configuration["AllowedHosts"]?.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
// Fall back to "*" to disable.
options.AllowedHosts = (hosts?.Length > 0 ? hosts : new[] { "*" });
}
});
//对应配置改变时触发通知
// Change notification
services.AddSingleton<IOptionsChangeTokenSource<HostFilteringOptions>>(
new ConfigurationChangeTokenSource<HostFilteringOptions>(hostingContext.Configuration));
services.AddTransient<IStartupFilter, HostFilteringStartupFilter>();
if (string.Equals("true", hostingContext.Configuration["ForwardedHeaders_Enabled"], StringComparison.OrdinalIgnoreCase))
{
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
// Only loopback proxies are allowed by default. Clear that restriction because forwarders are
// being enabled by explicit configuration.
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
services.AddTransient<IStartupFilter, ForwardedHeadersStartupFilter>();
}
services.AddRouting();
})//对使用IIS相关中间件
.UseIIS()
.UseIISIntegration();
}
3. Build方法,其实这个方法就是根据之前配置构造出一个IHost对象
public IHost Build()
{
if (_hostBuilt)
{
throw new InvalidOperationException("Build can only be called once.");
}
_hostBuilt = true;
// 执行ConfigureHostConfiguration添加的一系列配置回调方法
BuildHostConfiguration();
// 运行环境相关创建,如ApplicationName、EnvironmentName、ContentRootPath等
CreateHostingEnvironment();
// 构建HostBuilder
CreateHostBuilderContext();
// 执行ConfigureAppConfigureation添加的一系列配置回调方法
BuildAppConfiguration();
// 注入默认服务如:IHost、ILogging等,执行ConfigureServices添加的一系列回调方法
CreateServiceProvider();
return _appServices.GetRequiredService<IHost>();
}
4. Run()方法,开启服务器,之后就可以进行请求
借鉴出处