.NET 10 OpenAPI UI 三剑客:Swashbuckle、NSwag 与 Scalar 实战对比

前言

在 .NET 9 之前,生成 OpenAPI(即 Swagger)文档几乎离不开 Swashbuckle.AspNetCore。它既负责扫描控制器生成 JSON 文档,又顺手提供了那个熟悉的 Swagger UI 界面。然而从 .NET 9 开始,微软将 OpenAPI 文档生成能力 内置进框架(Microsoft.AspNetCore.OpenApi),这彻底改变了三方 UI 工具的定位——它们不再是"文档生成器",而退化(或者说回归)为单纯的 UI 渲染器。

本文基于一个最小演示项目,对比 Swashbuckle、NSwag、Scalar 这三种 UI 工具在 .NET 10 中的现代化集成方式。三个项目业务代码完全一致(都是经典的 WeatherForecast 端点),唯一差异就在于 UI 中间件的接入方式。

一、共同的基础:内置 OpenAPI 文档生成

无论使用哪种 UI,三个项目都使用同一套 .NET 内置 API 来生成 OpenAPI v3 JSON 文档:

// 服务注册
builder.Services.AddOpenApi();

// 路由挂载
app.MapOpenApi();  // 默认暴露在 /openapi/v1.json

这一组合的产出就是一份标准的 OpenAPI v3 JSON,访问地址固定为 /openapi/v1.json。所有三种 UI 工具消费的都是这同一份 JSON——这是理解后续差异的关键前提。

包引用上也只需要这一个:

<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.3" />

二、Swashbuckle:老牌选手的现代用法

2.1 安装

<PackageReference Include="Swashbuckle.AspNetCore" Version="10.2.2" />

2.2 集成代码

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddOpenApi();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
    app.UseSwaggerUI(options =>
    {
        options.SwaggerEndpoint("/openapi/v1.json", "My Open API");
    });
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();

2.3 关键点

  • 没有 AddSwaggerGen() 也没有 UseSwagger()。这是与传统 Swashbuckle 用法最大的区别。文档生成由 .NET 内置管道负责,Swashbuckle 仅扮演 UI 中间件的角色。
  • SwaggerEndpoint 显式告诉 UI 去哪里加载 JSON——这里指向内置端点 /openapi/v1.json,而不是 Swashbuckle 自己生成的端点。
  • UI 默认挂载在 /swagger 路径。

2.4 访问地址

启动后访问 http://localhost:5293/swagger 即可看到经典的 Swagger UI 界面。

三、NSwag:另一种 Swagger UI 风味

3.1 安装

<PackageReference Include="NSwag.AspNetCore" Version="14.7.1" />

3.2 集成代码

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddOpenApi();
// builder.Services.AddOpenApiDocument();  // 这是 NSwag 自己的文档生成器,本项目不启用

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
    app.UseSwaggerUi(options =>
    {
        options.DocumentPath = "/openapi/v1.json";
        options.DocumentTitle = "My Open API";
    });
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();

3.3 关键点

  • 注意方法名的细微差别:UseSwaggerUi(NSwag)vs UseSwaggerUI(Swashbuckle)。一个驼峰一个全大写,写错就找不到方法。
  • DocumentPath 等同于 Swashbuckle 的 SwaggerEndpoint,指向内置 JSON。
  • 注释掉的 AddOpenApiDocument() 是 NSwag 的"另一面"——它本身也是一个完整的文档生成器,可以完全绕过 Microsoft.AspNetCore.OpenApi 独立工作。本项目没启用,是为了让三种工具保持对等比较。

3.4 NSwag 的双重身份

