大家好,我是张飞洪,感谢您的阅读,我会不定期和你分享学习心得,希望我的文章能成为你成长路上的垫脚石,让我们一起精进。

为了了解ASP.NET Core Web API的版本控制,我们必须了解API中的一些版本控制策略,然后将API版本控制与OpenAPI集成,以便我们可以在Swagger UI中看到版本化的API。

1 版本控制及策略

1.1 什么是API版本控制?

API版本控制的目的是为了解决接口运维的问题。随着时间推移,我们希望对那些调用API的前端人员,都有一个固定不变的API调用规则和策略。因为需求会变化,业务会增长,如果我们对API的设计没有进行版本控制,那么依赖API的用户将变得无所适从,加上团队人员的变迁,这会大大降低我们的联调效率。

这就是我们为什么要进行API版本控制的目的所在。那么,我们如何对API进行版本化呢?

1.2 API版本控制策略

我们这里讨论三种最常用的API版本控制策略。

1)URI路径版本控制

URI路径策略很受欢迎,因为它更易于实现。一般我们会在URI路径的某个地方插入一个版本指示符,如v1或v2,如下所示:

https://iot.com/api/v1/products

以上是版本1,如果要升级为版本2,我们直接将v1改成v2即可:

https://iot.com/api/v2/products

注意在切换API版本时,为了获得正确的API返回的内容,原来的URI作为缓存键可能会失效。基于路径的版本控制很通用,几乎大部分的平台或者语言都支持这种方法,几乎成为了一种默认的标准,我们的案例代码默认也是采用这种策略。

2)Header版本控制

使用Header(头部)进行版本控制,头部一个谓词,并且有一个头部值,该值就是调用者需要分辨的版本号,如以下示例内容:

GET /api/products HTTP/1.1 Host: localhost:5001 Content-Type: application/json x-api-version: 2

此策略有个好处是它不会损坏URI。但是,在客户端使用这些类型的API会比较麻烦一些。

3)查询字符串版本控制

查询字符串(Query string)根据API的使用者的需要,使用查询字符串指定API的版本。,如果请求中没有查询字符串,则应该具有API的隐式默认版本。我们看一个示例:

https://iot.com/api/products?api-version=2

以上三种策略都有各自的使用场景,具体应该选择哪一个,取决于消费方法以及未来的规划。

1.3 废弃的API

我们可能会碰到一种需求,就是希望告知API调用方,哪些API不再推荐使用。比如一旦某个API版本在未来几个月没有人使用,我们希望删除该API:

[ApiVersion("1.0", Deprecated = true)]

具体使用很简单,这是Microsoft.AspNetCore.Mvc名称空间下的使用方式,凡是加上这种特性的API都会别废弃使用。

以上我们了解API版本控制的一些理论介绍,接下来我们通过代码来实现版本控制,以及如何将它们与OpenAPI集成方便在Swagger UI中查看。

2 API版本控制与OpenAPI的集成

2.1 API版本控制

本文是基于我视频的项目代码,所以在下面的代码连贯性上可能对您会有影响,但是整体上不影响您的理解。

如果您想查看完整的代码,可以订阅我的视频,不胜感觉。

为了通过代码实现版本控制,我们需要切换到Iot.WebApi项目下进行,我们先在该项目下安装两个NuGet包:

  1. dotnet add package Microsoft.AspNetCore.Mvc.Versioning
  2. dotnet add package Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer

第一个包是基于ASP.NET Core Mvc的版本服务,第二个包用于查找URL和HTTP方法、查找Controller(控制器)和Action元数据的一些功能。

接着,我们在Controller目录下创建两个文件夹,v1和v2,我们原先创建的控制器全部默认迁移到v1下,并修改一下相关的名称空间,原来是:

Iot.WebApi.Controllers

现在改成:

Iot.WebApi.Controllers.v1

然后,我们修改抽象基类ApiContoller头部的特性:

  1. [ApiVersion("1.0")]
  2. [ApiController]
  3. [Route("api/v{version:apiVersion}/[controller]")]
  4. public abstract class ApiController : ControllerBase
  5. {
  6. private IMediator _mediator;
  7. protected IMediator Mediator => _mediator ??= HttpContext.RequestServices.GetService<IMediator>();
  8. }

