2020-12-23

博客园Logo
首页
新闻
博问
专区
闪存
班级

代码改变世界
搜索
注册
登录
返回主页
老王Plus的全栈
博客园 首页 新随笔 联系 订阅 管理随笔 - 34 文章 - 0 评论 - 115
Dotnet Core多版本API共存的优雅实现
API升级,新旧版本的API共存,怎么管理呢?

一、前言
最近,单位APP做了升级,同步的,API也做了升级。

升级过程中,出现了一点问题:API升级后,旧API也需要保留,因为有旧的APP还在使用中。

那么,API端如何作到多个版本共存呢?

为防止非授权转发,这儿给出本文的原文链接:https://www.cnblogs.com/tiger-wang/p/14167625.html

二、快速的解决办法
API的露出,是在API的Route定义中实现的。看下面的例子:

[Route(“api/[controller]”)]
public class DemoController : ControllerBase
{
[Route(“demo”)]
public ActionResult DemoFunc()
{
}
}
那我们知道,这个API的终结点是:/api/demo/demo。代码中[controller]是个可替换变量,编译时会替换为当前控制器的名称。

这个Route,里面的参数是个字符串,也就是说是可以随便换的。所以,对于多版本API,有个快速的办法,就是在里面做文章。

我们可以写成:

[Route(“api/v1/[controller]”)]
public class DemoController : ControllerBase
{
[Route(“demo”)]
public ActionResult DemoFunc()
{
}
}
或者

[Route(“api/[controller]”)]
public class DemoController : ControllerBase
{
[Route(“v1/demo”)]
public ActionResult DemoFunc()
{
}
}
这样就区分出了版本号。

当然,这样做比较LOW,因为版本号是硬编码在代码中的。而且,这个改动会影响到API的终结点,例如上面两个变化,会让终结点变为:/api/v1/demo/demo和/api/demo/v1/demo。如果前端可以方便修改,也算是一个方法。但对于我们APP已经上线运行来说,这个改动无法接受。

三、优雅的解决办法
这个方案,才是今天要说的核心内容。

首先,我们需要从Nuget上引入两个库:

% dotnet add package Microsoft.AspNetCore.Mvc.Versioning
% dotnet add package Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer
这两个库,Versioning用来实现API的版本控制,Versioning.ApiExplorer用来实现元数据的发现工作。

引入完成后,修改Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
services.AddApiVersioning(options =>
{
options.DefaultApiVersion = new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
options.ReportApiVersions = true;
});

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

services.AddControllers();

}
就可以了。

这里面用了两个配置:AddApiVersioning,主要用来配置向前兼容,定义了如果没有带版本号的访问,会默认访问v1.0的接口。AddVersionedApiExplorer用来添加API的版本管理,并定义了版本号的格式化方式,以及兼容终结点上带版本号的方式。

到这儿,引入版本管理的工作就完成了。

使用时,就直接在控制器或方法上定义版本号:

[ApiVersion(“1”)]
[Route(“api/[controller]”)]
public class DemoController : ControllerBase
{
[MapToApiVersion(“2”)]
[Route(“demo”)]
public ActionResult DemoFunc()
{
}
}
这里面,又是两个属性:ApiVersion定义控制器提供哪个版本的API。这个属性可以定义多个。例如,我们控制器里既有v1的API,也有v2的API,我们可以写成:

[ApiVersion(“1”)]
[ApiVersion(“2”)]
[Route(“api/[controller]”)]
public class DemoController : ControllerBase
{
}
MapToApiVersion是API的版本定义,定义我们这个API是哪一个版本。

方法就这么简单。其它的,微软都帮我们做好了。

那,通常我们会用Swagger来做API文档。这个方法如何跟Swagger配合呢?

四、与Swagger的配合
Swagger也来自于Nuget的引用:

% dotnet add package swashbuckle.aspnetcore
引用后,通常我们Startup.cs里的配置是这样的:

public void ConfigureServices(IServiceCollection services)
{
services.AddSwaggerGen(option =>
{
option.SwaggerDoc(“v1”, new OpenApiInfo { Title = “Demo”, Version = “V1” });
});

services.AddControllers();

}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseSwagger();
app.UseSwaggerUI(option =>
{
option.SwaggerEndpoint("/swagger/v1/swagger.json", “Demo”);
});

}

