首页 > 其他分享 >.NET 6当中的Web API版本控制

.NET 6当中的Web API版本控制

时间:2022-09-21 09:01:56浏览次数:89  
标签:Web 版本控制 description public API 版本 NET 我们

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

为了了解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包:

dotnet add package Microsoft.AspNetCore.Mvc.Versioning
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头部的特性:

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

我们添加了一个ApiVersion特性,并指定版本号,更新Route为动态API版本,所有继承该基类的控制器都会标记上版本号。
我们还可以通过Deprecated来弃用WeatherForecast接口:

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

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

namespace Travel.WebApi.Controllers.v2 {     
  [ApiVersion("2.0")]     
  [ApiController]     
  [Route("api/v{version:apiVersion}/[controller]")]     
  public class WeatherForecastController : ControllerBase     
  {       
    …         
    [HttpPost]         
    public IEnumerable<WeatherForecast> Post(string city) {     
      var rng = new Random();             
      return Enumerable.Range(1,5).Select(index => new WeatherForecast
      {                 
        …                 
        City = city}).ToArray();
      }     
  } 
}

新旧接口的主要区别是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如下所示:

using System; 
using Microsoft.AspNetCore.Mvc.ApiExplorer; 
using Microsoft.Extensions.DependencyInjection; 
using Microsoft.Extensions.Options; 
using Microsoft.OpenApi.Models; 
using Swashbuckle.AspNetCore.SwaggerGen; 
namespace IoT.WebApi.OpenApi {     
public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions>  
{ 
  …  
  public void Configure(SwaggerGenOptions options) {…}         
  private static OpenApiInfo CreateInfoForApiVersion (ApiVersionDescription description) {…}     
  } 
}

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

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

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

private static OpenApiInfo CreateInfoForApiVersion(ApiVersionDescription description)
{
    var info = new OpenApiInfo
    {
        Title = "Travel Tour",
        Version = description.ApiVersion.ToString(),
        Description = "Web Service for Travel Tour.",
        Contact = new OpenApiContact
        {
            Name = "IT Department",
            Email = "[email protected]",
            Url = new Uri("https://traveltour.xyz/support")
        }
    };
 
    if (description.IsDeprecated)
        info.Description += " <strong>This API version of Travel Tour has been deprecated.</strong>";
    return info;
}

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

public class SwaggerDefaultValues : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
           //
    }
}

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

var apiDescription = context.ApiDescription;
operation.Deprecated |= apiDescription.IsDeprecated();
 
if (operation.Parameters == null)
    return;
 
foreach (var parameter in operation.Parameters)
{
    var description = apiDescription.ParameterDescriptions.First(
        pd => pd.Name == parameter.Name);
 
    parameter.Description ??= description.ModelMetadata.Description;
 
    if (parameter.Schema.Default == null && description.DefaultValue != null)
        parameter.Schema.Default = new OpenApiString(description.DefaultValue.ToString());
 
    parameter.Required |= description.IsRequired;
}

Apply方法允许Swagger生成器添加API资源管理器的所有相关元数据。
接下来我们更新一下Startup.cs文件,在ConfigureServices中找到AddSwageGen方法,然后使用下面代码进行替换:

services.AddSwaggerGen(c =>
{
    c.OperationFilter<SwaggerDefaultValues>();
});

这里使用过滤器配置我们之前创建的SwaggerDefaultValue。接下来在AddSwaggerGen方法后面给ConfigureSwaggerOptions设置服务生命周期:
services.AddTransient<IConfigureOptions, ConfigureSwaggerOptions>();
我们还要添加对ApiVersioning的注册(Microsoft.AspNetCore.Mvc.Versioning):

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

上面的代码在服务集合中添加了版本控制,包括定义默认API版本和API支持的版本。
我们继续在AddApiVersioning下面添加API Explorer(Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer):

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

该代码添加了一个API资源管理器,它的格式:'v'major[.minor][status] 。
现在在Configure方法中添加一个参数。将其命名为provider,类型为IApiVersionDescriptionProvider,如下所示:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IApiVersionDescriptionProvider provider)
这里涉及到的是有关API版本的信息,我们看下Configure中的UseSwaggerUI方法:

app.UseSwaggerUI(c =>
{
    foreach (var description in provider.ApiVersionDescriptions)
    {
        c.SwaggerEndpoint(
            $"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
    }
});

以上通过循环为每个发现的API版本构建一个Swagger访问地址。
现在,让我们运行程序并查看代码的结果。让我们看看Swagger UI,WeatherForecast的测试版本1 API和版本2 的API,看看如果我们发送请求,它们是否正常工作。您可以在下面的截图中看到效果,我们可以选择要检查的API版本:

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

而v2版本是正常的:

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

标签:Web,版本控制,description,public,API,版本,NET,我们
From: https://www.cnblogs.com/jackyfei/p/16710817.html

相关文章

  • dotnet 解析 TTF 字体文件格式
    在Windows下,可以使用DX提供的强大能力,调用DX读取TTF字体文件,获取字体文件的信息以及额外的渲染信息。特别是基于DX的WPF更是加了一层封装,使用FontFamily类型......
  • dotnet 使用 ConfigureAwait.Fody 库设置默认的 await 同步上下文切换配置
    在dotnet里面,使用await进行异步逻辑,默认是会尝试切换回调用await的线程同步上下文。这个机制对于大多数的上层应用来说都是符合逻辑且方便的逻辑,例如对于带UI线程......
  • dotnet 读 WPF 源代码笔记 为什么自定义的 UserControl 用户控件不能跨程序集继承
    从设计上,用户控件UserControl就不是一个合适用来多次继承的类型,更不要说进行跨程序集继承自定义的UserControl用户控件。对于大部分的用户控件来说,都是采用组合现有的......
  • dotnet 为大型应用接入 ApplicationStartupManager 启动流程框架
    对于大型的应用软件,特别是客户端应用软件,应用启动过程中,需要执行大量的逻辑,包括各个模块的初始化和注册等等逻辑。大型应用软件的启动过程都是非常复杂的,而客户端应用软件......
  • JavaWeb-SMBMS项目
    JavaWeb-SMBMS项目:学习视频-狂神说JavaWeb:视频链接JavaWeb-SMBMS项目一、SMBMSSMBMS模块数据库架构项目如何搭建?考虑是不是用maven?jar包,依赖二、项目搭建准备......
  • WEB自动化-08-Cypress 接口测试
    8接口测试  在服务和服务、系统和系统之间进行通信时,常常会使用到接口。通过接口测试,可以在项目早期更快发现问题。接口有很多类型,而现阶段使用的接口是基于HTTP协议......
  • Kubernetes(K8S)特性有哪些?
    Kubernetes简介Kubernetes是一个开源的,用于管理云平台中做个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单且高效,Kubernetes提供了应用部署,规划,更新......
  • web项目心得
    1、浏览器检查查看接口信息,发现看不到状态码等信息,则跨域失败了......
  • Net RunTIme Microsoft.Extensions.DependencyInjection 调试报错修复
       重新生成时直接报错,报错项目可直接找到,运行没问题。D:\SourceCode\Net\Runtime2\src\libraries\Common\tests\TestUtilities\TestUtilities.csproj//注释代码......
  • dotnet OpenXML 解析 PPT 图表 解析日期时间表示内容
    在OpenXML里的图表存放的日期时间很多存放的是数值,需要进行转换才能获取到用户可见的字符串日期在OpenXML里可以使用数值存放,需要根据数值和格式化字符串转换为用户可......