NSwag 比 Swashbuckle 更"重",它实际上包含三块能力:

  1. 文档生成器(AddOpenApiDocument)
  2. Swagger UI 渲染器(UseSwaggerUi,本项目用的这部分)
  3. 客户端代码生成工具(命令行 nswag.exe,可生成 C#/TypeScript 客户端)

在 .NET 10 时代,第一块能力被内置 API 取代后,第二块就是它在本场景下的核心价值。

3.5 访问地址

http://localhost:5027/swagger,UI 外观与 Swashbuckle 几乎一致——毕竟底层都是同一个开源的 Swagger UI 项目。

四、Scalar:现代化的新选手

4.1 安装

<PackageReference Include="Scalar.AspNetCore" Version="2.16.4" />

4.2 集成代码

using Scalar.AspNetCore;  // 注意:需要显式 using

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddOpenApi();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
    app.MapScalarApiReference();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();

4.3 关键点

  • 这里用的是 Map* 而非 Use*,这是路由端点注册,不是中间件。差别在于:中间件按管道顺序匹配所有请求,端点路由只命中特定 URL,性能与语义都更清晰,符合 ASP.NET Core 现代设计。
  • 默认无需任何参数。Scalar 会自动去找 /openapi/{documentName}.json,与 AddOpenApi() 的默认输出天然兼容。
  • UI 默认挂载在 /scalar 路径。

4.4 Scalar 的差异化卖点

如果说 Swashbuckle 和 NSwag 的 UI 都是同一个传统 Swagger UI 的不同包装,那 Scalar 就是真正"另起炉灶"的一个:

  • 现代化设计:三栏布局(导航 / 内容 / 请求示例),视觉风格接近 Stripe、Postman 等商业 API 平台。
  • 暗色模式:原生支持,无需额外配置。
  • 多语言代码示例:自动为每个端点生成 cURL、JavaScript、Python、Go 等多种语言的请求示例。
  • 更好的 Markdown 渲染:在端点描述里写富文本时表现更好。

4.5 访问地址

http://localhost:5115/scalar。

五、三者横向对比

维度 Swashbuckle NSwag Scalar
注册方式 中间件(Use*) 中间件(Use*) 路由端点(Map*)
UI 风格 传统 Swagger UI 传统 Swagger UI 现代化三栏布局
暗色模式 需自定义 需自定义 原生支持
代码示例 仅 cURL 仅 cURL 多语言
额外能力 几乎仅 UI 可独立生成文档、生成客户端代码 仅 UI(专注体验)
包大小 较小 较大 中等
学习曲线 最低(生态成熟) 中(配置项多) 低(默认即用)
配置必填项 SwaggerEndpoint DocumentPath 无

六、如何选型

把这三种工具按场景对号入座,大致是这样:

选 Swashbuckle,如果……

  • 团队习惯了传统 Swagger UI,想要最平滑的过渡
  • 项目里已经有大量 Swashbuckle 配置(Filter、SchemaFilter 等),延续使用即可
  • 想要最稳定、最被广泛验证的方案

选 NSwag,如果……

  • 需要在同一工具链里完成 "生成文档 + 渲染 UI + 生成客户端代码" 闭环
  • 团队后续可能脱离 .NET 内置管道,需要更精细的文档生成控制
  • 偏好基于 .NET 类型反射的更深度自定义

选 Scalar,如果……

  • 项目对外提供 API(开发者门户、SaaS 平台等),UI 颜值很重要
  • 希望开箱即用获得多语言代码示例,方便集成方
  • 不需要 UI 之外的能力(如客户端代码生成)

七、关键认知:UI 与文档生成已经解耦

回过头看,本文最重要的不是"三种工具谁更好",而是 .NET 9+ 带来的架构变化:

OpenAPI 文档的生成已经成为框架内置能力,UI 渲染则是可插拔的独立环节。

这意味着:

  1. 切换 UI 工具几乎零成本。文档 JSON 的来源不变,换个 NuGet 包、改一两行注册代码即可。
  2. 可以同时挂载多个 UI。比如内部用 Swagger UI 调试,对外用 Scalar 展示,互不冲突。
  3. 不必为 UI 库的文档生成能力买单。以前 Swashbuckle 的 Filter、ISchemaFilter 等配置都是为了影响它生成的 JSON——现在那些 JSON 来自框架,你只需要学一套:AddOpenApi() 的配置项。

这是一个值得在团队中普及的认知升级。如果你的 .NET 9/10 项目还在写 AddSwaggerGen() 加一堆 Filter,是时候重新审视技术栈了。

八、参考链接

九、源码仓库

本文涉及的全部演示代码已开源,欢迎 clone 体验:

https://gitee.com/Peter_Mond/my-open-api-swag.git

image

posted @ 2026-06-24 12:20  MikoyanF  阅读(34)  评论(0)    收藏  举报