我们添加了一个ApiVersion特性,并指定版本号,更新Route为动态API版本,所有继承该基类的控制器都会标记上版本号。

我们还可以通过Deprecated来弃用WeatherForecast接口:

  1. namespace Travel.WebApi.Controllers.v1 {
  2. [ApiVersion("1.0", Deprecated = true)]
  3. public class WeatherForecastController : ApiController { …} }

废弃了一个接口,我们一般会创建一个新的接口版本,我们在v2文件夹下创建一个新的WeatherForecast.cs文件,代码如下所示:

  1. namespace Travel.WebApi.Controllers.v2 {
  2. [ApiVersion("2.0")]
  3. [ApiController]
  4. [Route("api/v{version:apiVersion}/[controller]")]
  5. public class WeatherForecastController : ControllerBase
  6. {

  7. [HttpPost]
  8. public IEnumerable<WeatherForecast> Post(string city) {
  9. var rng = new Random();
  10. return Enumerable.Range(1,5).Select(index => new WeatherForecast
  11. {

  12. City = city}).ToArray();
  13. }
  14. }
  15. }

新旧接口的主要区别是HTTP方法,在版本1中,必须发送一个GET请求以获取日期和温度数据,而在版本2中,必须使用查询参数city发送一个POST请求。

因此,API必须具有版本控制,以避免中断第一个版本的API导致的问题。

带有查询的POST请求不是好的做法,因为它是非幂等的,而GET、PUT和DELETE用于幂等请求。这里先将就用着。

2.2 OpenAPI

我们先在Iot.WebApi的根目录中创建一个新文件夹并命名为Helpers。然后创建两个C#文件,SwagerOptions.cs和SwaggerDefaultValue.cs,ConfigureSwaggerOptions.cs如下所示:

  1. using System;
  2. using Microsoft.AspNetCore.Mvc.ApiExplorer;
  3. using Microsoft.Extensions.DependencyInjection;
  4. using Microsoft.Extensions.Options;
  5. using Microsoft.OpenApi.Models;
  6. using Swashbuckle.AspNetCore.SwaggerGen;
  7. namespace IoT.WebApi.OpenApi {
  8. public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions>
  9. {

  10. public void Configure(SwaggerGenOptions options) {…}
  11. private static OpenApiInfo CreateInfoForApiVersion (ApiVersionDescription description) {…}
  12. }
  13. }

这里有两个方法:Configure和OpenApiInfo,下面是Configure方法的代码块:

  1. public void Configure(SwaggerGenOptions options)
  2. {
  3. foreach (var description in _provider.ApiVersionDescriptions)
  4. options.SwaggerDoc(description.GroupName, CreateInfoForApiVersion(description));
  5. }

Configure方法的作用是为每个新发现的API版本添加一个Swagger文档。下面是OpenApiInfo方法的代码块:

  1. private static OpenApiInfo CreateInfoForApiVersion(ApiVersionDescription description)
  2. {
  3. var info = new OpenApiInfo
  4. {
  5. Title = "Travel Tour",
  6. Version = description.ApiVersion.ToString(),
  7. Description = "Web Service for Travel Tour.",
  8. Contact = new OpenApiContact
  9. {
  10. Name = "IT Department",
  11. Email = "developer@traveltour.xyz",
  12. Url = new Uri("https://traveltour.xyz/support")
  13. }
  14. };
  15. if (description.IsDeprecated)
  16. info.Description += " <strong>This API version of Travel Tour has been deprecated.</strong>";
  17. return info;
  18. }

此代码用于Swagger相关信息设置,如应用程序的标题、版本、描述、联系人姓名、联系人电子邮件和URL。

我们再看下SwaggerDefaultValues.cs:

  1. public class SwaggerDefaultValues : IOperationFilter
  2. {
  3. public void Apply(OpenApiOperation operation, OperationFilterContext context)
  4. {
  5. //
  6. }
  7. }

