WebApi的Swagger多版本控制實現


WebApi + Swagger2.0接口文檔多版本控制設計實現

最近前后端分離的項目越來越多,API的對接對於前后端開發交流得最多的一塊內容,一個好的API文檔生成工具就顯得非常重要,選取了Swagger文檔生成工具作為項目的文檔生成工具,考慮到多版本的文檔生成,基於swagger5.6版本實現了一套多版本控制

 

1.  NuGet包引用

比較簡單,下面三個包都引用,刪掉自動生成的頁面文件,本此介紹多版本此處省略NuGet引入的文件清理工作了

 

2. 多版本控制

找到App_Start文件夾下面的SwaggerConfig,找到下圖的節點,默認是c.SingApiVersion生效,先注釋此行,再打開c.MultipleApiVersions勾子節點

 

此處有一個匿名方法調用ResolveVersionSupportByRouteConstraint,此方法需要自己實現,其中apiDesc是當前工程文件實現ApiController的全部路由數據,targetApiVersion是當前版本信息,直接在SwaggerConfig類中生成私有方法,我的實現如下,思路是在此處過濾掉非當前版本的Controller路由

 private static bool ResolveVersionSupportByRouteConstraint(ApiDescription apiDesc, string targetApiVersion)
        {
            //過濾由多版本的controller帶來的重復route注冊api desc,按命名空間的版本信息過濾,只返回版本內的api
            return apiDesc.ActionDescriptor.ControllerDescriptor.ControllerType.FullName.ToLower().Contains(string.Format(".{0}.", targetApiVersion));
        }

 

3. 路由文件版本分離規則

注意工程文件中Controllers的版本是通過命名空間隔離的,上面的代碼就是通過版本信息來匹配這個命名空間來實現過濾,假設v1和v2文件夾中都有ValuesController

 

兩個版本的ValuesController如下,route在Map時不能有重復名稱的Controller,所以此處采取加上版本,v1不需要添加,v2的ValuesController上加上版本, 借助RoutePrefix為ValuesV2Controller重寫路由,對外路由統一為api/{verstion}/Values並不會有ValuesV2出現在api路由上,此處的ValuesV2在文檔生成時還需要特殊處理,下面會重點提到IDocumentFilter接口實現時的處理

 

4. 多版本路由注冊

此時在WebApiConfig的路由注冊中寫下如下代碼,分別注冊兩個版本的路由對應v1,v2版本

config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/v1/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional}
            );

            config.Routes.MapHttpRoute(
                name: "Apiv2",
                routeTemplate: "api/v2/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
                );

 

5. IDocumentFilter接口實現

多版本的控制到這就算基本實現了,只不過ValuesV2這個路由的文檔中依然會帶上這個V2, 由於我們在RoutePrefix中已經配置了V2的Values路由是api/v2/Values,但按路由注冊規則文檔生成的路由默認會是api/v2/ValuesV2, 如果按文檔生成的路徑調用時會報找不到文件,原因就是RoutePrefix生效的路由與Swagger文檔路由不匹配,好在Swagger提供的過濾接口能幫助我們自定義過濾規則,在SwaggerConfig中找到如下節點,打開注釋,其中ApplyDocumentVendorExtensions需要我們自己實現

c.DocumentFilter<ApplyDocumentVendorExtensions>();

 

實現IDocumentFilter接口的ApplyDocumentVendorExtensions文檔處理類

internal class ApplyDocumentVendorExtensions : IDocumentFilter
    {
        /// <summary>
        /// //swagger版本控制過濾
        /// </summary>
        /// <param name="swaggerDoc">文檔</param>
        /// <param name="schemaRegistry">schema注冊</param>
        /// <param name="apiExplorer">api概覽</param>
        public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
        {
            //緩存目標路由api
            IDictionary<string, PathItem> match = new Dictionary<string, PathItem>();
            //取版本
            var version = swaggerDoc.info.version;
            foreach (var path in swaggerDoc.paths)
            {
                //過濾命名空間 按名稱空間區分版本
                if (path.Key.Contains(string.Format("/{0}/", version)))
                {
                    //匹配controller descript中的版本信息
                    Regex r = new Regex("/\\w+" + version, RegexOptions.IgnoreCase);
                    string newKey = path.Key;
                    if (r.IsMatch(path.Key)) {
                        var routeinfo = r.Match(path.Key).Value;
                        //修正controller別名路由符合RoutePrefix配置的路由 如api/v2/ValuesV2 修正為 api/v2/Values
                        newKey = path.Key.Replace(routeinfo, routeinfo.Replace(version.ToLower(), "")).Replace(
                            routeinfo, routeinfo.Replace(version.ToUpper(), ""));
                    }
                    //保存修正的path
                    match.Add(newKey, path.Value);
                }
            }
            //當前版本的swagger document
            swaggerDoc.paths = match;
        }
    }

 

至此多版本控制就實現了,其中要注意的地方是Controllers下的V1,V2文件夾下的Controller文件的命名空間要保持默認命名空間,效果如下

 

 

ValuesV2請求的實際路由已修正

 

有部分朋友詢問SwaggerConfig中的勾子方法使用,本文重點在搭建SwaggerConfig在線文檔和多版本實現,勾子方法推薦使用的幾個方法下面簡單介紹下:

開啟數據模型注釋在文檔中生成,參數為當前應用程序依賴的數據模型程序集名稱,GetXmlPath自己實現

c.IncludeXmlComments(GetXmlPath("DataModel"));

//控制器描述Provider,Swagger提供了ISwaggerProvider接口,供自定義實現控制器的描述在文檔中的生成,CachingSwaggerProvider需要自己實現ISwaggerProvider接口

c.CustomProvider((defaultProvider) => new CachingSwaggerProvider(defaultProvider));

//Action相關描述

c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());

Swagger接口文檔頁面中的label漢化js文件,來源網絡

c.InjectJavaScript(thisAssembly, "WebApi.Scripts.Swagger-Custom.js");

 

有可運行的demo沒找到地方上傳,歡迎索取

 

                                                                            --晴天的故事


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM