文件的伺服
传统 ASP.NET
- 根目录的文件都被伺服
- 某些重要文件不会被伺服
- 黑名单策略
ASP.NET Core
- 只有 wwwroot 被伺服
- 白名单策略
ASP.NET Core Meta Package
项目配置文件里 <PackageReference Include="Microsoft.AspNetCore.App" />
引用的库是一个整合库称为 Meta Package。它没有具体版本号,默认引用电脑上最新的版本。它包括:
- 仅有的几个第三方库:Json.NET,Remotion.Linq 和 IX-Async
- 它们是保证框架功能所必需的
- 所有 ASP.NET Core 团队支持的库,包含第三方依赖项(除上面三个外)的库除外
- 所有 Entity Framework Core 团队支持的库,包含第三方依赖项(除上面三个外)的库除外
WebHost 源码分析
源码地址:https://github.com/aspnet/MetaPackages/blob/master/src/Microsoft.AspNetCore/WebHost.cs
builder.UseKestrel((builderContext, options) =>
{
options.Configure(builderContext.Configuration.GetSection("Kestrel"));
})
.ConfigureServices((hostingContext, services) =>
{
// 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>();
})
.UseIIS()
.UseIISIntegration();
- UseKestel 使用了项目内嵌的 Kestrel 服务器
- UseIIS 使用了外部的 IIS 服务器
- 所以一个 HTTP 请求会先到 IIS,再被中继到 Kestrel,处理后再先 Kestrel 后 IIS 返回
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
- 默认配置加载 appsettings.json
- 也可以根据环境加载不同配置文件
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddConsole();
logging.AddDebug();
logging.AddEventSourceLogger();
}).
配置 logging 时,默认输出到 Console、Debug 和 EventSourceLogger 三个地方。
UseDefaultServiceProvider((context, options) =>
{
options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
});
使用自带的依赖注入容器。
.ConfigureServices((hostingContext, services) =>
{
// 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>();
})
ConfigureServices 主要用来添加一些类型到依赖注入容器中。
WebHost 进行了很多的默认配置,如果你需要修改配置,它的代码很有参考意义。
依赖注入,IoC 容器
依赖注入的生命周期
- Transient:每次被请求都会创建新的实例
- Scoped:每次 Web 请求会创建一个实例
- Singleton:一旦被创建实例,就会一直使用这个实例,直到应用停止
Startup 类的 ConfigureServices 方法里面进行依赖注入配置。
public void ConfigureServices(IServiceCollection services)
{
// 每当有其他类请求 ICinemaService 时,容器都会返回 CinemaMemoryService 的实例
services.AddSingleton<ICinemaService, CinemaMemoryService>();
services.AddSingleton<IMovieService, MovieMemoryService>();
}
依赖注入的好处
- 不用去管生命周期
- 类型之间没有依赖,有利于单元测试
管道与中间件
Startup 类的 Configure 方法里面进行管道和中间件的配置。
管道示意图:
完整 Web 请求的流程:
切换启动配置
可以通过选择项目名,使用 Kestrel 服务器进行调试,而不是默认的 IIS Express。
可以通过项目 Properties 下的 launchSettings.json 修改启动配置。
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:53994",
"sslPort": 44374
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"CoreDemo": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
中间件测试
// 配置 HTTP 请求管道
// 管道:配置我们的 Web 应用如何响应 HTTP 请求
// 管道里面放的东西就是中间件,MVC 就是一个中间件
public void Configure(IApplicationBuilder app, IHostingEnvironment env,ILogger<Startup> logger)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.Use(async (context, next) =>
{
logger.LogInformation("M1 Start");
await context.Response.WriteAsync("Hello World!");
await next();
logger.LogInformation("M1 End");
});
app.Run(async (context) =>
{
logger.LogInformation("M2 Start");
await context.Response.WriteAsync("Another Hello!");
logger.LogInformation("M2 End");
});
}