WebApi的多版本管理
1.多版本管理概念
什么是API的多版本问题?Android等App存在着多版本客户端共存的问题:由于早期没有内置升级机制,用户不会升级,拒绝升级等原因,造成了许多软件的旧版本App也在运行。开发新版本App时,要给接口增加新的功能或者修改以前接口的规范,会造成旧版本App无法使用,因此再一定情况下会“保留旧接口的运行,新功能用新接口”,这样就会存在多版本接口共存的问题。
2.解决方式
1.不同版本用不同的域名:v1.api.rsfy.com、v2.api.rsfy.com、v3……;
2.在Url,报文头等中带不同的版本信息,用Nginx等做反向代理服务,然后将 http://api.rsfy.com/api/v1/User/1和http://api.rsfy.com/api/v2/User/1 转到不同的服务器处理
3.多个版本的Controller共处在一个项目中,然后使用[RoutePrefix]或者IHttpControllerSelector根据报文头,路径等选择不同的Controller执行
下面以第三个种记录一个例子
3.解决例题
创建一个WebApi项目,在Controllers中创建各个版本的目录

然后我们在每个版本下创建一个Home控制器

public class HomeController : ApiController
{
[HttpGet]
public String GetIndex()
{
return "这是v1版本的Index";
}
}
public class HomeController : ApiController
{
[HttpGet]
public String GetIndex()
{
return "这是v2版本的Index";
}
}
正常情况下,我们是不可以在Controllers中创建目录的,这不符合约定,所以我们必须改写其中代码,让其根据我们需求来选择控制器。
下面我们创建一个我们自己的IHttpControllerSelector的实现类来替换默认的IHttpControllerSelector。
/// <summary>
/// 自己实现IHttpControllerSelector来替换默认IHttpConllerSelector
/// </summary>
public class VersionConstrollerSelector : IHttpControllerSelector
{
private readonly HttpConfiguration _conf;
public VersionConstrollerSelector(HttpConfiguration configuration)
{
_conf = configuration;
} public IDictionary<string, HttpControllerDescriptor> GetControllerMapping()
{
throw new NotImplementedException();
} public HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
throw new NotImplementedException();
}
}
IHttpControllerSelector接口有两个方法,
GetControllerMapping():获取程序中所有的Api接口
SelectController(HttpRequestMessage request):匹配请求的路由
下面我们来重写这两个方法
/// <summary>
/// 获取所有Controller
/// </summary>
/// <returns></returns>
public IDictionary<string, HttpControllerDescriptor> GetControllerMapping()
{
Dictionary<String, HttpControllerDescriptor> dict = new Dictionary<string, HttpControllerDescriptor>();
foreach (var item in _conf.Services.GetAssembliesResolver().GetAssemblies())
{//循环所有程序集
//获取所有继承自ApiController的非抽象类
var controllerTypes = item.GetTypes()
.Where(y => !y.IsAbstract && typeof(ApiController)
.IsAssignableFrom(y)).ToArray();
foreach (var ctrlType in controllerTypes)
{//循环程序集中类型
//从namespace中提取出版本号
var match = Regex.Match(ctrlType.Namespace,GetType().Namespace+ @".Controllers.v(\d+)");
if(match.Success)
{//匹配成功
//获取版本号
string verNum = match.Groups[].Value;
//从控制器总名称中拿到控制器名称(例: HomeController中获取Home)
string ctrlName = Regex.Match(ctrlType.Name, "(.+)Controller").Groups[].Value;
//声明集合中的键
String key = (ctrlName + "v" + verNum).ToLower();
//存储集合值(控制器信息)
dict[key] = new HttpControllerDescriptor(_conf, ctrlName, ctrlType);
}
}
}
return dict;
}
/// <summary>
/// 进行匹配Controller
/// </summary>
/// <param name="request">http请求信息</param>
/// <returns>匹配成功返回控制器信息,匹配失败返回null</returns>
public HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
//获取所有的Controller集合
var controllers = GetControllerMapping();
//获取路由数据
var routeData = request.GetRouteData();
//从路由中获取当前controller的名称
var controllerName = routeData.Values["Controller"] as String;
//如果请求头中存在ApiVerson信息则总其中获取版本号否则从url中获取版本号
var verNum = request.Headers.TryGetValues("ApiVerson", out var versions) ?
versions.Single() :
Regex.Match(request.RequestUri.PathAndQuery, @"api/v(\d+)").Groups[].Value; //获取版本号
var key = (controllerName + "v" + verNum).ToLower();//获取Personv2
//返回控制器信息
return controllers.ContainsKey(key) ? controllers[key] : null; }
现在我们这个类实现完成以后我们便可以在WebApiConfig类中的Register方法中替换原来的IHttpControllerSelector
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API 配置和服务
//替换HttpControllerSelector
config.Services.Replace(typeof(IHttpControllerSelector), new VersionConstrollerSelector(config)); }
}
并且在其方法创建新的路由
public static void Register(HttpConfiguration config)
{// Web API 路由
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApiv1",
routeTemplate: "api/v1/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }); config.Routes.MapHttpRoute(
name: "DefaultApiv2",
routeTemplate: "api/v2/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApiv3",
routeTemplate: "api/v3/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
至此,我们便成功的以替换IHttpControllerSelector方式来完成了多版本管理


WebApi的多版本管理的更多相关文章
- Web API的参数、多版本和Filter
一.关于API的参数a) Web API在WebApiConfig.cs中配置了路由模板,默认为"api/{controller}/{id}",这与MVC路由模板的区别在于没有{a ...
- 第十一节:WebApi的版本管理的几种方式
一. 背景和方案 1. 多版本管理的概念 Android .IOS等 App 存在着多版本客户端共存的问题:App 最新版已经升级到了5.0 了,但是有的用户手机上还运行着 4.8.3.9 甚至2.2 ...
- 4.C#WebAPI多版本管理介绍及实现方案详解
1.什么是 API 的多版本? 说白了就是多版本共存的问题.为方便大家理解我就举个例子吧,大家想必都用过Jquery吧,它的1.*版本做到了对低版本IE的支持:2.*版本还保留着ajax,但是不再支持 ...
- WebApi系列(从.Net FrameWork 到 .Net Core)
一. 简介 1. 什么是WebApi? WebApi是一个很广泛的概念,在这里我们特指.Net平台下的Asp.Net WebApi框架,它是针对各种客户端(浏览器.APP等)来构建Http服务的一个 ...
- 基于 Kong 和 Kubernetes 的 WebApi 多版本解决方案
前言 大家好,很久没有写博客了,最近半年也是比较的忙,所以给关注我的粉丝们道个歉.去年和朱永光大哥聊的时候提了一下我们的这个方案,他说让我有空写篇博客讲一下,之前是非常的忙,所以这次趁着有些时间就写一 ...
- ASP.NET Core WebApi版本控制
前言: 在日常项目开发中,随着项目需求不断的累加.不断的迭代:项目服务接口需要向下兼容历史版本:前些时候就因为Api接口为做版本管理导致接口对低版本兼容处理不友好. 最近就像了解下如何实现WebApi ...
- webapi - 使用依赖注入
本篇将要和大家分享的是webapi中如何使用依赖注入,依赖注入这个东西在接口中常用,实际工作中也用的比较频繁,因此这里分享两种在api中依赖注入的方式Ninject和Unity:由于快过年这段时间打算 ...
- ASP.NET Core MVC/WebAPi 模型绑定探索
前言 相信一直关注我的园友都知道,我写的博文都没有特别枯燥理论性的东西,主要是当每开启一门新的技术之旅时,刚开始就直接去看底层实现原理,第一会感觉索然无味,第二也不明白到底为何要这样做,所以只有当你用 ...
- Asp.Net WebApi核心对象解析(下篇)
在接着写Asp.Net WebApi核心对象解析(下篇)之前,还是一如既往的扯扯淡,元旦刚过,整个人还是处于晕的状态,一大早就来处理系统BUG,简直是坑爹(好在没让我元旦赶过来该BUG),队友挖的坑, ...
随机推荐
- Java中常用加减密方式
1.加密概述: 加密就是是以某种特殊的算法改变原有的信息数据,使得未授权的用户即使以获得了加密的信息,但因不知解密方式,仍无法了解信息的内容.大体上又分为双向加密和单向加密. 2.单项加密 2.1.概 ...
- 《用Java写一个通用的服务器程序》02 监听器
在一个服务器程序中,监听器的作用类似于公司前台,起引导作用,因此监听器花在每个新连接上的时间应该尽可能短,这样才能保证最快响应. 回到编程本身来说: 1. 监听器最好由单独的线程运行 2. 监听器在接 ...
- 邻里街坊 golang入坑系列
如果要追新或者怀旧,就点击https://andy-zhangtao.gitbooks.io/golang/content/ . 博客园里面的文章基本和gitbook上面是保持同步的. 这几天看了几集 ...
- 简单的OC程序
知识点 1.#import的用途: 1> 跟#include一样,拷贝文件的内容 2> 可以自动防止文件的内容被重复拷贝 2.#import <Foundation/NSObjCRu ...
- 将百度的ECharts整合到阿里的Weex中。
由于公司的业务,之前PC版产品中,大量的使用了百度的ECharts库.所以现在要做移动端,在大概熟悉了Weex基本语法和搭建环境后,就着手研究如何将这两个好东西糅合起来. 首先,按照Weex官方教程, ...
- WEB漏洞攻击之验证码绕过浅析
最近安全部门对WEB系统进行了一次漏洞整改,发现了某个系统存在验证码绕过风险. 根据安全部门提供的信息,该漏洞构造场景是通过一层中间代理(Burpsuite Proxy)拦截客户端与服务端的请求,通过 ...
- hdu 1150 Machine Schedule 最小覆盖点集
题意:x,y两台机器各在一边,分别有模式x0 x1 x2 ... xn, y0 y1 y2 ... ym, 现在对给定K个任务,每个任务可以用xi模式或者yj模式完成,同时变换一次模式需要重新启动一次 ...
- cookie解决跨域问题
v一.前言 随着项目模块越来越多,很多模块现在都是独立部署.模块之间的交流有时可能会通过cookie来完成.比如说门户和应用,分别部署在不同的机器或者web容器中,假如用户登陆之后会在浏览器客户端写入 ...
- PHP面向对象-----魔术方法
PHP面向对象-----魔术方法 __get($name)--触发时机:当调用一个不访问的成员属性的时候,会自动触发,可以利用这个方法来完成对不可调用的属性进行调用,但是不能设置值 ___set($n ...
- 《RabbitMQ Tutorial》译文 第 3 章 发布和订阅
原文来自 RabbitMQ 英文官网的教程(3.Publish and Subscribe),其示例代码采用了 .NET C# 语言. In the previous tutorial we crea ...