练习 - 使用 XML 注释和批注来自定义和扩展 OpenAPI 文档

已完成

在本练习中,你将通过向代码添加注释和批注来扩充开发人员看到的有关 API 的文档。 首先,让我们来了解默认情况下从 Swagger UI 获得的内容。

  1. 若要检查 Swagger UI 中 API 终结点的 OpenAPI 定义,请在浏览器中导航到 http://localhost:5000/swagger。 选择“Get”方法时,应会看到如下所示输出。

    Default Swagger UI for our API.

    Swagger UI 为我们提供了有关 API 的一些有用信息。 它显示了可调用的方法(在我们的简单示例中,调用了一个名为 PriceFrame 的方法)。 可以看到这是一个 HTTP Get 操作,它采用了两个分别名为“高度”和“宽度”的必需参数。 要查看 API 调用的运行情况,可以选择“试一试”,输入“高度”和“宽度”值,然后选择“执行”

    你的 API 用户仍缺乏足够的信息来了解 PriceFrame 方法的限制。 让我们帮助他们通过 XML 注释了解更详细的信息。

将 XML 注释添加到 API

  1. 返回到上一练习所用 Visual Studio Code 的实例。

  2. 如果 Web API 仍在上一个练习中运行,请在 Windows 上按 ctrl+c,或在 Mac 上按 cmd+c 来停止它。

  3. 若要在项目中激活 XML 文档,请更新 PrintFramerAPI.csproj 项目文件,然后将 GenerateDocumentationFile 标记添加到现有的 <PropertyGroup> 中,并将其设置为 true

    <PropertyGroup>
        <TargetFramework>net7.0</TargetFramework>
        <GenerateDocumentationFile>true</GenerateDocumentationFile>
        <NoWarn>$(NoWarn);1591</NoWarn>
    </PropertyGroup>
    
  4. 在 Startup.cs 中添加以下 using 语句。

    using System.Reflection;
    using System.IO;
    
  5. 在“Startup.cs”中,通过更新对 ConfigureServicesAddSwaggerGen() 的调用来指示 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 文件的名称。

  6. 在“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}";
     }
    
  7. 若要保存所有更改并确保它在本地生成,请在 Visual Studio Code 终端窗口中运行以下命令。

    dotnet build
    
  8. 若要查看更改,请本地运行 ASP.NET 应用程序,方法是在 Visual Studio 代码终端窗口中输入以下内容:

    dotnet run
    
  9. 再次在 http://localhost:5000/swagger 中查看 Swagger UI,并观察 XML 注释提供给 OpenAPI 文档的附加信息。

    Swagger UI with the final documentation from XML comments for our API.

将数据注释添加到 API

若要启用 Swagger 来改进 OpenAPI 文档,则可以使用 Microsoft.AspNetCore.Mvc 命名空间中的属性。

  1. 如果 Web API 仍在上一个练习中运行,请在 Windows 上按 ctrl+c,或在 Mac 上按 cmd+c 来停止它。

  2. 若要表明 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 值。

  1. 将以下 using 语句添加到“PriceFrameController.cs”文件

    using Microsoft.AspNetCore.Http;
    
  2. 在“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 中包含了每个响应的易于理解的描述
  3. 使用以下命令重新生成 Web API:

    dotnet build
    
  4. 使用以下命令运行 ASP.NET 应用程序:

    dotnet run
    
  5. 再次在 http://localhost:5000/swagger 中查看 Swagger UI,并观察这些注释提供的附加信息。 下图显示 API 的最终 Swagger UI。

    Swagger UI with more documentation from XML comments for our API.

在本练习中,你扩充了开发人员可收到的有关 API 的信息,从而可以更轻松地使用该 API。