SwaggerDefaultValues 会重写并替换Startup.cs中的services.AddSwaggerGen()。下面是Apply方法的代码:

  1. var apiDescription = context.ApiDescription;
  2. operation.Deprecated |= apiDescription.IsDeprecated();
  3. if (operation.Parameters == null)
  4. return;
  5. foreach (var parameter in operation.Parameters)
  6. {
  7. var description = apiDescription.ParameterDescriptions.First(
  8. pd => pd.Name == parameter.Name);
  9. parameter.Description ??= description.ModelMetadata.Description;
  10. if (parameter.Schema.Default == null && description.DefaultValue != null)
  11. parameter.Schema.Default = new OpenApiString(description.DefaultValue.ToString());
  12. parameter.Required |= description.IsRequired;
  13. }

Apply方法允许Swagger生成器添加API资源管理器的所有相关元数据。

接下来我们更新一下Startup.cs文件,在ConfigureServices中找到AddSwageGen方法,然后使用下面代码进行替换:

  1. services.AddSwaggerGen(c =>
  2. {
  3. c.OperationFilter<SwaggerDefaultValues>();
  4. });

这里使用过滤器配置我们之前创建的SwaggerDefaultValue。接下来在AddSwaggerGen方法后面给ConfigureSwaggerOptions设置服务生命周期:

services.AddTransient<IConfigureOptions, ConfigureSwaggerOptions>();

我们还要添加对ApiVersioning的注册(Microsoft.AspNetCore.Mvc.Versioning):

  1. services.AddApiVersioning(config =>
  2. {
  3. config.DefaultApiVersion = new ApiVersion(1, 0);
  4. config.AssumeDefaultVersionWhenUnspecified = true;
  5. config.ReportApiVersions = true;
  6. });

上面的代码在服务集合中添加了版本控制,包括定义默认API版本和API支持的版本。

我们继续在AddApiVersioning下面添加API Explorer(Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer):

  1. services.AddVersionedApiExplorer(options =>
  2. {
  3. options.GroupNameFormat = "'v'VVV";
  4. });

该代码添加了一个API资源管理器,它的格式:'v'major[.minor][status] 。

现在在Configure方法中添加一个参数。将其命名为provider,类型为IApiVersionDescriptionProvider,如下所示:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IApiVersionDescriptionProvider provider)