API多版本管理与Swagger配合,也有一个快速但比较LOW的方法:

public void ConfigureServices(IServiceCollection services)
{
services.AddSwaggerGen(option =>
{
option.SwaggerDoc(“v1”, new OpenApiInfo { Title = “Demo”, Version = “V1” });
option.SwaggerDoc(“v1”, new OpenApiInfo { Title = “Demo”, Version = “V2” });

});

services.AddControllers();

}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseSwagger();
app.UseSwaggerUI(option =>
{
option.SwaggerEndpoint("/swagger/v1/swagger.json", “Demo V1”);
option.SwaggerEndpoint("/swagger/v2/swagger.json", “Demo V2”);
});
}
这个方法也可以快速实现,不过跟上边的情况一样,版本号是硬编码的。

其实,也有另一个比较优雅的方式,就是手动实现IConfigureOptions和过滤IOperationFilter。

先看Startup.cs里:

public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IConfigureOptions, ConfigureSwaggerOptions>();
services.AddSwaggerGen(options => options.OperationFilter());

services.AddControllers();

}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseSwagger();
app.UseSwaggerUI(option =>
{
foreach (var description in provider.ApiVersionDescriptions)
{
c.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
}
});
}
这里加了两个类,第一个ConfigureSwaggerOptions:

internal class ConfigureSwaggerOptions : IConfigureOptions
{
private readonly IApiVersionDescriptionProvider _provider;
public ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider) => _provider = provider;

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

private OpenApiInfo CreateInfoForApiVersion(ApiVersionDescription description)
{
    var info = new OpenApiInfo()
    {
        Title = "Demo API",
        Version = description.ApiVersion.ToString(),
    };

    if (description.IsDeprecated)
    {
        info.Description += " 方法被弃用.";
    }

    return info;
}

}
第二个SwaggerDefaultValues:

internal class SwaggerDefaultValues : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var apiDescription = context.ApiDescription;
operation.Deprecated |= apiDescription.IsDeprecated();

	    if (operation.Parameters == null)
        return;

	    foreach (var parameter in operation.Parameters)
	    {
        var description = apiDescription.ParameterDescriptions.First(p => p.Name == parameter.Name);
        if (parameter.Description == null)
        {
            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;
    }
}

}
代码不一行行解释了,都是比较简单的。

运行,进入Swagger界面,右上角Select a definition,可以选择我们定义的版本号。

今天的配套代码已上传到Github,位置在:https://github.com/humornif/Demo-Code/tree/master/0035/demo

微信公众号:老王Plus

扫描二维码,关注个人公众号,可以第一时间得到最新的个人文章和内容推送

本文版权归作者所有,转载请保留此声明和原文链接

分类: .Net core
标签: dotnet core, c#
好文要顶 关注我 收藏该文
老王Plus
关注 - 3
粉丝 - 53
+加关注
3 0
« 上一篇: 一文说通C#中的异步迭代器
posted @ 2020-12-23 09:17 老王Plus 阅读(317) 评论(2) 编辑 收藏

评论列表
#1楼 2020-12-23 09:40 mrfangzheng
有2种方式,
[1] 客户端URL主动指定服务端API版本号(比如v1,v2)
[2 ]客户端请求头header中带有客户端版本号(比如1.0.2.1, 1.0.3.188).
第二种情况下, 服务端根据客户端版本来判断调哪个API, 感觉更灵活.
支持(0) 反对(0)
#2楼 [楼主] 2020-12-23 10:49 老王Plus
@mrfangzheng
有2种方式,
[1] 客户端URL主动指定服务端API版本号(比如v1,v2)
[2 ]客户端请求头header中带有客户端版本号(比如1.0.2.1, 1.0.3.188).
第二种情况下, 服务端根据客户端版本来判断调哪个API, 感觉更灵活.
这是一个理论上的理想状态,但实际开发的时候一般不会这么做。API版本升级来自于业务升级,是先有的业务升级,才有API升级,然后才是APP升级。如果能提前规划到API版本的升级,这倒是个好想法。
支持(0) 反对(0)
刷新评论刷新页面返回顶部
登录后才能发表评论,立即 登录 或 注册, 访问 网站首页
写给园友们的一封求助信
【推荐】News: 大型组态、工控、仿真、CADGIS 50万行VC++源码免费下载
【推荐】有你助力,更好为你——博客园用户消费观调查,附带小惊喜!
【推荐】博客园x丝芙兰-圣诞特别活动:圣诞选礼,美力送递
【推荐】了不起的开发者,挡不住的华为,园子里的品牌专区
【福利】AWS携手博客园为开发者送免费套餐+50元京东E卡
【推荐】未知数的距离,毫秒间的传递,声网与你实时互动
【推荐】新一代 NoSQL 数据库,Aerospike专区新鲜入驻

