ASP.NET WebApi 文檔Swagger中度優化

来源:http://www.cnblogs.com/tdws/archive/2016/11/25/6100126.html
-Advertisement-
Play Games

本文版權歸博客園和作者吳雙本人共同所有,轉載和爬蟲請註明原文地址: www.cnblogs.com/tdws 寫在前面 在後臺介面開發中,介面文檔是必不可少的。在複雜的業務當中和多人對接的情況下,簡單的介面文檔又不能滿足需求,試想你的單應用後臺有幾十個模塊,幾百甚至更多的介面,又有上百個ViewMo ...


本文版權歸博客園和作者吳雙本人共同所有,轉載和爬蟲請註明原文地址: www.cnblogs.com/tdws

  寫在前面

在後臺介面開發中,介面文檔是必不可少的。在複雜的業務當中和多人對接的情況下,簡單的介面文檔又不能滿足需求,試想你的單應用後臺有幾十個模塊,幾百甚至更多的介面,又有上百個ViewModel。怎麼能讓人用起來更順手更明瞭?本篇介紹第一步的中度優化,下一篇將分享下一階段的深度優化。

 第一篇:ASP.NET WebApi 文檔Swagger中度優化

1.上手使用

2.Controller註釋讀取和漢化

3.Actionf group by 分組

4.通過exe整合xxxModel.xml和xxxAPI.XML

5.通過批處理命令在生成後調用exe

 第二篇:ASP.NET WebApi 文檔Swashbuckle.Core與SwaggerUI深度定製

Swagger是一款完全開源的文檔工具,其優點在於前後端的完整分離,他們之間的契約就是Json的數據格式。其後臺項目就是github中的Swashbuckle。其前臺項目就是github中的SwaggerUI。有一點需要註意的是,如果你直接從nuget安裝Swashbuckle的話,你也並不想做更多的定製化,那麼UI界面你完全不需要處理,因為所有的資源Resources都是嵌入到Swashbuckle.dll當中的,你可以在vs對象管理器中查看到Resources,如下圖,是不是又複習了dll的作用了呢?其中還可以包含css,js,image等資源:

看下本次分享的效果圖吧,只選了四個Controller做展示,個人覺得還是比較明瞭的吧,如果模塊和控制器多了起來,就會深刻體會到好處:

 

  先學會上手使用

  nuget中搜索Swashbuckle並安裝到你的WebApi項目中,其他的不用安裝哦。

  安裝完成後你的App_Start中會多一個SwaggerConfig這樣一個配置文件,這個文件是Swagger為我們留下的配置入口,我們可以根據其中的註釋和介紹做很多事情。然後我把Swagger單獨出來一個文件夾,直接將配置類拖進去,如下效果:

下一步配置你的項目屬性,在其生成選項當中,選擇下圖配置:

配置文件中主要有兩個入口:EnableSagger和EnableSwaggerUi,顧名思義,配置其後臺項和前臺項。

找到下麵這行代碼,傳入你所需的兩個字元串

下一步找到IncludeXmlComments方法,配置讀取XML的路徑:

 c.IncludeXmlComments(string.Format("{0}/bin/SwaggerDemo.XML", System.AppDomain.CurrentDomain.BaseDirectory));

至此基本就可以顯示你的介面了,請訪問:localhost:xxxx/swagger   你可能會問為什麼我沒有添加頁面也能展示,這就是因為頁面和其路由設置都在dll中了!下麵這段源碼揭示了為什麼可以直接通過路由訪問到你的swagger主頁,當然你也可以不必關心下麵這段:

public void EnableSwaggerUi(
            string routeTemplate,
            Action<SwaggerUiConfig> configure = null)
        {
            var config = new SwaggerUiConfig(_discoveryPaths, _rootUrlResolver);
            if (configure != null) configure(config);

            _httpConfig.Routes.MapHttpRoute(
                name: "swagger_ui" + routeTemplate,
                routeTemplate: routeTemplate,
                defaults: null,
                constraints: new { assetPath = @".+" },
                handler: new SwaggerUiHandler(config)
            );

            if (routeTemplate == DefaultRouteTemplate)
            {
                _httpConfig.Routes.MapHttpRoute(
                    name: "swagger_ui_shortcut",
                    routeTemplate: "swagger",
                    defaults: null,
                    constraints: new { uriResolution = new HttpRouteDirectionConstraint(HttpRouteDirection.UriResolution) },
                    handler: new RedirectHandler(_rootUrlResolver, "swagger/ui/index"));
            }
        }

 

 

 Controller註釋讀取

