一个应用程序总有一个入口文件,是应用启动代码开始执行的地方,这里往往也会涉及到应用的各种配置。当我们接触到一个新框架的时候,可以从入口文件入手,了解入口文件,能够帮助我们更好地理解应用的相关配置以及应用的工作方式。
.NET Core 应用的入口文件是 Program.cs,这里是应用启动的地方。在 .NET 6 之前的版本,Program.cs 文件是下面这样的,这是创建一个 Web 项目时的默认代码。
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
其中 Main 方法就是应用启动的入口。可以看到在应用启动的时候,通过 建造者模式 创建了一个主机,并进行了相关的配置,最后将其运行起来。
从代码中可以看到,在对主机进行配置的时候,使用到了 Startup 类,在 .NET 6 之前的版本,Startup 类承担应用的启动任务,是应用配置的主要地方。
Startup 类的基本结构包含以下两个个关键函数。
ConfigureServices 方法
○ 该方法是可选的
○ 该方法用于添加服务到 DI 容器中
○ 该方法在 Configure 方法之前被调用
○ 该方法要么无参数,要么只能有一个参数且类型必须为 IServiceCollection
○ 该方法内的代码大多是形如 Add{Service} 的扩展方法
Configure方法
○ 该方法是必须的
○ 该方法用于配置 HTTP 请求管道,通过向管道添加中间件,应用不同的响应方式。
○ 该方法在 ConfigureServices 方法之后被调用
○ 该方法中的参数可以接受任何已注入到 DI 容器中的服务
○ 该方法内的代码大多是形如 Use{Middleware} 的扩展方法
○ 该方法内中间件的注册顺序与代码的书写顺序是一致的,先注册的先执行,后注册的后执行
另外还有构造函数,当使用通用主机时,Startup 构造函数支持注入以下三种服务类型,在 Startup 类中全局进行使用:
○ IConfiguration
○ IWebHostEnvironment
○ IHostEnvironment
所谓缺省 Startup,就是应用启动配置不用 Startup 类,直接在 ConfigureWebHostDefaults 中进行配置。
publicstaticIHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
// ConfigureServices 可以调用多次,最终会将结果聚合
webBuilder.ConfigureServices(services =>
{
})
// Configure 如果调用多次,则只有最后一次生效.
Configure(app =>
{
// Configure调用之前,ConfigureServices已经调用,容器对象已经生成,所以这里可以通过容器直接解析需要的对象
var env = app.ApplicationServices.GetRequiredService<IWebHostEnvironment>();
});
});
这里记一些最基本的知识点,Startup 类还有挺多的知识点,比如 Startup 类的多环境适配、通过 IStartupFilter 对 Startup 进行扩展,通过 HostingStartup 特性和 IHostingStartup 接口使用使用承载启动程序集,在应用启动时从外部程序集向应用添加增强功能等。相关的介绍可以参考以下文章: 理解ASP.NET Core - Startup 。这些功能介绍本来想自己写的,但是意外发现了一篇好文,内容已经非常详细了,也就不再重复去写了,在这里引用一下。
自从 .NET 6 开始,微软对应用的入口文件进行了调整,移除了 Main 方法和 Startup 文件,使用顶级语句的写法,将应用初始化的相关配置和操作全部集中在 Program.cs 文件中,如下:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseAuthorization();
app.MapControllers();
app.Run();
关于顶级语句语法的规范,大家可以通过官方文档了解一下:顶级语句。这种改变怎么说呢,我自己是挺不习惯的,虽然这种方式更加简洁,但是过于简洁也容易让人一脸懵,还是觉得之前的Startup文件的方式根据逻辑清晰一点,也更能做到关注点分离。
不过呢,总的来说改变也不大。之前能够在 Startup 中拿到的东西,在现在的入口文件中依旧可以拿到。
以下是 WebApplicationBuilder 对象 builder 张包含的几个关键实例
// builder 中可以获取到的几个关键实例
// 依赖注入容器
IServiceCollection service = builder.Services;
// 配置
IConfiguration configuration = builder.Configuration;
// 日志
ILoggingBuilder loggingBuilder = builder.Logging;
// 主机
IHostBuilder host = builder.Host;
IWebHostBuilder webHost = builder.WebHost;
// 环境
IWebHostEnvironment env = builder.Environment;
现在的依赖注入配置,直接通过 builder.services 进行配置即可
// 依赖注入,相当于 Startup 中的ConfigureService方法
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
日志驱动配置:
// 日志提供程序配置,相当于之前主机中的 hostBuilder.ConfigureLogging
builder.Logging.AddConsole().AddDebug();
以下是 WebApplication 对象 app 中包含的几个关键实例
// app 中包含的几个关键实例
// 环境
IWebHostEnvironment enviroment = app.Environment;
// 配置
IConfiguration config = app.Configuration;
// 应用生命周期
IHostApplicationLifetime lifetime = app.Lifetime;
// 日志记录器
ILogger logger = app.Logger;
// 容器解析器
IServiceProvider serviceProvider = app.Services;
在执行完成 builder.Build(); 之后,应用已经初始化了依赖注入容器,所以我们可以通过 app.services获取我们需要的实例。
// 通过容器获取实例
var conf = app.Services.GetRequiredService<IConfiguration>();
当然,在 builder.Build(); 再通过 builder.services 往容器中配置依赖注入关系是没有用的了,会抛出无效操作异常,因为容器已经创建,无法再修改。
根据顶级语句语法,顶级语句文件中存在隐式 using 指令, 但如果我们需要在 Program.cs 文件中额外引入一些命名空间也是可以的,using 语句需要在文件的最前面,也可以定义方法或者类,只不过需要在顶级语句的后面,也可以使用异步方法。
参考文章:
ASP.NET CORE 5.0 — 应用启动
顶级语句
理解ASP.NET Core - Startup
ASP.NET Core 系列总结:
下一篇:ASP.NET CORE — 请求管道与中间件