Minimal API 不走 MVC 管道,必须使用 .NET 6+、正确顺序注册路由(builder.Build() 后、app.Run() 前)、参数绑定依赖名称与类型而非特性、返回值须用 Results.() 或 TypedResults.()。

Minimal API 不是“简化版 MVC”,它压根不走 MVC 管道,写错顺序、用错返回值、参数名大小写不对,接口就直接 404 或 400——不是代码没生效,是根本没注册或绑定失败。
目标框架和 SDK 必须是 .NET 6+
MapGet 找不到?IEndpointRouteBuilder 未定义?这不是拼写错误,是项目卡在 .NET 5 或更低版本。Visual Studio 新建时默认可能选“.NET 5 Web API”模板,哪怕你手动改了 .csproj 里的 <TargetFramework>net8.0</TargetFramework>,缓存也会让编译继续走旧路径。
- 运行
dotnet --list-sdks,确认本地装了6.0.x或更高版本(如8.0.100) - 检查
.csproj文件,确保只有一行<TargetFramework>,且值为net6.0、net8.0等单目标,不要写net6.0;net8.0 - 改完立刻执行
dotnet clean && dotnet build,清掉obj/和bin/下的残留
路由注册顺序不能颠倒
app.MapGet 写在 app.Run() 后面,服务能启动,但所有请求一律 404;写在 builder.Build() 前,编译直接报错 “app 未声明”。Minimal API 对初始化链极其敏感,五步缺一不可,且顺序固定:
var builder = WebApplication.CreateBuilder(args);- 服务注册(如
builder.Services.AddDbContext<AppDbContext>()) var app = builder.Build();- 中间件与路由注册(
app.UseHttpsRedirection()必须在app.MapGet()之前) app.Run();
特别注意:app.UseHttpsRedirection() 放在 MapGet 后面,重定向对 API 路由不生效。
参数绑定靠名字和类型,不是靠特性
Minimal API 完全忽略 [FromQuery]、[FromBody]、[FromRoute] 这类特性。它根据参数名是否匹配路由段、类型是否为简单类型,自动决定数据来源:
-
app.MapGet("/user/{id}", (int id) => ...)→id是路径参数,名字必须完全一致(大小写敏感),且类型为int -
app.MapGet("/search", (string q, int page = 1) => ...)→q来自查询字符串?q=abc,page有默认值,可省略 -
app.MapPost("/order", (Order req) => ...)→ 自动尝试 JSON 反序列化,请求头必须含Content-Type: application/json - 发
application/x-www-form-urlencoded却期望绑定到Order?直接返回 400,Minimal API 默认不解析表单
返回值必须用 Results.*() 或 TypedResults.*()
不能直接 return new { ok = true },否则要么编译失败,要么响应体为空或固定 200 + text/plain。所有 HTTP 状态码、响应头、内容类型都得显式控制:
-
Results.Ok(new { Id = 123 })→ 200 + JSON -
Results.Created($"/api/users/{id}", user)→ 201 + Location header + body -
Results.BadRequest("Missing name")→ 400 + 文本 - 想生成准确 OpenAPI 文档、支持单元测试断言?优先用
TypedResults.Ok<User>(user),它返回强类型Ok<User>,而非泛型IResult
最容易被忽略的是:文件上传必须先调用 await Request.ReadFormAsync() 才能访问 Request.Form.Files,否则 Request.Form 为 null;Swagger 要显示可读名称,每个 MapGet 都得链式调用 .WithName("Users_GetById"),否则只显示 Get 这种随机名。


















