第二章:项目骨架搭建
好,咱们开始动手了。
这一章,我会带你从零创建一个 ASP.NET Core Web API 项目。别小看这一步,骨架搭得好,后面写代码才舒服。我见过太多项目,一开始图省事,后面改得想哭。
2.1 创建第一个 ASP.NET Core Web API 项目
打开 Visual Studio 2022,或者你用 Rider 也行。我个人习惯用 .NET CLI,因为快,而且跨平台一致。
打开终端,敲下这行命令:
dotnet new webapi -n MyFirstApi
就这么简单。一个名为 MyFirstApi 的项目就生成了。
你可能会问:为什么不用模板里的「带控制器」选项?嗯,这里要注意,新版的 .NET 6+ 默认使用最小 API(Minimal API)。但咱们课程里,我选择用传统的控制器模式。为什么?因为真实企业项目里,控制器模式更常见,也更容易组织代码。
我曾经在一个创业项目里,一开始图新鲜全用最小 API,结果项目一复杂,路由散得到处都是,维护起来那叫一个酸爽。后来还是老老实实改回了控制器。
2.2 项目结构解析
项目创建好了,咱们来看看里面都有啥。打开项目文件夹,你会看到这些:
- Controllers/ —— 控制器放这里
- Program.cs —— 应用程序入口
- appsettings.json —— 配置文件
- Properties/launchSettings.json —— 启动配置
别急着写代码,先搞清楚每个文件是干嘛的。
2.2.1 Program.cs —— 一切从这里开始
这是整个应用的入口。在 .NET 6 之后,它变得非常简洁。你看:
var builder = WebApplication.CreateBuilder(args);
// 注册服务
builder.Services.AddControllers();
var app = builder.Build();
// 配置中间件管道
app.MapControllers();
app.Run();
说白了,就三步:
- 创建 builder —— 准备构建应用
- 注册服务 —— 告诉框架你需要什么
- 构建并运行 —— 启动应用
我记得刚接触 .NET Core 时,看到 Startup.cs 和 Program.cs 分开,觉得好麻烦。后来 .NET 6 把它们合并了,确实清爽很多。但如果你是从 .NET 5 过来的,别慌,后面我会讲 Startup 的兼容写法。
2.2.2 launchSettings.json —— 启动的秘密
这个文件藏在 Properties 文件夹里。很多人忽略它,但它决定了你的项目怎么跑。
{
"profiles": {
"MyFirstApi": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
这里有几个关键点:
- applicationUrl —— 应用监听的地址和端口。默认是 5000/5001
- ASPNETCORE_ENVIRONMENT —— 环境变量。Development 表示开发环境
- launchBrowser —— 启动时是否自动打开浏览器
我曾经踩过一个坑:把 applicationUrl 改成了 8080,结果忘了改回来,部署到服务器上端口冲突,排查了半天。所以,这个文件虽然小,但改的时候要小心。
2.3 依赖注入初体验
依赖注入(DI)是 ASP.NET Core 的核心。说白了,就是「我要什么,你给我什么」,不用我自己 new。
举个例子。假设你有一个日志服务:
public interface ILoggerService
{
void Log(string message);
}
public class ConsoleLoggerService : ILoggerService
{
public void Log(string message)
{
Console.WriteLine($"[{DateTime.Now}] {message}");
}
}
在 Program.cs 里注册它:
builder.Services.AddScoped<ILoggerService, ConsoleLoggerService>();
然后在控制器里直接用:
[ApiController]
[Route("api/[controller]")]
public class WeatherController : ControllerBase
{
private readonly ILoggerService _logger;
public WeatherController(ILoggerService logger)
{
_logger = logger;
}
[HttpGet]
public IActionResult Get()
{
_logger.Log("有人调用了 Get 方法");
return Ok(new { Message = "Hello World" });
}
}
看到没?控制器不需要知道具体是哪个日志实现。你只需要在构造函数里声明「我需要一个 ILoggerService」,框架会自动给你注入。
这就是依赖注入的魅力——解耦。你想想看,如果以后想换成文件日志,只需要改注册那一行代码,控制器完全不用动。
| 生命周期 | 说明 | 适用场景 |
|---|---|---|
| AddTransient | 每次请求都创建新实例 | 轻量级、无状态服务 |
| AddScoped | 每个 HTTP 请求内共享同一个实例 | 数据库上下文、业务服务 |
| AddSingleton | 整个应用生命周期内只有一个实例 | 配置、缓存、日志 |
我在项目中遇到过一个问题:把一个 Scoped 服务注入到了 Singleton 服务里。结果呢?Singleton 一直持有同一个 Scoped 实例,导致数据错乱。排查了好久才发现是生命周期搞错了。
所以,记住一个原则:不要注入生命周期比自己短的服务。Singleton 里不要注入 Scoped 或 Transient,Scoped 里不要注入 Transient(除非你知道自己在做什么)。
2.4 本章小结
这一章,我们做了三件事:
- 用 CLI 创建了一个 Web API 项目
- 搞清楚了 Program.cs 和 launchSettings.json 的作用
- 体验了依赖注入的基本用法
骨架已经搭好了。下一章,咱们开始往里面填肉——写真正的业务代码。
对了,如果你在创建项目时遇到问题,检查一下 .NET SDK 版本。用 dotnet --version 看看,至少要是 6.0 以上。
dotnet run,确保能正常启动。别等到写了一大堆代码才发现环境有问题。
好,这一章就到这儿。有问题随时问,咱们下章见。