預設情況下,Controller註釋是沒有讀取的。那麼你需要通過如下配置來達到目的,增加這樣一個類,不用問為什麼。下麵這段代碼也是參考了一位園友的。漢化我也沒必要講了,他已經說的很詳細了。

 
public class CachingSwaggerProvider : ISwaggerProvider
    {
        private static ConcurrentDictionary<string, SwaggerDocument> _cache =
            new ConcurrentDictionary<string, SwaggerDocument>();

        private readonly ISwaggerProvider _swaggerProvider;

        public CachingSwaggerProvider(ISwaggerProvider swaggerProvider)
        {
            _swaggerProvider = swaggerProvider;
        }

        public SwaggerDocument GetSwagger(string rootUrl, string apiVersion)
        {
            var cacheKey = String.Format("{0}_{1}", rootUrl, apiVersion);
            SwaggerDocument srcDoc = null;
            //只讀取一次
            if (!_cache.TryGetValue(cacheKey, out srcDoc))
            {

                //AppendModelToCurrentXml();
                srcDoc = _swaggerProvider.GetSwagger(rootUrl, apiVersion);
                srcDoc.vendorExtensions = new Dictionary<string, object> { { "ControllerDesc", GetControllerDesc() }, { "", "" } };
                _cache.TryAdd(cacheKey, srcDoc);
            }
            return srcDoc;
        }

        /// <summary>
        /// 從API文檔中讀取控制器描述
        /// </summary>
        /// <returns>所有控制器描述</returns>
        public static ConcurrentDictionary<string, string> GetControllerDesc()
        {
            string xmlpath = String.Format("{0}/bin/SwaggerDemo.XML", AppDomain.CurrentDomain.BaseDirectory);
            ConcurrentDictionary<string, string> controllerDescDict = new ConcurrentDictionary<string, string>();
            if (File.Exists(xmlpath))
            {
                XmlDocument xmldoc = new XmlDocument();
                xmldoc.Load(xmlpath);
                string type = String.Empty, path = String.Empty, controllerName = String.Empty;

                string[] arrPath;
                int length = -1, cCount = "Controller".Length;
                XmlNode summaryNode = null;
                foreach (XmlNode node in xmldoc.SelectNodes("//member"))
                {
                    type = node.Attributes["name"].Value;
                    if (type.StartsWith("T:"))
                    {
                        //控制器
                        arrPath = type.Split('.');
                        length = arrPath.Length;
                        controllerName = arrPath[length - 1];
                        if (controllerName.EndsWith("Controller"))
                        {
                            //獲取控制器註釋
                            summaryNode = node.SelectSingleNode("summary");
                            string key = controllerName.Remove(controllerName.Length - cCount, cCount);
                            if (summaryNode != null && !String.IsNullOrEmpty(summaryNode.InnerText) && !controllerDescDict.ContainsKey(key))
                            {
                                controllerDescDict.TryAdd(key, summaryNode.InnerText.Trim());
                            }
                        }
                    }
                }
            }
            return controllerDescDict;
        }
    }

並且在SwaggerConfig找到下麵這行代碼:

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

至此XML讀取完成。

  Action分組展示

下麵這個功能通過我們自定義的Attribute來實現。先往下看,不用問為什麼,功能實現後自然明白啦:

 /// <summary>
    /// Controller描述信息
    /// </summary>
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    public class ControllerGroupAttribute : Attribute
    {
        /// <summary>
        /// 當前Controller所屬模塊 請用中文
        /// </summary>
        public string GroupName { get; private set; }

        /// <summary>
        /// 當前controller用途    請用中文
        /// </summary>
        public string Useage { get; private set; }

        /// <summary>
        ///  Controller描述信息 構造
        /// </summary>
        /// <param name="groupName">模塊名稱</param>
        /// <param name="useage">當前controller用途</param>
        public ControllerGroupAttribute(string groupName, string useage)
        {
            if (string.IsNullOrEmpty(groupName) || string.IsNullOrEmpty(useage))
            {
                throw new ArgumentNullException("groupName||useage");
            }
            GroupName = groupName;
            Useage = useage;
        }
    }

給你的每個Controller加上這個Attribute:

 

 

為了分模塊,我做了這種描述,其他內容不一一描述:

在Swagger找到GroupActionsBy方法:

並且按照你所設定的分組Attribute來分組排序,最終達到我們想要的效果,請仔細閱讀代碼,就自然理解了:

 c.GroupActionsBy(apiDesc => apiDesc.GetControllerAndActionAttributes<ControllerGroupAttribute>().Any() ? 
apiDesc.GetControllerAndActionAttributes<ControllerGroupAttribute>().First().GroupName + "_" +
apiDesc.GetControllerAndActionAttributes<ControllerGroupAttribute>().First().Useage : "無模塊歸類");
   合併Model層的XML文件

上面的效果,你可能看不到Model層的描述信息(如果你的實體沒有在其他層是會正常顯示的)。但是Model分層了,怎麼能展示呢,我目前給出的解決方案是合併XML.寫了一個ConsoleApp,當然你也可以手動來複制處理。

通過相對路徑,將model層的xml生成到與API層相同的路徑下,方便我們來處理。ConsoleApp的代碼如下

