技术速递|.NET 9 中的 OpenAPI 文档生成

作者:Mike Kistler

排版:Alan Wang

.NET 9 中的 ASP.NET Core 通过引入全新的对 OpenAPI 文档生成功能的内置支持,简化了为 API 端点创建 OpenAPI 文档的过程。这项新功能旨在简化开发工作流程,并改善 OpenAPI 定义在 ASP.NET 应用中的集成。OpenAPI 的广泛使用催生了丰富的工具和服务生态系统,它们能够帮助您更高效地构建、测试和记录 API。例如,Swagger UI、Kiota 客户端库生成器和 Redoc 等,当然还有许多其他工具。

为什么选择 OpenAPI?

OpenAPI 是定义和记录 HTTP API 的强大工具。它提供了一种标准化方式来描述 API 的端点、请求和响应格式、身份验证方案以及其他重要细节。这种标准化使开发人员能够更轻松地理解和交互 API,从而促进更好的协作并构建更强大的应用程序。

此外,许多大型语言模型(LLMs)已经通过 OpenAPI 文档进行训练,使其能够自动生成代码、测试用例和其他工件。通过为您的 API 生成 OpenAPI 文档,您可以利用这些 LLM 来加速开发流程。

.NET 9 的新功能?

在 .NET 9 中,我们引入了对 OpenAPI 文档生成功能的内置支持,为 .NET 开发人员提供了更集成、更流畅的体验。此功能可用于最小 API 和基于控制器的应用程序。以下是一些关键亮点:

  • 支持在运行时生成 OpenAPI 文档,并通过应用程序上的端点访问它们,或在构建时生成文档。

  • 为 API 方法和数据添加元数据的属性和扩展方法。

  • 支持“转换器”API,允许以多种方式修改生成的文档。

  • 支持从单个应用程序生成多个 OpenAPI 文档。

  • 利用 System.Text.Json 提供的 JSON schema 支持。

  • 与最小 API 结合使用时,兼容原生 AoT(Ahead-of-Time)编译。

如何入门

在 .NET 9 中开始使用新的 OpenAPI 文档生成功能非常简单。以下是一个帮助您入门的快速指南。

更新到 .NET 9

确保您的项目使用的是本月初发布的 .NET 9。您可以从 官方 .NET 网站下载最新版本。

如果您想为现有项目添加 OpenAPI 支持,则需要将项目的目标框架更新为 .NET 9。有关详细的迁移指南,请参阅 ASP.NET Core 文档中的相关内容。

启用 OpenAPI 支持

如果您正在创建一个新项目,.NET 9 的 webapi 模板已经内置了 OpenAPI 支持。

要在现有项目中启用 OpenAPI 文档支持,您只需添加 Microsoft.AspNetCore.OpenApi 包,并在主应用程序文件中添加几行代码。

您可以通过命令 dotnet add package 添加该包:

dotnet add package Microsoft.AspNetCore.OpenApi

接着,您需要在 Program.cs 文件中将 OpenAPI 服务添加到 WebApplicationBuilder:

builder.Services.AddOpenApi();

OpenAPI 功能提供了各种配置选项,例如设置文档标题、版本和其他元数据。您可以在 ASP.NET Core 文档中找到有关这些选项的更多信息。

然后,在应用程序中添加端点,通过 MapOpenApi 扩展方法为 OpenAPI 文档提供服务,如下所示:

app.MapOpenApi();

现在,您可以运行您的应用程序,并在 /openapi/v1.json 端点访问生成的 OpenAPI 文档。

您将在该端点看到一个包含路径、操作和模式的 OpenAPI 文档,这些内容是基于您的应用程序代码生成的,但可能不包括描述和示例等重要细节。要获取这些元素,您需要按照下一节中的说明添加元数据。

添加 OpenAPI 元数据

描述、标签、示例和其他元数据都可以被添加到 API 方法和数据中,以赋予生成的 OpenAPI 文档含义。您可以使用属性或扩展方法添加此元数据。

