<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Asp.Net MVC項(xiàng)目集成Swagger

        公司最近的項(xiàng)目使用mvc+webapi,采取前后端分離的方式,后臺提供API接口給前端開發(fā)人員。這個(gè)過程中遇到一個(gè)問題后臺開發(fā)人員怎么提供接口說明文檔給前端開發(fā)人員,之前一直使用的是word文檔方式進(jìn)行交流,效率低下而且不利于維護(hù)。為了解決這個(gè)問題,經(jīng)過一番研究,引起我注意的有兩種方案。1.微軟自帶的Microsoft.AspNet.WebApi.HelpPage  2.swagger(我比較喜歡戲稱為“絲襪哥”)

      最先嘗試的是微軟自帶的方案,由于界面實(shí)在是比較一般,于是轉(zhuǎn)向了第二種方案,經(jīng)過大半天大搗鼓,最終效果如下:

      1.列出所有API控制器和控制器描述

       

       

      2.列出action和描述

       

       

      3.直觀的接口測試

      達(dá)到這幾點(diǎn)目標(biāo),已經(jīng)滿足項(xiàng)目使用。

       

      使用swagger

        1.創(chuàng)建webapi項(xiàng)目解決方案

        2.引用swagger nuget包

        引入Swashbuckle一個(gè)包即可,有些教程說要引入和Swagger.Net.UI,其實(shí)功能重復(fù)了(后面會解釋)。

      引入后,項(xiàng)目App_Start下會多一個(gè)文件:

         3.添加接口注釋

        完成上面三部運(yùn)行項(xiàng)目,可以看到接口描述已經(jīng)生成,瀏覽地址http://xxx/Swagger。但是沒有接口的注釋,當(dāng)時(shí)決定引入Api管理工具就是看中了注釋功能,下面添加接口注釋

        

       

         項(xiàng)目屬性->生成,勾選生成xml文檔文件(有些太古老的WebSite項(xiàng)目不支持注釋功能,因?yàn)楦緵]有生成xml這一個(gè)選項(xiàng))

        

        修改SwaggerConfig文件

        

        

        給接口添加注釋,即可看到參數(shù)及方法描述了。

      漢化及問題解決

      經(jīng)過上面的操作,已經(jīng)完成了所需功能。但是還有幾點(diǎn)問題需要完善

           1.界面的說明都是英文的需要進(jìn)行漢化

           2.控制器沒有描述

           3.接口過多每次生成速度比較慢

      1.漢化步驟

      在SwaggerConfig配置文件中有這么一段代碼

      .EnableSwaggerUi(c =>{
           //c.InjectJavaScript(thisAssembly, "Swashbuckle.Dummy.SwaggerExtensions.testScript1.js")
       });

      這段代碼的作用是向頁面輸出引用Swashbuckle.Dummy.SwaggerExtensions.testScript1.js文件,或許會疑問js文件路徑為什么這么奇怪。那是因?yàn)镾wagger將資源文件都嵌入到dll中了,我們常用的資源文件都是以內(nèi)容的方式放在項(xiàng)目中的,我們也可以以嵌入的資源方式引入到項(xiàng)目中

      這也是上面不引入Swagger.Net.UI,頁面也能正常出來的原因。資源文件都被打包到dll中了,使用反編譯工具reflector。來反編譯一下Swashbuckle.Core.dll

      弄清楚了實(shí)現(xiàn)原理,現(xiàn)在來實(shí)現(xiàn)漢化。添加自己的中文語言包,和轉(zhuǎn)換js,實(shí)現(xiàn)邏輯參考swagger源碼。

       

      //c.InjectJavaScript(thisAssembly, "Swashbuckle.Dummy.SwaggerExtensions.testScript1.js");
        //路徑規(guī)則,項(xiàng)目命名空間.文件夾名稱.js文件名稱
        c.InjectJavaScript(thisAssembly, "BWebFoowwSoftStatistic.Content.js.SwaggerUI.Swagger_lang.js");

       

       

      ///    <summary>
      /// 中文轉(zhuǎn)換
      ///    </summary>
      var SwaggerTranslator = (function () {
          //定時(shí)執(zhí)行檢測是否轉(zhuǎn)換成中文,最多執(zhí)行500次  即500*50/1000=25s
          var iexcute = 0,
          //中文語言包
          _words = {
              "Warning: Deprecated": "警告:已過時(shí)",
              "Implementation Notes": "實(shí)現(xiàn)備注",
              "Response Class": "響應(yīng)類",
              "Status": "狀態(tài)",
              "Parameters": "參數(shù)",
              "Parameter": "參數(shù)",
              "Value": "值",
              "Description": "描述",
              "Parameter Type": "參數(shù)類型",
              "Data Type": "數(shù)據(jù)類型",
              "Response Messages": "響應(yīng)消息",
              "HTTP Status Code": "HTTP狀態(tài)碼",
              "Reason": "原因",
              "Response Model": "響應(yīng)模型",
              "Request URL": "請求URL",
              "Response Body": "響應(yīng)體",
              "Response Code": "響應(yīng)碼",
              "Response Headers": "響應(yīng)頭",
              "Hide Response": "隱藏響應(yīng)",
              "Headers": "頭",
              "Try it out!": "試一下!",
              "Show/Hide": "顯示/隱藏",
              "List Operations": "顯示操作",
              "Expand Operations": "展開操作",
              "Raw": "原始",
              "can't parse JSON.  Raw result": "無法解析JSON. 原始結(jié)果",
              "Model Schema": "模型架構(gòu)",
              "Model": "模型",
              "apply": "應(yīng)用",
              "Username": "用戶名",
              "Password": "密碼",
              "Terms of service": "服務(wù)條款",
              "Created by": "創(chuàng)建者",
              "See more at": "查看更多:",
              "Contact the developer": "聯(lián)系開發(fā)者",
              "api version": "api版本",
              "Response Content Type": "響應(yīng)Content Type",
              "fetching resource": "正在獲取資源",
              "fetching resource list": "正在獲取資源列表",
              "Explore": "瀏覽",
              "Show Swagger Petstore Example Apis": "顯示 Swagger Petstore 示例 Apis",
              "Can't read from server.  It may not have the appropriate access-control-origin settings.": "無法從服務(wù)器讀取。可能沒有正確設(shè)置access-control-origin。",
              "Please specify the protocol for": "請指定協(xié)議:",
              "Can't read swagger JSON from": "無法讀取swagger JSON于",
              "Finished Loading Resource Information. Rendering Swagger UI": "已加載資源信息。正在渲染Swagger UI",
              "Unable to read api": "無法讀取api",
              "from path": "從路徑",
              "Click to set as parameter value": "點(diǎn)擊設(shè)置參數(shù)",
              "server returned": "服務(wù)器返回"
          },
      
          //定時(shí)執(zhí)行轉(zhuǎn)換
           _translator2Cn = function () {
               if ($("#resources_container .resource").length > 0) {
                   _tryTranslate();
               }
      
               if ($("#explore").text() == "Explore" && iexcute < 500) {
                   iexcute++;
                   setTimeout(_translator2Cn, 50);
               }
           },
      
           //設(shè)置控制器注釋
           _setControllerSummary = function () {
               $.ajax({
                   type: "get",
                   async: true,
                   url: $("#input_baseUrl").val(),
                   dataType: "json",
                   success: function (data) {
                       var summaryDict = data.ControllerDesc;
                       var id, controllerName, strSummary;
                       $("#resources_container .resource").each(function (i, item) {
                           id = $(item).attr("id");
                           if (id) {
                               controllerName = id.substring(9);
                               strSummary = summaryDict[controllerName];
                               if (strSummary) {                            
                                   $(item).children(".heading").children(".options").prepend('<li class="controller-summary" title="' + strSummary + '">' + strSummary + '</li>');
                               }
                           }
                       });
                   }
               });
           },
      
           //嘗試將英文轉(zhuǎn)換成中文
          _tryTranslate = function () {
              $('[data-sw-translate]').each(function () {
                  $(this).html(_getLangDesc($(this).html()));
                  $(this).val(_getLangDesc($(this).val()));
                  $(this).attr('title', _getLangDesc($(this).attr('title')));
              });
          },
          _getLangDesc = function (word) {
              return _words[$.trim(word)] !== undefined ? _words[$.trim(word)] : word;
          };
      
          return {
              Translator: function () {
                  document.title = "API描述文檔";
                  $('body').append('<style type="text/css">.controller-summary{color:#10a54a !important;word-break:keep-all;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:250px;text-align:right;cursor:default;} </style>');
                  $("#logo").html("接口描述").attr("href", "/Home/Index");
                  //設(shè)置控制器描述
                  _setControllerSummary();
                  _translator2Cn();         
              }
          }
      })();
      //執(zhí)行轉(zhuǎn)換
      SwaggerTranslator.Translator();

      2.控制器描述和接口文檔緩存

      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))
                  {
                      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", System.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;
              }
          }
      c.CustomProvider((defaultProvider) => new CachingSwaggerProvider(defaultProvider)); 

      上面漢化的js中的方法_setControllerSummary通過讀取ControllerDesc屬性設(shè)置了控制器的描述,至此項(xiàng)目可以無憂使用接口描述文檔。

      3.action 方法名稱相同處理

       

      根據(jù)錯誤提示 很快發(fā)現(xiàn) 某位大神 同樣的接口名 傳遞了不同參數(shù),導(dǎo)致了這個(gè)錯誤,解決方式:

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

      4.一個(gè)Controller不支持多個(gè)Get/Post請求問題,修改WebApiConfig.cs

       

      5.Date時(shí)間類型不對生成Json格式不對的問題

      WebApi自帶json序列化對遇到時(shí)間日期字段的時(shí)候,到前端獲取的格式總是為“ 2016-07-14T15:32:44”,中間總是會帶一個(gè)T,顯然不是很友好,解決方案如下:

      6swagger 問題2.序列化出來的JSON NULL 值處理。

      先上圖

      等了好半天 一直不出來 打開F12一看原來有錯,萬能的網(wǎng)友幫了我,原來問題出在http://localhost:58303/swagger/docs/v1這個(gè)JSON資源上面,

      序列化出來的JSON,包含了為NULL的字段,導(dǎo)致swagger-ui-min-js出現(xiàn)異常。

      進(jìn)一步分析是因?yàn)槲翼?xiàng)目使用的newtonsoft.json這個(gè)庫的配置導(dǎo)致,應(yīng)該忽略為NULL的字段,

      對應(yīng)解決辦法如圖: settings.NullValueHandling = NullValueHandling.Ignore;

      總結(jié):

      規(guī)范化api的編寫和注釋,以及標(biāo)準(zhǔn)化文檔,對于團(tuán)隊(duì)的開發(fā)效率有很大的提升,也有利于項(xiàng)目的維護(hù)。使用在線接口文檔后,方便前后端工程師溝通,測試人員測試只需要在頁面輸入?yún)?shù),點(diǎn)擊調(diào)用就可以看到調(diào)用結(jié)果。

       

      posted on 2018-12-11 12:53  Baymax01  閱讀(8481)  評論(0)    收藏  舉報(bào)

      導(dǎo)航

      主站蜘蛛池模板: 久久久久久无码午夜精品直播| 亚洲av无码之国产精品网址蜜芽| 国产精品高清国产三级囯产AV| 高清自拍亚洲精品二区| 日本妇人成熟免费| 久99久热精品免费视频| 亚洲精品中文字幕一区二| 四虎影院176| 亚洲最大成人av在线天堂网| 日本高清久久一区二区三区| 亚洲欧洲日产国码高潮αv| 国产超高清麻豆精品传媒麻豆精品 | 人妻少妇久久中文字幕| 不卡高清AV手机在线观看| 崇仁县| 亚洲老熟女一区二区三区| 亚洲AV美女在线播放啊| 奇米777四色影视在线看| 狠狠色噜噜狠狠狠777米奇小说| 少妇人妻偷人一区二区| 亚洲欧美国产精品专区久久| 蜜桃臀av一区二区三区| 少妇人妻偷人免费观看| 伊人精品无码av一区二区三区| 久久免费观看午夜成人网站 | 亚洲av成人网人人蜜臀| 亚洲第一区二区国产精品| 巨熟乳波霸若妻在线播放| 日韩中文字幕v亚洲中文字幕| 国产av黄色一区二区三区| 国产精品白浆在线观看免费| 久久天天躁狠狠躁夜夜avapp| 欧美熟妇乱子伦XX视频| 亚洲精品不卡av在线播放| 超碰成人人人做人人爽| 国产精品自在拍在线播放| 色婷婷五月综合亚洲小说| 亚洲激情av一区二区三区| gogo无码大胆啪啪艺术| 国内精品久久久久精免费| 成人一区二区人妻不卡视频|