static void Main(string[] args)
        {
            AppendModelToCurrentXml();
            Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory);
            Console.WriteLine("XML整合成功");
            //Console.ReadLine();
        }

        public static void AppendModelToCurrentXml()
        {
            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load(AppDomain.CurrentDomain.BaseDirectory + @"/bin/Model.XML");
            var membersNode = xmlDocument.GetElementsByTagName("members")[0]; //Model層Members節點
            xmlDocument.Load(AppDomain.CurrentDomain.BaseDirectory + @"/bin/SwaggerDemo.XML");
            var currentMembersNode = xmlDocument.GetElementsByTagName("members")[0];  //API層Members節點
            for (int i = 0; i < membersNode.ChildNodes.Count; i++)
            {
                var memberNode = membersNode.ChildNodes[i];
                currentMembersNode.AppendChild(memberNode.Clone());
                if (memberNode.HasChildNodes)
                {
                    memberNode.AppendChild(memberNode.ChildNodes[0]);
                }
            }
            xmlDocument.Save(AppDomain.CurrentDomain.BaseDirectory + @"/bin/SwaggerDemo.XML");
        }

至於我為什麼要取路徑時選擇appDomain,是因為我準備把該exe文件放置到webAPI項目的根目錄下,這樣取到的路徑就是API項目的物理路徑,如果把物理路徑寫死,很煩的,你懂的,因為發佈或者到其他人電腦中,物理路徑基本就變了。這段代碼的主要功能就是把Model層中所生成的XML中的Members節點的所有內容,Copy到API項目的XML當中。

 並且,為了不用每次都手動調用exe文件,我使用批處理命令,在每次項目生成後,自動執行exe.

Swagger的前後端分離,靠json格式的契約,你可以在network中查看json結果,下一篇深度定製分享將會用到它。

 

 

   寫在最後

 本篇多數是配置化的內容,只不過在實際操作的時候,面對不同情況,我們希望能得到更好的結果。動手嘗試一下吧,如果有問題和不足的地方,歡迎留言探討,萬一你以後用上了呢,不,應該說WebApi文檔你是一定用得上。下一篇,將會更深一步的優化,讓我們拿到源碼後,無論有什麼特別的需求,都能自己親手修改,而不被矇蔽在dll中。

如果我的點滴分享對你有點滴幫助,歡迎點下方紅色按鈕關註,我將持續分享。也歡迎為我,也為你自己點贊。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • centos7 字元界面操作基礎 1.字元界面的使用方法 2.本地登錄和遠程登錄 3.學會使用putty 4.理解系統運行級別及其切換方法 5.掌握常用的系統關機和重啟命令 為什麼使用字元工作方式? 1.在字元操作方式下可以高效的完成所有的任務,尤其是系統管理任務。 2.系統管理任務通常都是遠程進行 ...
  • Hyper-V是微軟的管理虛擬機(Virtual Machine)的服務,在安裝Hyper-V功能之後,系統自動安裝可視化的虛擬機管理工具:Hyper-V Manager。在同一臺物理機上,能夠使用Hyper-V創建多個虛擬機(VM),每一個VM執行不同的工作負載(workload),運行單獨的系統 ...
  • linux的特點 優點: 1、免費的/開源的系統 2、支持多線程/多用戶的系統 3、安全性好 4、對記憶體和文件管理優越 5、提供了豐富的網路功能 6、良好的用戶界面。圖形化界面和字元型界面 linux體積最少只需要記憶體4M,由於小所以可以做嵌入式開發 linux系統的組成: 內核:是系統的心臟,實現 ...
  • 若虛擬機在不正常關機的時候會遇到如下圖所示的問題:先點擊“取消”按鈕 解決方法:打開“資源管理器”,進入到彈出提示視窗所在的路徑(即H:\VMware\Virtual Machines Documents\CentOS),在這裡找到CentOS.vmx.lck文件夾,然後將尾碼名.lck的文件夾刪除 ...
  • 1.參照Zabbix文檔配置 依照官方文檔配置,沒什麼說的。 zabbix官方文檔:https://www.zabbix.com/documentation/3.2/manual/vm_monitoring 2.遇到的問題 這裡主要介紹我遇到的問題。由於理解偏差,文檔中的sdk,我以為是sdk的意思... ...
  • 問題 怎麼樣可以使用更貼近資源(Controller,Action)的方式定義路由。 解決方案 可以使用屬性路由直接在資源級別聲明路由。只要簡單的在 Action 上使用屬性路由 RouteAttribute,然後傳一個相關路由模板就可以。屬性路由與集中式路由在路由模板含義上基本是一樣的,所有路由參 ...
  • 在對ASP.NET Core管道中關於依賴註入的兩個核心對象(ServiceCollection和ServiceProvider)有了足夠的認識之後,我們將關註的目光轉移到編程層面。在ASP.NET Core應用中基於依賴註入的編程主要涉及到兩個方面,它們分別是將服務註冊到ServiceCollec... ...
  • 本月16號,MS發佈了 .NET Core 1.1。作為一個用貫MS產品的小盆友,我第一時間就把相關的安裝包下載下來了,然後果斷安裝(入坑)。 我猜你來看這篇博客可能遇到了和我一樣的問題。 問題0:正確的安裝順需 正確的順序在MS的dotnet Core官網上可以找到,請根據自己的VS版本對號入座。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...