这里涉及到的是有关API版本的信息,我们看下Configure中的UseSwaggerUI方法:

  1. app.UseSwaggerUI(c =>
  2. {
  3. foreach (var description in provider.ApiVersionDescriptions)
  4. {
  5. c.SwaggerEndpoint(
  6. $"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
  7. }
  8. });

以上通过循环为每个发现的API版本构建一个Swagger访问地址。

现在,让我们运行程序并查看代码的结果。让我们看看Swagger UI,WeatherForecast的测试版本1 API和版本2 的API,看看如果我们发送请求,它们是否正常工作。您可以在下面的截图中看到效果,我们可以选择要检查的API版本:

我们可以看到v1和v2的WeatherForecast接口是不一样的,v1的版本被抛弃了,所以显示成灰色的。



而v2版本是正常的:



我们可以随便传入一个City参数,然后就可以看到返回记录了:

.NET 6当中的Web API版本控制的更多相关文章

  1. ****Web API 版本控制的几种方式

    个人建议:用content type,即放在Header里面!比如加一个Version:1.4.3 这篇文章写得很好,介绍了三种实现web api版本化的三种方式.我从评论里又收集到两种方式,所以一共 ...

  2. asp.net web api 版本控制

    版本控制   版本控制的方法有很多,这里提供一种将Odata与普通web api版本控制机制统一的方法,但也可以单独控制,整合控制与单独控制主要的不同是:整合控制通过VersionController ...

  3. ASP.NET Core Web API 版本控制

    在nuget.org上,您可以找到  Microsoft.AspNetCore.Mvc.Versioning包,它提供了有关如何对Web API端点进行版本化的更多选项.这个包的好处是允许你直接在控制 ...

  4. WEB API 版本控制

    参照 http://blog.csdn.net/hengyunabc/article/details/20506345

  5. ASP.NET Web API编程——版本控制

    版本控制   版本控制的方法有很多,这里提供一种将Odata与普通web api版本控制机制统一的方法,但也可以单独控制,整合控制与单独控制主要的不同是:整合控制通过VersionController ...

  6. API 版本控制的几种方式

    个人建议:用content type,即放在Header里面!比如加一个Version:1.4.3 这篇文章写得很好,介绍了三种实现web api版本化的三种方式.我从评论里又收集到两种方式,所以一共 ...

  7. List多个字段标识过滤 IIS发布.net core mvc web站点 ASP.NET Core 实战:构建带有版本控制的 API 接口 ASP.NET Core 实战:使用 ASP.NET Core Web API 和 Vue.js 搭建前后端分离项目 Using AutoFac

    List多个字段标识过滤 class Program{  public static void Main(string[] args) { List<T> list = new List& ...

  8. Web API 接口版本控制 SDammann.WebApi.Versioning

    前言 在设计对外 Web API 时,实务上可能会有新旧版本 API 并存的情况,例如开放 Web API 给厂商串接,但同一个服务更新版本时,不一定所有厂商可以在同一时间都跟着更新他们的系统,但如果 ...

  9. 如何设计出优美的Web API?

    概述 WEB API的应用场景非常丰富,例如:将已有系统的功能或数据开放给合作伙伴或生态圈:对外发布可嵌入到其他网页的微件:构建前后端分离的WEB应用:开发跨不同终端的移动应用:集成公司内部不同系统等 ...

随机推荐

  1. Java服务假死后续之内存溢出

    一.现象分析 上篇博客说到,Java服务假死的原因是使用了Guava缓存,30分钟的有效期导致Full GC无法回收内存.经过优化后,已经不再使用Guava缓存,实时查询数据.从短期效果来看,确实解决 ...

  2. 零基础学Java(4)字符串

    字符串 从概念上讲,Java字符串就是Unicode字符序列.例如,字符串"Java\u2122"由5个Unicode字符J.a.v.a和组成.Java没有内置的字符串类型,而是在 ...

  3. 绝对路径-相对路径和File类的构造方法

    绝对路径和相对路径 绝对路径:是一个完整的路径,以盘符开始(c: d:)c:\a.txt 相对路径:相对指的是相对于当前项目的根目录(可以省略项目的根目录) 注意: 1.路径不区分大小写 2.路径中的 ...

  4. C# 实例解释面向对象编程中的接口隔离原则

    在面向对象编程中,SOLID 是五个设计原则的首字母缩写,旨在使软件设计更易于理解.灵活和可维护.这些原则是由美国软件工程师和讲师罗伯特·C·马丁(Robert Cecil Martin)提出的许多原 ...

  5. 5-17 ELK 日志采集查询保存

    ELK简介 什么是ELK ELK: E:Elasticsearch 全文搜索引擎 L:logstash 日志采集工具 K:Kibana ES的可视化工具 ELK是当今业界非常流行的日志采集保存和查询的 ...

  6. nginx概述及配置

    Nginx是什么? Nginx是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器.因它的稳定性.丰富的功能集.示例配置文件和低系统资源的消耗而闻名.20 ...

  7. Python图像处理丨三种实现图像形态学转化运算模式

    摘要:本篇文章主要讲解Python调用OpenCV实现图像形态学转化,包括图像开运算.图像闭运算和梯度运算 本文分享自华为云社区<[Python图像处理] 九.形态学之图像开运算.闭运算.梯度运 ...

  8. Go语言基础五:引用类型-切片和映射

    切片 Go的数组长度不可以改变,在某些特定的场景中就不太适用了.对于这种情况Go语言提供了一种由数组建立的.更加灵活方便且功能强大的包装(Wapper),也就是切片.与数组相比切片的长度不是固定的,可 ...

  9. 1269: 求最长上升子序列(LIS)

     题目描述: LIS问题(longest increasing subsequence),即:最长上升子序列问题,是动态规划中一个比较经典的问题.具体描述为:一个有n个整数的序列:A[1],A[2], ...

  10. websocket理解

    简介 在实际开发中,可能会出现一个需求场景,要求网页的数据可以实时更新.在这种情况下,我们一般会采用轮询的方式,间隔性获取数据,即通过定时器间隔性请求相应接口获取数据,此方式由于是不断请求服务器,资源 ...