• 4.C#WebAPI多版本管理介绍及实现方案详解


    1.什么是 API 的多版本?

    说白了就是多版本共存的问题。为方便大家理解我就举个例子吧,大家想必都用过Jquery吧,它的1.*版本做到了对低版本IE的支持;2.*版本还保留着ajax,但是不再支持老旧浏览器;3.*版本连ajax都不留了;但是用户不会升级、用户拒绝升级等原因,造成这些旧版本也需要运行,但是新版却已经修改了规范与旧版旧版冲突了。造成这些旧版本也需要运行使用。再例如我们手机有Android4.0、5.0、6.0、7.0、8.0或IOS8.0、9.0、10、11同时存在于市场也是类似的。

    2.出现多版本问题我们通常的做法

    旧版接口做成一个分支,除了进行 bug 修改外,旧版本接口不再做改动;新接口代码继续演化升级。在客户端请求的时候带着要请求的接口版本号,在服务器端选择合适的版本代码进行处理。

    3.技术处理方案

    (1)(最推荐)不同版本用不同的域名:v1.api.jiyuwu.com、v2.api.jiyuwu.com、v3……。

    (2) 在url、报文头等中带不同的版本信息,用 Nginx 等做反向代理服务器,然后将 http://api.jiyuwu.com/api/V1/Login/1和http://api.jiyuwu.com/api/V2/Login/1转到不同的服务器处理。

    (3) 多 个 版 本 的 Controller 共 处 在 一 个 项 目 中 , 然 后 使 用 [RoutePrefix] 或 者 IHttpControllerSelector 根据报文头、路径等选择不同的 Controller 执行。下面主要讲这两种方法。

    4.针对3.(3)的两种方案的案例

     (1)[RoutePrefix] 案例

    旧版保持原样不改变

    public class LoginController : ApiController
        {
            [HttpGet]
            public string ToLogin(int id)
            {
                return "这是旧版" + id;
            }
    
        }
    View Code

    新版代码同时用路由处理

    [RoutePrefix("api/V2/Login")]
        public class LoginV2Controller : ApiController
        {
            [Route("{id}")]
            [HttpGet]
            public string ToLogin(int id)
            {
                return "这是新版" + id;
            }
        }
    View Code

    (2) IHttpControllerSelector 案例

    项目结构如图

    (1)添加VersionnControllerSelector类

    public class VersionnControllerSelector : DefaultHttpControllerSelector
        {
            public HttpConfiguration _config;
    
            public VersionnControllerSelector(HttpConfiguration config)
                : base(config)
            {
                _config = config;
            }
            public override IDictionary<string, System.Web.Http.Controllers.HttpControllerDescriptor> GetControllerMapping()
            {
                Dictionary<string, HttpControllerDescriptor> dic = new Dictionary<string, HttpControllerDescriptor>();
                foreach (var ams in _config.Services.GetAssembliesResolver().GetAssemblies())
                {
                    //获取继承自ApiControl的非抽象类
                    var controlTypes = ams.GetTypes().Where(p => !p.IsAbstract && typeof(ApiController).IsAssignableFrom(p)).ToArray();
                    foreach (var ctrlType in controlTypes)
                    {
                        //从namespace中提取出版本号
                        var match = Regex.Match(ctrlType.Namespace,
                        @"MoreVersionContorl.Controllers.V(d+)");
                        if (match.Success)
                        {
                            string verNum = match.Groups[1].Value;//获取版本号
                            string ctrlName =
                            Regex.Match(ctrlType.Name, "(.+)Controller").Groups[1].Value;//从LoginController中拿到Login
                            string key = ctrlName + "V" + verNum;//Personv2为key
                            dic[key] = new HttpControllerDescriptor(_config, ctrlName, ctrlType);
                        }
                    }
                }
                return dic;
            }
            public override System.Web.Http.Controllers.HttpControllerDescriptor SelectController(HttpRequestMessage request)
            {
                //获取所有Controller集合
                var controllers = GetControllerMapping();
                //获取路由数据
                var routeData = request.GetRouteData();
                //从路由中获取当前controller的名称
                var controllerName = (string)routeData.Values["controller"];
                //从url中获取到版本号
                string verNum =
                Regex.Match(request.RequestUri.PathAndQuery, @"api/V(d+)").Groups[1].Value;
                string key = controllerName + "V" + verNum;//获取Loginv2
                if (controllers.ContainsKey(key))//获取HttpControllerDescriptor
                {
                    return controllers[key];
                }
                else
                {
                    return null;
                }
            }
        }
    View Code

    (2)创建V1和V2下的两个控制器

    1) V1下的LoginController

     public class LoginController : ApiController
        {
            public string Get(int id)
            {
                return "This Version is V1,id=" + id;
            }
        }
    View Code

    2) V2下的LoginController

    public class LoginController : ApiController
        {
            public string Get(int id)
            {
                return "This Version is V2,id="+id;
            }
        }
    View Code

    (3)修改WebApiConfig

    public static void Register(HttpConfiguration config)
            {
                // Web API 配置和服务
    
                // Web API 路由
                config.MapHttpAttributeRoutes();
    
                //config.Routes.MapHttpRoute(
                //    name: "DefaultApi",
                //    routeTemplate: "api/{controller}/{id}",
                //    defaults: new { id = RouteParameter.Optional }
                //);
                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.Services.Replace(typeof(IHttpControllerSelector),
                new VersionnControllerSelector(config));
            }
    View Code

    (4)配置完毕请求结果如图:

  • 相关阅读:
    winform 异步更新ui
    定时器的写法 winform
    延迟加载
    使用VS分析程序性能
    win7 C/C++,QT安装环境总结
    论文总结
    天舟一号
    硬盘 SMART 检测参数详解[转]
    碧桃花
    在C的头文件中定义的结构体,如何在cpp文件中引用
  • 原文地址:https://www.cnblogs.com/jiyuwu/p/9213455.html
Copyright © 2020-2023  润新知