关于 dotnet-openapi
面向 ASP.NET Core 开发者的 OpenAPI 集成指南,介绍文档生成、转换和架构定制,并说明 Microsoft.AspNetCore.OpenApi、Swashbuckle 与 NSwag 的用法。还涵盖迁移以及 .NET 10 中的 OpenAPI 3.1。
主要功能
- 01生成和配置 OpenAPI 文档
- 02使用文档、操作及架构转换器
- 03丰富端点的 OpenAPI 元数据
- 04从 Swashbuckle 迁移
- 05通过 NSwag 生成 C# 或 TypeScript 客户端
适用场景
- 01为 ASP.NET Core API 生成规范文档
- 02按 API 版本或功能组拆分文档
- 03为端点添加说明和响应元数据
- 04从 OpenAPI 规范生成类型化客户端
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ wshaddix/ dotnet-skills --skill dotnet-openapi安装后在 Claude Code 中输入/dotnet-openapi确认已加载。
详细介绍
dotnet-openapi
ASP.NET Core 的 OpenAPI/Swagger 集成。Microsoft.AspNetCore.OpenApi 是 .NET 9+ 推荐的第一方方案,也是新项目模板中的默认方案。Swashbuckle 已不再积极维护;使用 Swashbuckle 的现有项目应规划迁移。NSwag 仍是客户端生成和高级场景的替代方案。
不在此范围内: Minimal API 端点模式(路由组、筛选器、TypedResults)——请参阅 [skill:dotnet-minimal-apis]。API 版本控制策略——请参阅 [skill:dotnet-api-versioning]。身份验证和授权——请参阅 [skill:dotnet-api-security]。
交叉引用:[skill:dotnet-minimal-apis] 介绍可生成 OpenAPI 元数据的端点模式;[skill:dotnet-api-versioning] 介绍带版本的 OpenAPI 文档。
Microsoft.AspNetCore.OpenApi(推荐)
Microsoft.AspNetCore.OpenApi 是适用于 ASP.NET Core 9+ 的第一方 OpenAPI 包,并默认包含在新项目模板中。.NET 10 新增了对 OpenAPI 3.1 的支持,并符合 JSON Schema draft 2020-12 规范。
基本设置
// Microsoft.AspNetCore.OpenApi -- included by default in .NET 9+ project templates
// If not present, add: <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.*" />
// Version must match the project's target framework major version
builder.Services.AddOpenApi();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.MapOpenApi(); // Serves /openapi/v1.json
}
多个文档
为每个 API 版本或功能组生成单独的 OpenAPI 文档:
builder.Services.AddOpenApi("v1", options =>
{
options.OpenApiVersion = OpenApiSpecVersion.OpenApi3_0;
});
builder.Services.AddOpenApi("v2", options =>
{
options.OpenApiVersion = OpenApiSpecVersion.OpenApi3_1;
});
var app = builder.Build();
app.MapOpenApi(); // Serves /openapi/v1.json and /openapi/v2.json
文档转换器
文档转换器会在生成 OpenAPI 文档后对其进行修改。可使用它们添加服务器信息、安全方案或自定义元数据。
IOpenApiDocumentTransformer
public sealed class SecuritySchemeTransformer : IOpenApiDocumentTransformer
{
public Task TransformAsync(
OpenApiDocument document,
OpenApiDocumentTransformerContext context,
CancellationToken cancellationToken)
{
document.Components ??= new OpenApiComponents();
document.Components.SecuritySchemes["Bearer"] = new OpenApiSecurityScheme
{
Type = SecuritySchemeType.Http,
Scheme = "bearer",
BearerFormat = "JWT",
Description = "JWT Bearer token authentication"
};
document.SecurityRequirements.Add(new OpenApiSecurityRequirement
{
[new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
}] = Array.Empty<string>()
});
return Task.CompletedTask;
}
}
// Register the transformer
builder.Services.AddOpenApi(options =>
{
options.AddDocumentTransformer<SecuritySchemeTransformer>();
});
Lambda 文档转换器
对于简单的转换,可以使用 lambda 重载:
builder.Services.AddOpenApi(options =>
{
options.AddDocumentTransformer((document, context, ct) =>
{
document.Info = new OpenApiInfo
{
Title = "Products API",
Version = "v1",
Description = "Product catalog management API",
Contact = new OpenApiContact
{
Name = "API Support",
Email = "[email protected]"
}
};
return Task.CompletedTask;
});
});
操作转换器
操作转换器会修改 OpenAPI 文档中的单个操作(端点)。可使用它们添加每个操作的元数据、示例或条件逻辑。
public sealed class DeprecationTransformer : IOpenApiOperationTransformer
{
public Task TransformAsync(
OpenApiOperation operation,
OpenApiOperationTransformerContext context,
CancellationToken cancellationToken)
{
var deprecatedAttr = context.Description.ActionDescriptor
.EndpointMetadata
.OfType<ObsoleteAttribute>()
.FirstOrDefault();
if (deprecatedAttr is not null)
{
operation.Deprecated = true;
operation.Description = $"DEPRECATED: {deprecatedAttr.Message}";
}
return Task.CompletedTask;
}
}
builder.Services.AddOpenApi(options =>
{
options.AddOperationTransformer<DeprecationTransformer>();
});
架构自定义
使用架构转换器自定义 .NET 类型到 OpenAPI 架构的映射:
builder.Services.AddOpenApi(options =>
{
options.AddSchemaTransformer((schema, context, ct) =>
{
// Add example values for known types
if (context.JsonTypeInfo.Type == typeof(ProductDto))
{
schema.Example = new OpenApiObject
{
["id"] = new OpenApiInteger(1),
["name"] = new OpenApiString("Widget"),
["price"] = new OpenApiDouble(19.99)
};
}
return Task.CompletedTask;
});
});
丰富端点元数据
使用端点构建器上的 fluent 方法提供更丰富的 OpenAPI 元数据:
products.MapGet("/{id:int}", GetProductById)
.WithName("GetProductById")
.WithSummary("Get a product by its ID")
.WithDescription("Returns the product details for the specified ID, or 404 if not found.")
.WithTags("Products")
.Produces<Product>(StatusCodes.Status200OK)
.ProducesProblem(StatusCodes.Status404NotFound);
从 Swashbuckle 迁移
Swashbuckle(Swashbuckle.AspNetCore)已不再积极维护。它不支持 OpenAPI 3.1。现有项目应规划迁移到 Microsoft.AspNetCore.OpenApi。
仍需使用 Swashbuckle 的情况: 无法升级到 .NET 9+ 的 .NET 8 项目,或依赖 Swashbuckle 特有功能(可深度自定义的 SwaggerUI、ISchemaFilter 管道)的项目,可以在规划迁移期间继续使用 Swashbuckle。
迁移步骤
- 移除 Swashbuckle 包:
- 替换服务注册:
// Before (Swashbuckle)
builder.Services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
});
// After (Microsoft.AspNetCore.OpenApi)
builder.Services.AddOpenApi();
- 替换中间件:
// Before (Swashbuckle)
app.UseSwagger();
app.UseSwaggerUI();
// After (built-in)
app.MapOpenApi(); // Serves raw OpenAPI JSON at /openapi/v1.json
- 对于 Swagger UI,添加独立的 UI 包或使用 Scalar:
// Option 1: Scalar (modern, built-in support in .NET 10)
// <PackageReference Include="Aspire.Dashboard.Components.Scalar" ... /> or use MapScalarApiReference
app.MapScalarApiReference(); // .NET 10
// Option 2: Swagger UI standalone
// <PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="..." />
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/openapi/v1.json", "v1");
});
- 将 Swashbuckle 筛选器迁移为转换器:
| Swashbuckle 概念 | 内置替代方案 |
|---|---|
IDocumentFilter | IOpenApiDocumentTransformer |
IOperationFilter | IOpenApiOperationTransformer |
ISchemaFilter | 通过 AddSchemaTransformer 使用架构转换器 |
[SwaggerOperation] | .WithSummary()、.WithDescription() |
[SwaggerResponse] | .Produces<T>()、TypedResults |
NSwag
NSwag 是一套替代的 OpenAPI 工具链,包含文档生成、客户端生成(C#、TypeScript)和 UI。如果需要生成 API 客户端,或需要与非 .NET 使用方集成,它会很有用。
文档生成
// <PackageReference Include="NSwag.AspNetCore" Version="14.*" />
builder.Services.AddOpenApiDocument(options =>
{
options.Title = "Products API";
options.Version = "v1";
options.DocumentName = "v1";
});
var app = builder.Build();
app.UseOpenApi(); // Serves /swagger/v1/swagger.json
app.UseSwaggerUi(); // Serves /swagger UI
客户端生成
NSwag 可根据 OpenAPI 规范生成类型化的 C# 或 TypeScript 客户端:
# Install NSwag CLI
dotnet tool install --global NSwag.ConsoleCore
# Generate C# client from OpenAPI spec
nswag openapi2csclient /input:https://api.example.com/openapi/v1.json \
/output:GeneratedClient.cs \
/namespace:MyApp.ApiClient \
/generateClientInterfaces:true
建议: 使用 Microsoft.AspNetCore.OpenApi 生成文档。使用 NSwag CLI 或 Kiota 根据生成的 OpenAPI 规范生成客户端。新项目应避免同时使用 NSwag 进行生成和服务。
OpenAPI 3.1(.NET 10)
.NET 10 引入了对 OpenAPI 3.1 的完整支持,并符合 JSON Schema draft 2020-12。相比 3.0 的主要改进:
- 可空类型: 使用 JSON Schema
type: ["string", "null"]代替nullable: true - 判别器改进: 更好地支持多态类型的 oneOf/anyOf
- Webhooks: 原生支持 Webhook 定义
- JSON Schema 对齐: 与 JSON Schema draft 2020-12 工具完全兼容
// .NET 10: OpenAPI 3.1 is the default
// <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.*" />
builder.Services.AddOpenApi(options =>
{
// Explicitly set version if needed (3.1 is default in .NET 10)
options.OpenApiVersion = OpenApiSpecVersion.OpenApi3_1;
});
注意事项: Swashbuckle 不支持 OpenAPI 3.1。需要使用 3.1 功能的项目必须迁移到 Microsoft.AspNetCore.OpenApi。
Agent 注意事项
- 不要固定使用与
Microsoft.AspNetCore.OpenApi主版本不匹配的版本 —— 包版本必须与项目的目标框架主版本一致。不要在同一项目中混用不兼容的 OpenAPI 技术栈(例如 Swashbuckle 与内置方案)。 - 不要为新的 .NET 9+ 项目推荐 Swashbuckle —— 它已不再积极维护。请改用内置的
Microsoft.AspNetCore.OpenApi。 - 不要称 Swashbuckle 为“已弃用” —— 它并未正式弃用,但已不再积极维护。提及内置替代方案时,请使用“首选”或“推荐”。
- 不要忘记替换 Swagger UI ——
MapOpenApi()只提供原始 JSON 规范。请另外添加 Scalar、独立版 Swagger UI 或其他 UI。 - 不要在同一项目中混用 Swashbuckle 和内置 OpenAPI —— 它们会生成相互冲突的文档。请选择一种方案。
- 不要对 ASP.NET 共享框架包的版本进行硬编码 ——
Microsoft.AspNetCore.OpenApi等包必须与项目 TFM 主版本一致。
前置条件
- 使用
Microsoft.AspNetCore.OpenApi需要 .NET 9.0+(包含在默认项目模板中) - 使用 OpenAPI 3.1、JSON Schema draft 2020-12 和 Scalar 集成需要 .NET 10.0
NSwag.AspNetCore(可选),用于基于 NSwag 的生成和 UISwashbuckle.AspNetCore(旧版),适用于尚未迁移的现有项目