您可以使用 WithSummaryWithDescription 扩展方法为应用程序中的每个端点添加摘要和描述:

app.MapGet("/hello", () => "Hello, World!").WithSummary("Get a greeting").WithDescription("This endpoint returns a friendly greeting.");

端点的摘要和描述非常重要,因为它们告诉用户(以及大语言模型 LLM)可以通过您的 API 完成哪些操作。

您可能还希望将相关的端点在文档中进行分组,通常可以通过标签来实现。您可以使用 WithTag 扩展方法为端点添加标签:

app.MapGet("/hello", () => "Hello, World!").WithTag("Greetings");

当端点具有参数时,重要的是为每个参数添加描述,以解释其含义以及该参数如何被端点使用。您可以使用 [Description] 属性为参数添加描述:

app.MapGet("/hello/{name}",
([Description("The name of the person to greet.")] string name
) => $"Hello, {name}!").WithSummary("Get a personalized greeting").WithDescription("This endpoint returns a personalized greeting.").WithTag("Greetings");

您还可以使用 [Description] 属性为数据模型中的属性添加描述:

public record Person
{[Description("The person's name.")]public string Name { get; init; }[Description("The person's age.")]public int Age { get; init; }
}

还有许多其他元数据属性用于描述参数和属性,包括 [MaxLength](最大长度)、[Range](范围)、[RegularExpression](正则表达式)和 [DefaultValue](默认值)。请注意,在基于控制器的应用程序中,这些属性会触发在模型绑定期间执行的验证,但在最小 API 中,它们仅用于文档生成。

请参阅文档中的包括 OpenAPI 元数据主题,了解更多关于为您的 API 方法和数据添加元数据的信息。

自定义文档

ASP.NET 还提供了一种使用“转换器”自定义生成的 OpenAPI 文档的方法,转换器可以对整个文档、操作或架构进行操作。转换器是实现 IOpenApiDocumentTransformerIOpenApiOperationTransformerIOpenApiSchemaTransformer 接口的类。每个接口都有一个异步方法,用于接收要转换的文档、操作或架构以及提供其他信息的上下文对象。传递给转换器的 OpenAPI 文档、操作或架构是使用 Microsoft.OpenApi.Models 命名空间中类型的强类型对象。该方法通过修改它接收到的对象来“原地”执行转换。

转换器通过 AddOpenApi 调用的 configureOptions 委托参数添加,并且可以指定为类的实例、以 DI 激活的类或委托方法。

builder.Services.AddOpenApi(options =>
{// 添加文档转换器作为类的实例 options.AddDocumentTransformer(new MyDocumentTransformer());// 以 DI 激活类的形式添加操作转换器 options.AddOperationTransformer<MyOperationTransformer>();// 作为委托方法添加模式转换器 options.AddSchemaTransformer((schema, context, cancellationToken)=> Task.CompletedTask);
});

文档转换器的一种用处是修改 OpenAPI 文档中 pathscomponents.schemas 之外的部分。例如,您可以在文档的 info 元素中添加 contact,如下所示:

