一些实用的 .NET 开发工具(一):swagger

swagger 是什么?

swagger 是一套框架,作用是自动化生成 .NET 的 Web API 项目的 API 文档。
ASP.NET Core 官方提供了简单的 Swagger 使用文档:ASP.NET Web API Help Pages using Swagger

Getting Started

  1. 首先我们要安装 Swashbuckle.AspNetCore 的 Nuget 包

    1
    Install-Package Swashbuckle.AspNetCore -Pre
  2. 然后我们可以在 Startup.cs 中的 ConfigureServices 方法中注册 Swagger 文档生成器,这里可以定义一个或多个需要生成的文档

    1
    2
    3
    4
    5
    6
    services.AddMvc();

    services.AddSwaggerGen(c =>
    {
    c.SwaggerDoc("v1", new Info { Title = "My API", Version = "v1" });
    });
  3. 我们需要确保所有的 API 方法和非路径的参数都有明确的 Http 和 From 绑定修饰符

    1
    2
    3
    4
    5
    6
    7
    [HttpPost]
    public void Create([FromBody]Product product)
    ...

    [HttpGet]
    public IEnumerable<Product> Search([FromQuery]string keywords)
    ...

    注: 省略参数绑定修饰符则默认为请求 (query) 字段

  4. Configure 方法中添加中间件来暴露 Swagger 生成的文档 JSON

    1
    app.UseSwagger();

    此时你可以启动应用并在 “/swagger/v1/swagger.json.” 下看到 Swagger 生成的 JSON

  5. (可选)如果你想得到交互式的文档,可以添加 swagger-ui 中间件。需要指定 Swagger JSON 源

    1
    2
    3
    4
    app.UseSwaggerUI(c =>
    {
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
    });

    在 “/swagger” 下可以看到这个交互式的页面

Swashbuckle & ApiExplorer

Swashbuckle 十分依赖 ApiExplorerApiExplorer 是一项位于 ASP.NET Core 之上的 Metadata 层的服务。如果服务集使用的是 AddMvc 方法引导 MVC 栈的话那么会自动注册 ApiExplorer_。然而如果是用 _AddMvcCore 来自行引导 MVC stack 的话你需要手动添加 Api Explorer 服务:

1
2
services.AddMvcCore()
.AddApiExplorer();

组件

Swashbuckle 包含三个包:Swagger 生成器, 暴露 JSON 格式 Swagger 文档的中间件和使用这个 JSON 暴露 swagger-ui 的中间件。 你可以通过 “Swashbuckle.AspNetCore” 包一起下载这些包或根据自己的需要独立下载。详细说明如下表所示

Package Description
Swashbuckle.AspNetCore.Swagger 用一个 JSON API 暴露 SwaggerDocument 对象。在返回一个序列化的 JSON 之前,这个包需要注册一个 ISwaggerProvider 的实现用于生成 Swagger 文档
Swashbuckle.AspNetCore.SwaggerGen 用于注入第一个组件需要的 ISwaggerProvider 的实现。这个特定的实现可以用你的路由(routes)、控制器(controllers)和模型(models)自动生成 Swagger 文档
Swashbuckle.AspNetCore.SwaggerUI 暴露一个嵌入版本的 swagger-ui。你可以指定 ui 从哪个 API 获取Swagger JSON,然后 ui 会使用 JSON 生成交互式文档

配置 & 自定义

Swashbuckle.AspNetCore.Swagger

修改 Swagger JSON 路径

Swagger JSON 默认暴露在 /swagger/{documentName}/swagger.json 路径下。在启用中间件时我们可以自行修改这个路径。自定义的路径必须包含 {documentName} 字段。

1
2
3
4
app.UseSwagger(c =>
{
c.RouteTemplate = "api-docs/{documentName}/swagger.json";
});

NOTE: 如果同时也使用了 SwaggerUI 中间件,那么我们还需要更新 Swagger UI 的配置:

1
2
3
4
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/api-docs/v1/swagger.json", "My API V1");
})

使用 HTTP 请求信息修改 Swagger

如果我们想使用当前请求的某些信息设置 Swagger metadata,那么可以注册一个过滤器。

1
2
3
4
app.UseSwagger(c =>
{
c.PreSerializeFilters.Add((swaggerDoc, httpReq) => swaggerDoc.Host = httpReq.Host.Value);
});

