练习 - 使用 XML 注释和批注来自定义和扩展 OpenAPI 文档
在本练习中,你将通过向代码添加注释和批注来扩充开发人员看到的有关 API 的文档。 首先,让我们来了解默认情况下从 Swagger UI 获得的内容。
若要检查 Swagger UI 中 API 终结点的 OpenAPI 定义,请在浏览器中导航到
http://localhost:5000/swagger
。 选择“Get”方法时,应会看到如下所示输出。Swagger UI 为我们提供了有关 API 的一些有用信息。 它显示了可调用的方法(在我们的简单示例中,调用了一个名为 PriceFrame 的方法)。 可以看到这是一个 HTTP Get 操作,它采用了两个分别名为“高度”和“宽度”的必需参数。 要查看 API 调用的运行情况,可以选择“试一试”,输入“高度”和“宽度”值,然后选择“执行”。
你的 API 用户仍缺乏足够的信息来了解 PriceFrame 方法的限制。 让我们帮助他们通过 XML 注释了解更详细的信息。
将 XML 注释添加到 API
返回到上一练习所用 Visual Studio Code 的实例。
如果 Web API 仍在上一个练习中运行,请在 Windows 上按 ctrl+c,或在 Mac 上按 cmd+c 来停止它。
若要在项目中激活 XML 文档,请更新 PrintFramerAPI.csproj 项目文件,然后将
GenerateDocumentationFile
标记添加到现有的<PropertyGroup>
中,并将其设置为true
。<PropertyGroup> <TargetFramework>net7.0</TargetFramework> <GenerateDocumentationFile>true</GenerateDocumentationFile> <NoWarn>$(NoWarn);1591</NoWarn> </PropertyGroup>
在 Startup.cs 中添加以下 using 语句。
using System.Reflection; using System.IO;
在“Startup.cs”中,通过更新对
ConfigureServices
中AddSwaggerGen()
的调用来指示 Swashbuckle 使用 XML 文档。public void ConfigureServices(IServiceCollection services) { services.AddControllers(); // Register the Swagger generator, defining 1 or more Swagger documents services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Version = "v1", Title = "PrintFramer API", Description = "Calculates the cost of a picture frame based on its dimensions.", TermsOfService = new Uri("https://go.microsoft.com/fwlink/?LinkID=206977"), Contact = new OpenApiContact { Name = "Your name", Email = string.Empty, Url = new Uri("https://learn.microsoft.com/training") } }); // Set the comments path for the Swagger JSON and UI. var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); c.IncludeXmlComments(xmlPath); }); }
在上面的代码中,反射的作用是确定加载 XML 注释的 XML 文件的名称。
在“Controllers”文件夹中,打开“PriceFrameController.cs”。 在
GetPrice
方法的“HTTPGet”属性上方添加以下 XML 注释块。 向操作添加三斜杠注释会通过将描述添加到节标题来增强 Swagger UI。/// <summary> /// Returns the price of a frame based on its dimensions. /// </summary> /// <param name="Height">The height of the frame.</param> /// <param name="Width">The width of the frame.</param> /// <returns>The price, in dollars, of the picture frame.</returns> /// <remarks> The API returns 'not valid' if the total length of frame material needed (the perimeter of the frame) is less than 20 inches and greater than 1000 inches.</remarks> [HttpGet("{Height}/{Width}")] public string GetPrice(string Height, string Width) { string result; result = CalculatePrice(Double.Parse(Height), Double.Parse(Width)); return $"The cost of a {Height}x{Width} frame is ${result}"; }
若要保存所有更改并确保它在本地生成,请在 Visual Studio Code 终端窗口中运行以下命令。
dotnet build
若要查看更改,请本地运行 ASP.NET 应用程序,方法是在 Visual Studio 代码终端窗口中输入以下内容:
dotnet run
再次在
http://localhost:5000/swagger
中查看 Swagger UI,并观察 XML 注释提供给 OpenAPI 文档的附加信息。
将数据注释添加到 API
若要启用 Swagger 来改进 OpenAPI 文档,则可以使用 Microsoft.AspNetCore.Mvc
命名空间中的属性。
如果 Web API 仍在上一个练习中运行,请在 Windows 上按 ctrl+c,或在 Mac 上按 cmd+c 来停止它。
若要表明
GetPrice
API 支持文本/纯文本的内容类型响应,请在 API 控制器 PriceFrameController.cs 中的GetPrice
定义上方添加[Produces("text/plain")]
属性。[HttpGet("{Height}/{Width}")] [Produces("text/plain")]
在“响应内容类型”下拉列表中选择此内容类型作为控制器的 GET 操作的默认值。
将 Swashbuckle 注释添加到 API
到目前为止,当 API 能够计算给定框架尺寸的价格后,它会返回状态代码 200。 在 GetPrice
方法的说明中,请注意无法计算价格的事例。
告诉开发人员响应类型和错误代码的更为可靠的方法是使用以下 XML 注释和数据注释。 Swashbuckle 和 Swagger 工具将使用这些值来明确生成预期 HTTP 响应代码的 OpenAPI 描述。
此外,请更新 HTTP 谓词筛选器构造函数以包含 Name
属性,并包括 OpenAPI operationId
值。
将以下 using 语句添加到“PriceFrameController.cs”文件。
using Microsoft.AspNetCore.Http;
在“PriceFrameController.cs”中,使用以下代码和注释替换
GetPrice
。/// <summary> /// Returns the price of a frame based on its dimensions. /// </summary> /// <param name="Height">The height of the frame.</param> /// <param name="Width">The width of the frame.</param> /// <returns>The price, in dollars, of the picture frame.</returns> /// <remarks> /// Sample request: /// /// Get /api/priceframe/5/10 /// /// </remarks> /// <response code="200">Returns the cost of the frame in dollars.</response> /// <response code="400">If the amount of frame material needed is less than 20 inches or greater than 1000 inches.</response> [HttpGet("{Height}/{Width}", Name=nameof(GetPrice))] [Produces("text/plain")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] public ActionResult<string> GetPrice(string Height, string Width) { string result; result = CalculatePrice(Double.Parse(Height), Double.Parse(Width)); if (result == "not valid") { return BadRequest(result); } else { return Ok($"The cost of a {Height}x{Width} frame is ${result}"); } }
此代码更新进行了以下更改:
- 该方法使用
BadRequest()
和Ok()
方法分别创建 BadRequest(400) 和 Ok 状态,将字符串结果传递给响应。 - XML 注释描述此方法可以返回的每个状态代码。
- HttpGet 属性包含用于发出 OpenAPI
operationId
参数的Name
属性。 - ProducesResponseType 属性可列出操作可以返回的不同响应。 如上所述,这些属性与 XML 注释相结合,从而在生成的 Swagger 中包含了每个响应的易于理解的描述
- 该方法使用
使用以下命令重新生成 Web API:
dotnet build
使用以下命令运行 ASP.NET 应用程序:
dotnet run
再次在
http://localhost:5000/swagger
中查看 Swagger UI,并观察这些注释提供的附加信息。 下图显示 API 的最终 Swagger UI。
在本练习中,你扩充了开发人员可收到的有关 API 的信息,从而可以更轻松地使用该 API。