builder.Services.AddOpenApi(options =>
{options.AddDocumentTransformer((document, context, cancellationToken) =>{document.Info.Contact = new OpenApiContact{Name = "Contoso Support",Email = "support@contoso.com"};return Task.CompletedTask;}
});

操作转换器可用于修改文档中的单个操作。操作转换器会针对应用中的每个操作调用,它可以选择是否修改操作。例如,您可以像这样为所有需要授权的操作添加一个安全要求:

options.AddOperationTransformer((operation, context, cancellationToken) =>{if (context.Description.ActionDescriptor.EndpointMetadata.OfType<IAuthorizeData>().Any()){operation.Security = [new() { ["Bearer"] = [] }];}return Task.CompletedTask;});

架构转换器可用于修改应用程序的架构。架构描述了操作的请求或响应体。请求或响应体中的复杂属性可能具有其自己的架构。架构转换器可以用来修改任意或所有这些架构。

需要注意的是,包括架构转换器在内的所有转换器都会在架构被转换为 “$ref” 引用之前被调用——此过程将在下一节中讨论。

以下示例展示了一个简单的架构转换器,它将任何表示 C# decimal (十进制)值的架构的 format (格式)字段设置为 decimal(十进制):

options.AddSchemaTransformer((schema, context, cancellationToken) =>{if (context.JsonTypeInfo.Type == typeof(decimal)){//  默认模式仅为 type: number。 添加格式:十进制schema.Format = "decimal";}return Task.CompletedTask;});

自定义架构重用

在所有转换器应用完成后,框架会对文档进行处理,将某些架构转移到 components.schemas 部分,并替换为指向被转移架构的 “$ref” 引用。这种处理减少了文档的大小,使其更易于阅读。

这个处理的细节比较复杂,并且可能会在未来的 .NET 版本中发生变化,但总体来说:

对于 类/记录/结构 类型的架构,如果它们在文档中出现多次,则会被替换为指向 components.schemas 中架构的 “$ref” 引用。

对于 原始类型 和 标准集合 的架构,则保持“内联”。

对于 枚举类型 的架构,总是会被替换为指向 components.schemas 中架构的 “$ref” 引用。

通常情况下,components.schemas 中的架构名称是类/记录/结构类型的名称,但在某些情况下可能需要使用其他名称。

ASP.NET Core 允许您通过配置 OpenApiOptionsCreateSchemaReferenceId 属性自定义哪些架构会被替换为指向 components.schemas 中架构的 “$ref” 引用。此属性是一个委托,它接受 JsonTypeInfo 对象并返回 components.schemas 中应用于该类型的架构的名称。框架提供了此委托的默认实现 OpenApiOptions.CreateDefaultSchemaReferenceId,它使用了类型的名称,但您也可以用自己的实现来代替它。

举个简单的自定义例子,您可以选择始终内联枚举模式。这可以通过将 CreateSchemaReferenceId 设置为一个委托实现来实现,该委托对枚举类型始终返回 null,而对其他类型则返回默认实现的值。以下代码展示了如何完成此操作:

builder.Services.AddOpenApi(options =>
{// 始终内联枚举模式 options.CreateSchemaReferenceId = (type) => type.Type.IsEnum ? null : OpenApiOptions.CreateDefaultSchemaReferenceId(type);
});

在构建时生成 OpenAPI 文档

我想许多 .NET 开发人员都会发现,在构建时生成 OpenAPI 文档的选项是一项非常吸引人的功能。将 OpenAPI 文档的生成作为构建过程的一部分,可以更轻松地与本地开发工作流或 CI 管道中的工具集成。例如,您可以对生成的文档运行 linter (检验程序)以确保其符合组织的标准,或者使用该文档生成客户端代码或测试。

在构建时生成 OpenAPI 文档非常简单。只需将 Microsoft.Extensions.ApiDescription.Server 包添加到您的项目中。默认情况下,OpenAPI 文档会生成到项目的 obj 目录中,但您可以通过 OpenApiDocumentsDirectory 属性自定义生成文档的位置。例如,要将文档生成到项目的根目录,可以在项目文件中添加以下内容:

<PropertyGroup><OpenApiDocumentsDirectory>./</OpenApiDocumentsDirectory>
</PropertyGroup>

请注意,构建时生成 OpenAPI 文档的机制是通过启动应用程序的入口点并使用惰性服务器实现来完成的。这允许框架纳入仅在运行时可用的元数据,但在某些构建场景下,可能需要对您的应用程序进行一些更改以确保正常工作。

有关更多信息,请参阅文档中的构建时生成 OpenAPI 主题。

总结

.NET 9 中新的 OpenAPI 文档生成功能为开发人员创建和维护 ASP.NET 应用程序的 API 文档提供了新的途径。通过将此功能直接集成到 ASP.NET Core 中,开发人员现在可以在构建时或运行时生成 OpenAPI 文档,根据需要自定义它们,并确保它们与代码保持同步。而且,在最小 API 应用程序中,此功能与原生 AoT 编译完全兼容。

我们很乐意听到您对此新功能的反馈。请试用并告诉我们您的想法。

祝编码愉快!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/69250.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

StarRocks BE源码编译、CLion高亮跳转方法

阅读SR BE源码时&#xff0c;很多类的引用位置爆红找不到&#xff0c;或无法跳转过去&#xff0c;而自己的Linux机器往往缺乏各种C依赖库&#xff0c;配置安装比较麻烦&#xff0c;因此总体的思路是通过CLion远程连接SR社区已经安装完各种依赖库的Docker容器&#xff0c;进行编…

STM32 按键密码系统的实现

本次基于STM32F407开发板&#xff0c;来实现密码系统&#xff0c;输入四位密码&#xff0c;密码正确时LED1亮&#xff0c;密码错误时四个LED灯双闪。 LED双闪代码 简单的逻辑&#xff0c;让四个LED灯先亮然后再延时一会LED灯灭&#xff0c;循环4此实现双闪的效果。 按键密码的…

linux常用加固方式

目录 一.系统加固 二.ssh加固 三.换个隐蔽的端口 四.防火墙配置 五.用户权限管理 六.暴力破解防护 七.病毒防护 八.磁盘加密 九.双因素认证2FA 十.日志监控 十一.精简服务 一.系统加固 第一步&#xff1a;打好系统补丁 sudo apt update && sudo apt upgra…

hadoop==docker desktop搭建hadoop

hdfs map readuce yarn https://medium.com/guillermovc/setting-up-hadoop-with-docker-and-using-mapreduce-framework-c1cd125d4f7b 清理资源 docker-compose down docker system prune -f

【Elasticsearch 基础入门】Centos7下Elasticsearch 7.x安装与配置(单机)

Elasticsearch系列文章目录 【Elasticsearch 基础入门】一文带你了解Elasticsearch&#xff01;&#xff01;&#xff01;【Elasticsearch 基础入门】Centos7下Elasticsearch 7.x安装与配置&#xff08;单机&#xff09; 目录 Elasticsearch系列文章目录前言单机模式1. 安装 J…

Fullcalendar @fullcalendar/react 样式错乱丢失问题和导致页面卡顿崩溃问题

问题描述&#xff1a; 我使用 fullcalendar的react版本时&#xff0c;出现了一个诡异的问题&#xff0c;当我切换到 一个iframe页面时&#xff08;整个页面是一个iframe嵌入的&#xff09;&#xff0c;再切换回来日历的样式丢失了&#xff01;不仅丢失了样式还导致页面崩溃了&…

算法12(力扣739)-每日温度

1、问题 给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0c;下一个更高温度出现在几天后。如果气温在这之后都不会升高&#xff0c;请在该位置用 0 来代替。 2、示例 &#…

STM32项目分享:智能厨房安全检测系统

目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 PCB图 五、程序设计 六、实验效果 七、资料内容 项目分享 一、前言 项目成品图片&#xff1a; 哔哩哔哩视频链接&#xff1a; STM32智能厨房安全检测系统 &#xff08;资料分…

定时器按键tim_key模版

低优先级放在高优先级内势必是程序卡死 把高优先级放到低优先级内&#xff0c;会使程序卡死 可修改 Debuger调试方法 Pwm rcc #include "my_main.h" uint8_t led_sta0x10; char text[30]; void LED_Disp(uint8_t dsLED) {HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPI…

大模型-本地化部署调用--基于ollama+openWebUI+springBoot

大模型-本地化部署调用–基于ollamaopenWebUIspringBoot 前言 前段时间&#xff0c;啊&#xff0c;可能不是前段时间&#xff0c;过去的2024年吧&#xff0c;大模型这块的内容也是非常火的&#xff0c;各家巨头也开始卷大模型的研发。那么本人呢也在过去的一年中也是用到了一…

RV1126+FFMPEG推流项目源码

源码在我的gitee上面&#xff0c;感兴趣的可以自行了解 nullhttps://gitee.com/x-lan/rv126-ffmpeg-streaming-projecthttps://gitee.com/x-lan/rv126-ffmpeg-streaming-project

宏_wps_宏修改word中所有excel表格的格式_设置字体对齐格式_删除空行等

需求&#xff1a; 将word中所有excel表格的格式进行统一化&#xff0c;修改其中的数字类型为“宋体&#xff0c; 五号&#xff0c;右对齐&#xff0c; 不加粗&#xff0c;不倾斜”&#xff0c;其中的中文为“宋体&#xff0c; 五号&#xff0c; 不加粗&#xff0c;不倾斜” 数…

ServletOutputStream failed to write: Broken pipe

案发现场 问题&#xff1a; org.springframework.web.context.request.async.AsyncRequestNotUsableException: ServletOutputStream failed to write: Broken pipe org.springframework.web.context.request.async.AsyncRequestNotUsableException: ServletOutputStream …

CNN-BiLSTM卷积双向长短期记忆神经网络时间序列预测(Matlab完整源码和数据)

CNN-BiLSTM卷积双向长短期记忆神经网络时间序列预测&#xff08;Matlab完整源码和数据&#xff09; 目录 CNN-BiLSTM卷积双向长短期记忆神经网络时间序列预测&#xff08;Matlab完整源码和数据&#xff09;预测效果基本介绍 CNN-BiLSTM卷积双向长短期记忆神经网络时间序列预测一…

14-6-2C++STL的list

(一&#xff09;list对象的带参数构造 1.list&#xff08;elem);//构造函数将n个elem拷贝给本身 #include <iostream> #include <list> using namespace std; int main() { list<int> lst(3,7); list<int>::iterator it; for(itlst.begi…

[b01lers2020]Life on Mars1

打开题目页面如下 看了旁边的链接&#xff0c;也没有什么注入点&#xff0c;是正常的科普 利用burp suite抓包&#xff0c;发现传参 访问一下 http://5edaec92-dd87-4fec-b0e3-501ff24d3650.node5.buuoj.cn:81/query?searchtharsis_rise 接下来进行sql注入 方法一&#xf…

Linux的udev详解、安装和使用(dev下的设备每次开机的名称不固定怎么办?)

前言&#xff08;问题与需求&#xff09;&#xff1a; 在传统的devfs 1&#xff1a;设备映射的不确定&#xff1a;一个设备多次加载设备的设备文件可能不同&#xff0c;比如一个hub有可能是ttyUSB0或ttyUSB2或ttyUSB3 2&#xff1a;devfs没有足够的主辅设备号&#xff0c;当设…

Linux 内核中的 InfiniBand 核心模块:drivers/infiniband/core/device.c 分析

InfiniBand 是一种高性能、低延迟的网络互连技术,广泛应用于高性能计算(HPC)、数据中心和云计算等领域。Linux 内核中的 InfiniBand 子系统提供了对 InfiniBand 设备的支持,而 drivers/infiniband/core/device.c 文件则是 InfiniBand 核心模块的重要组成部分。本文将对 dev…

如何快速开发LabVIEW项目,成为LabVIEW开发的高手

发现了一篇多年前写的文章&#xff0c;转发到这里 如何快速开发LabVIEW项目&#xff0c;成为LabVIEW开发的高手。 如果您手里有LabVIEW项目&#xff0c;领导催的又很紧&#xff0c;该怎么办&#xff1f; 如果您公司规模小&#xff0c;就想把LabVIEW项目快速搞定&#xff0c;有什…