SwaggerDocument 和当前的 HttpRequest 都会被传递至过滤器。这个方法提供了很大的灵活性。例如你可以赋值给 host 属性(如上所示),你也可以检查 session 信息或者是 Authoriation header 来验证用户权限。

Swashbuckle.AspNetCore.SwaggerGen

列举 HTTP responses

Swashbuckle 默认会为所有方法生成 200 responses。如果这个方法返回一个 DTO,那么这个 DTO 将会被用来生成 HTTP responses body 的 schema,例如:

1
2
[HttpPost("{id}")]
public Product GetById(int id)

Will produce the following response metadata:

1
2
3
4
5
6
7
8
responses: {
200: {
description: "Success",
schema: {
$ref: "#/definitions/Product"
}
}
}

指定 HTTP responses

如果你想要指定一个状态码和/或其他 responses,或者需要返回的不是 DTO 而是 IActionResult_,你可以用 ASP.NET Core 中的 _ProducesResponseTypeAttribute 描述特定的 response,例如:

1
2
3
4
5
[HttpPost("{id}")]
[ProducesResponseType(typeof(Product), 200)]
[ProducesResponseType(typeof(IDictionary<string, string>), 400)]
[ProducesResponseType(typeof(void), 500)]
public IActionResult GetById(int id)

这种写法会得到的 response metadata:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
responses: {
200: {
description: "Success",
schema: {
$ref: "#/definitions/Product"
}
},
400: {
description: "Bad Request",
schema: {
type: "object",
additionalProperties: {
type: "string"
}
}
},
500: {
description: "Server Error"
}
}

使用 XML 注释生成描述

为了增强可读性,控制器和模型可以添加 XML 文档注释,并在注册 Swashbuckle 时将这些注释包含进 Swagger JSON:

  1. 打开项目的“属性”选项,选择“生成”标签页并勾上“ XML 文档文件”。然后当你生成项目时可以它会自动生成一个包含所有 XML 注释的文件。

    此时如果某个类或方法没有使用 XML 注释,那么会产生一个生成警告。如果想要去掉这个警告,在此页的“禁止显示警告”选项中添加警告码“1591”即可。

  2. 在注册 Swashbuckle 时引用 XML 注释文件来生成 Swagger JSON:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    services.AddSwaggerGen(c =>
    {
    c.SwaggerDoc("v1",
    new Info
    {
    Title = "My API - V1",
    Version = "v1"
    }
    );

    var filePath = Path.Combine(PlatformServices.Default.Application.ApplicationBasePath, "MyApi.xml");
    c.IncludeXmlComments(filePath);
    }
  3. 方法注释应当有 summary、 remarks 和 response 标签。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /// <summary>
    /// Retrieves a specific product by unique id
    /// </summary>
    /// <remarks>Awesomeness!</remarks>
    /// <response code="200">Product created</response>
    /// <response code="400">Product has missing/invalid values</response>
    /// <response code="500">Oops! Can't create your product right now</response>
    [HttpGet("{id}")]
    [ProducesResponseType(typeof(Product), 200)]
    [ProducesResponseType(typeof(IDictionary<string, string>), 400)]
    [ProducesResponseType(typeof(void), 500)]
    public Product GetById(int id)
  4. 重新生成项目,XML 注释文件会被更新。你可以打开 Swagger JSON 页面看看这些注释是怎么映射进对应的 Swagger 文档的。

注:你也可以通过给 model 以及它们的属性添加 summary 标签的方式生成 Swagger 文档。如果你有多个 XML 注释文件(例如控制器和 model 是独立的类库),你可以多次调用 IncludeXmlComments 方法,他们会被合并进输出的 Swagger JSON.

提供全局 API Metadata

除了 Paths_, _Operations 和 _Responses_,Swashbuckle 还提供了全局 metadata (详见 http://swagger.io/specification/#swaggerObject)。例如,你可以为你的 API、服务项、甚至是联系方式和证书信息提供一个完整的描述:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
c.SwaggerDoc("v1",
new Info
{
Title = "My API - V1",
Version = "v1",
Description = "A sample API to demo Swashbuckle",
TermsOfService = "Knock yourself out",
Contact = new Contact
{
Name = "Joe Developer",
Email = "joe.developer@tempuri.org"
},
License = new License
{
Name = "Apache 2.0",
Url = "http://www.apache.org/licenses/LICENSE-2.0.html"
}
}
)

使用 IntelliSense 可以看到哪些字段是可用的。

未完待更。