.NET 6 Minimal APIs 入门解析:轻量级 Web API 的现代化实现
什么是 .NET 6 Minimal APIs?
.NET 6 作为首个长期支持(LTS)版本,带来了显著的性能提升和开发体验优化。其中最引人注目的新特性之一是 Minimal APIs —— 一种极简方式构建 HTTP 接口的技术,特别适用于微服务、小型应用或快速原型开发。
它通过去除传统 ASP.NET Core 项目中常见的冗余结构(如 Startup.cs、Controller 类等),让开发者用极少代码即可启动一个功能完整的 Web 服务。这种模式借鉴了 Node.js + Express 的简洁风格,同时深度集成 C# 和 .NET 生态的优势。
初识 Minimal APIs:四行代码的 Web 服务
以下是一个典型的 Minimal API 示例:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello, World!");
app.Run();
这段代码创建了一个监听默认端口的 Web 应用,并在根路径返回字符串。尽管只有四行,但它已经是一个可运行的 HTTP 服务。无需显式定义 Main 方法,也不需要命名空间引用——这得益于 .NET 6 的两项关键改进。
背后的技术支撑
上述代码之所以能如此简洁,依赖于 .NET 6 引入的两个核心机制:
- 顶级语句(Top-level Statements):C# 10 允许程序入口直接写在文件顶层,编译器自动将其包裹进
Program.Main中,省去模板代码。 - 隐式全局 using 指令:项目文件中设置
<ImplicitUsings>enable</ImplicitUsings>后,常用命名空间(如System,Microsoft.AspNetCore.Builder等)会被自动引入,避免重复声明。
生成过程中,SDK 会自动生成一个名为 [ProjectName].GlobalUsings.g.cs 的隐藏文件,集中管理所有全局引用。若需关闭此功能,只需将配置改为 disable 即可。
实战:使用 Minimal APIs 实现订单管理系统
接下来我们构建一个简单的订单 CRUD 接口来展示其完整能力。
1. 定义模型与服务接口
首先创建订单实体类:
public class Order
{
public int Id { get; set; }
public decimal Amount { get; set; }
public string Address { get; set; } = string.Empty;
public int Status { get; set; }
}
接着定义数据访问契约:
public interface IOrderRepository
{
Order? GetById(int id);
void Add(Order order);
void Update(Order order);
void Remove(int id);
}
然后提供基于内存的实现:
public class InMemoryOrderRepository : IOrderRepository
{
private static readonly List<Order> _orders = new();
public Order? GetById(int id) => _orders.FirstOrDefault(o => o.Id == id);
public void Add(Order order) => _orders.Add(order);
public void Update(Order order)
{
var existing = GetById(order.Id);
if (existing != null)
{
_orders.Remove(existing);
_orders.Add(order);
}
}
public void Remove(int id)
{
var order = GetById(id);
if (order is not null) _orders.Remove(order);
}
}
2. 在 Program 中注册服务并映射路由
现在回到主程序文件,注册依赖并添加接口:
using NET6;
var builder = WebApplication.CreateBuilder(args);
// 注册仓储服务为作用域生命周期
builder.Services.AddScoped<IOrderRepository, InMemoryOrderRepository>();
var app = builder.Build();
// 根路径健康检查
app.MapGet("/", () => "API is running");
// 创建订单 POST /order
app.MapPost("/order", (Order input, IOrderRepository repo) =>
{
repo.Add(input);
return Results.Created($"/order/{input.Id}", input);
});
// 查询订单 GET /order/{id}
app.MapGet("/order/{id:int}", (int id, IOrderRepository repo) =>
{
var order = repo.GetById(id);
return order is not null ? Results.Ok(order) : Results.NotFound();
});
// 更新订单 PUT /order
app.MapPut("/order", (Order input, IOrderRepository repo) =>
{
var existing = repo.GetById(input.Id);
if (existing is null) return Results.NotFound();
repo.Update(input);
return Results.NoContent();
});
// 删除订单 DELETE /order/{id}
app.MapDelete("/order/{id:int}", (int id, IOrderRepository repo) =>
{
repo.Remove(id);
return Results.NoContent();
});
app.Run();
注意每个端点处理函数如何直接接收服务实例(如 IOrderRepository)——这是 Minimal APIs 内建的依赖注入支持,框架会自动解析所需服务。
3. 测试 API 接口
运行命令启动服务:
dotnet run
使用 Postman 或 curl 进行测试。例如提交新订单时,应将 JSON 数据放在请求体中:
POST http://localhost:5000/order
Content-Type: application/json
{
"Id": 1,
"Amount": 99.99,
"Address": "北京市朝阳区",
"Status": 1
}
常见误区是误将参数放在 Headers 或 Query String 中,导致模型绑定失败。正确做法始终是通过 Raw Body 发送 JSON 数据。
从 Minimal 到 MVC:平滑演进路径
虽然 Minimal APIs 适合简单场景,但当业务复杂度上升时,仍可无缝迁移到传统的控制器模式。你可以在同一个项目中混合使用两者,逐步重构而无需重写整个应用。
总结来说,Minimal APIs 并非取代 MVC,而是提供了一条"低门槛进入、高弹性扩展"的开发路径,尤其适合云原生环境下的轻量服务部署。