相关博文:
· 2019-11-29-dotnet-core-使用-GBK-编码
· dotnetcore2.2在linux下不支持画图
· Docker简单发布dotnetcore项目文本版
· 【ASP.NETCore学习】WebAPI
· Docker简单发布dotnetcore项目图文版
» 更多推荐…

最新 IT 新闻:
· 四周都是“气氛组”,只有你是傻白甜
· 让神经网络给符号AI“打工”,MIT和IBM联合解决深度学习痛点,未来将用于自动驾驶
· 互联网存款产品48小时集体下架 原因定性:“无照驾驶”非法金融活动
· NASA开放新发射台,支持小型运载火箭发射客户
· 花12亿买和解!瑞幸咖啡未来何解?律师:不排除重新上市
» 更多新闻…
公告

昵称: 老王Plus
园龄: 4年9个月
粉丝: 53
关注: 3
+加关注
< 2020年12月 >
日 一 二 三 四 五 六
29 30 1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31 1 2
3 4 5 6 7 8 9
搜索

找找看

谷歌搜索
常用链接

我的随笔
我的评论
我的参与
最新评论
我的标签
我的标签

dotnet core(28)
c#(8)
mongodb(7)
架构(6)
debian(5)
dotnet(4)
设计模式(4)
异步(3)
安装(2)
k8s(2)
更多
随笔分类

.Net core(31)
Blazor(1)
Debian(5)
Kubernetes(2)
Mono(2)
MonogDB(7)
Python(1)
机器学习(1)
架构(6)
区块链(1)
项目管理(1)
随笔档案

2020年12月(3)
2020年11月(3)
2020年10月(2)
2020年9月(4)
2020年8月(4)
2020年7月(4)
2020年6月(4)
2020年5月(6)
2020年4月(3)
2016年3月(1)
最新评论

  1. Re:Dotnet Core多版本API共存的优雅实现
    @mrfangzheng 有2种方式, [1] 客户端URL主动指定服务端API版本号(比如v1,v2) [2 ]客户端请求头header中带有客户端版本号(比如1.0.2.1, 1.0.3.188)…
    –老王Plus

  2. Re:Dotnet Core多版本API共存的优雅实现
    有2种方式, [1] 客户端URL主动指定服务端API版本号(比如v1,v2) [2 ]客户端请求头header中带有客户端版本号(比如1.0.2.1, 1.0.3.188). 第二种情况下, 服务端…
    –mrfangzheng

  3. Re:Dotnet Core下的Channel, 你用了吗?
    又学到了新的知识
    –鑫神

  4. Re:Dotnet Core下的Channel, 你用了吗?
    跟队列有什么区别? 优劣势分析一下呗
    –提伯斯

  5. Re:Dotnet Core下的Channel, 你用了吗?
    内置的生产者,消费者模式
    –说书的猫
    阅读排行榜

  6. 一文说通C#中的异步编程(2400)

  7. .Net Core实现区块链初探(1813)

  8. Dotnet core使用JWT认证授权最佳实践(一)(1689)

  9. 15分钟从零开始搭建支持10w+用户的生产环境(四)(1669)

  10. 15分钟从零开始搭建支持10w+用户的生产环境(二)(1505)
    评论排行榜

  11. 一文说通C#中的异步编程(14)

  12. .Net Core实现区块链初探(13)

  13. Dotnet Core下的Channel, 你用了吗?(12)

  14. Dotnet Core Public API的安全实践(11)

  15. C#实践设计模式原则SOLID(6)
    推荐排行榜

  16. 一文说通C#中的异步编程(25)

  17. .Net Core实现区块链初探(23)

  18. C#实践设计模式原则SOLID(13)

  19. 一文说通C#中的异步编程补遗(11)

  20. 一文说通C#中的异步迭代器(10)
    Copyright © 2020 老王Plus
    Powered by .NET 5.0.1-servicing.20575.16 on Kubernetes

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值