ASP.NET WebAPI 2 整合 NSwag
19 |
前陣子介紹過用 Swashbuckle 為 ASP.NET WebAPI 產生 Swagger/OpenAPI 文件,可自動產生 Swagger UI 線上說明及測試介面,再配合 NSwag Studio 等工具自動產生客戶端,開發體驗不輸 WCF/Web Service。
但後來發現一件事,Swashbuckle 雖然歷史較久名氣較大,但作者兩年前重心已移往 ASP.NET Core,另起了 Swashbuckle.AspNetCore,ASP.NET WebAPI 版本已不再維護。此點讓我慎重評估另一個選項 - NSwag,它跟 Swashbuckle 一樣是 ASP.NET Core 官方文件列舉的 Swagger 解決方案。NSwag 專案同時支援 ASP.NET Core 及 OWIN Middleware,通吃 .NET Framework 與 .NET Core 版本 WebAPI。由於工作專案仍以 ASP.NET MVC/WebAPI 為主,但新的小型專案可能會用 ASP.NET Core,再加上客戶端程式庫產生器已決定採用 NSwag Studio,伺服器端統一改用 NSwag 似乎是個不錯的選擇。
如何在 ASP.NET Core 使用 NSwag,官方文件已有說明,在 ASP.NET WebAPI 整合 NSwag 的資料相對較少,在此整理新建 ASP.NET Web API 引用 NSwag 步驟以為日後參考。參考來源:NSwag OWIN Middleware
在 Visual Studio 新增 ASP.NET Web Application (.NET Framework) 專案 (以 VS2017 為例)
選擇 Web API 範本
規格沿用自範例教學:使用 ASP.NET MVC 打造 WebAPI 服務開發一加解密 Web API,核心邏輯照抄 Models/CodecModule.cs,提供 EncrytString()、DecryptData() 兩個方法。
新增 Web API 2 Controller - Empty
CodecController.cs 內容如下,介面不走 RESTful,採 RPC-Style 以名稱區隔多個 HttpPost,這在 Swashbuckle 會遇到Multiple operations with path 'api/MyApiName' and method 'POST'
錯誤,要以 [Route(api/...)] 在每個 Action 明確定義路由;NSwag 則在初始設定階段定義一次即可,簡單許多。using System.Collections.Generic; using System.Web.Http; using WebApiDemo.Models; namespace WebApiDemo.Controllers { public class CodecController : ApiController { /// <summary> /// 加密字串 /// </summary> /// <param name="encKey">加密金鑰</param> /// <param name="rawText">明文字串</param> /// <returns>加密字串</returns> [HttpPost] public byte[] EncryptString(string encKey, string rawText) { return CodecModule.EncrytString(encKey, rawText); } /// <summary> /// 解密請求參數物件 /// </summary> public class DecryptParameter { /// <summary> /// 加密金鑰 /// </summary> public string EncKey { get; set; } /// <summary> /// 加密字串陣列 /// </summary> public List<byte[]> EncData { get; set; } } /// <summary> /// 批次解密 /// </summary> /// <param name="decData">解密請求參數(加解密金鑰與加密字串陣列)</param> /// <returns>解密字串陣列</returns> [HttpPost] public List<string> BatchDecryptData([FromBody]DecryptParameter decData) { return CodecModule.DecryptData(decData.EncKey, decData.EncData); } } }
接著用 NuGet 新增以下項目:
- NSwag.AspNet.Owin
- Microsoft.AspNet.WebApi.Owin
- Microsoft.Owin.Host.SystemWeb
安裝 NSwag.AspNet.Owin 時會一併安裝 Owin、Microsoft.Owin 等套件,但不包含 Microsoft.AspNet.WebApi.Owin 及 Microsoft.Owin.Host.SystemWeb,記得要額外加裝。
在專案新增 Startup.cs
Startup.cs 內容如下:using Microsoft.Owin; using NSwag.AspNet.Owin; using Owin; using System.Web.Http; [assembly: OwinStartup(typeof(WebApiDemo.Startup))] namespace WebApiDemo { public class Startup { public void Configuration(IAppBuilder app) { var config = new HttpConfiguration(); app.UseSwaggerUi3(typeof(Startup).Assembly, settings => { //針對RPC-Style WebAPI,指定路由包含Action名稱 settings.GeneratorSettings.DefaultUrlTemplate = "api/{controller}/{action}/{id?}"; //可加入客製化調整邏輯 settings.PostProcess = document => { document.Info.Title = "WebAPI 範例"; }; }); app.UseWebApi(config); config.MapHttpAttributeRoutes(); config.EnsureInitialized(); } } }
另外記得要開啟產生 XML 文件 Swagger UI 才會有方法及參數說明,Swashbuckle 需手工指定 XML 路徑,NSwag 會自己抓,再方便一些。
因為要將 URL /swagger/* 導向 NSwag 處理程式,web.config 需加入處理器設定:
<system.webServer> ... <handlers> ... <add name="NSwag" path="swagger" verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
萬事齊備,執行網站,連上 ~/swagger 可在 Swagger UI 看到 WebAPI 項目並直接在網頁上測試:
【實測心得】NSwag 設定上較 Swashbuckle 簡單,尤其我採用 RPC-Style Web API,Swashbuckle 需在每個 Action 加註 [Route],NSwag 只需在 Startup.cs 設定。但主要考量點仍在於 ASP.NET WebAPI 版的 Swashbuckle 已不再維護,NSwag 專案則相對活躍,經評估,未來專案如需 WebAPI 文件、測試 UI、客戶端產生自動化解決方案,將以 NSwag 為主。
Tutorial of using NSwag on ASP.NET Web API project (non .NET Core), especially for RPC-style web api scenarios.
Comments
# by littleRD
請問如果API格式要改成OAS3.0, startup那邊該如何設定呢?
# by Jeffrey
to littleRD, 查了 Swagger 有支援 OpenAPI 3.0,細節可以參考官網文件:https://swagger.io/blog/news/support-for-oas-3-0-in-swagger-editor-and-swagger/
# by William
你好, 請問ASP.NET Web API 2 (.NET Framework) 有辦法加入header參數嗎? 我Google到的範例都是使用.net core, 沒看到適用在.net framework的 web api。(順帶一提, Swashbuckle 的swagger是可以做到的) 謝謝
# by Jeffrey
to William, 你說的「Header 參數」類似這樣嗎?https://dotblogs.com.tw/yc421206/2018/12/20/swagger_custom_header
# by William
To Jeffrey, 對的,我當時使用swagger時,就是按照他的做法成功加入header參數。有一個小地方跟他不一樣,他自訂的header類別有一個EnumValues屬性,所以在swagger頁面上會自動產生一個下拉選單來選擇header參數的值;而我的header類別裡不放這個EnumValues屬性,所以在swagger頁面上會自動產生一個textbox用來輸入header參數的值。然而我現在改用NSwag後就不知如何加入header,我在網路上看到的做法似乎全是只適用於.net core。我之所以用到header的原因是凡事呼叫我web api都需要傳遞token來做身份驗證,而token就是用header來傳的,我不想把token放在api的參數裡,是因為api的參數我只想用來放跟我的商業邏輯或功能相關的資料。所以我在想如果只是為了能夠在NSwag加入header而把整個專案改寫成.net core版,代價也太大了,難道.net framework的web api就真的不能加header嗎 :( 謝謝
# by William
補充一下,若不能加入header, 則NSwag的API說明頁面上就不能真正完整體現出所有需要的資訊,且也無法在該頁面上做測試,因為沒有地方能輸入header
# by Jeffrey
to William, 應該可以,需設定 DocumentProcessors、OperationProcessors 。參考: https://github.com/RicoSuter/NSwag/issues/1304#issuecomment-449567045
# by William
To Jeffrey, 非常感謝您的寶貴時間, 您提供的參考作法是可行的。此外, 雖然我的Web Api不是透過Startup來啟動, 而是Global.asax, 但稍加調整後還是能夠使用的。謝謝。 順帶一提, 在這裡留言需要輸入正確的Captcha, 也就是兩個數字相減的值, 但遇過好幾次明明輸入的數字沒錯, 但確顯示Error: Captcha validation failed, 在此提醒您可能有這類的情況發生, 謝謝
# by Hao
Jeffrey您好,想請問有辦法一個controller一份文件嗎?就像新北市政府開放平台api那樣可以選擇而不是全部的controller都在同一個頁面這樣。 新北市政府的api:https://data.ntpc.gov.tw/openapi/swagger-ui/index.html?configUrl=/openapi/swagger/config
# by Jeffrey
to Hao, 原理是修改 Swagger JSON 用 urls 跟 "urls.primaryName" 分組,參考: https://stackoverflow.com/a/45161533/288936 但 NSwag 應該不支援。
# by Bike
NSwag 可以用回傳 DataTable 的 Action 上嗎 ? 我試了, 它會回傳這個錯誤: The JSON property 'Item' is defined multiple times on type 'System.ComponentModel.ComponentCollection'.
# by bike
呵呵, 我試出來了, 若是要回傳 DataTable 改成, 要回到 object 就可以了
# by Jeffrey
to Bike, 分享我的解法 https://blog.darkthread.net/blog/nswag-return-datatable/
# by Jim
請教一下如何在Nswag上開啟像Swashbuckle Filter by tag 這個搜尋Bar的功能,可否請黑大分享一下
# by Jeffrey
to Jim, 沒用過這個功能耶,NSwag 有支援嗎?
# by Jacky Wu
Hao, NSwag可以做分組,我最近才實作 https://www.cnblogs.com/shanfeng1000/p/13476834.html 主要就是AddOpenApiDocument可以做多次 最後把所有的分組都加進來 app.UseSwaggerUi3(options => { options.Path = "/swagger"; options.DocumentPath = "/swagger/{documentName}/swagger.json"; options.SwaggerRoutes.Add(new SwaggerUi3Route("v1", "/swagger/v1/swagger.json")); options.SwaggerRoutes.Add(new SwaggerUi3Route("v2", "/swagger/v2/swagger.json")); });
# by Teddy
黑大 想請教我用VS debug模式的時候swagger的物件就有出現desc,可是當我部屬上iis的時候就消失了@@ 不知道怎麼會這樣,看起來不太像組態問題,想問問黑大有遇過嗎QQ 感謝
# by Jeffrey
to Teddy, 沒遇過,想到一種可能,會是漏部署 bin/WebAppName.xml ?
# by Teddy
感謝黑大 我後來知道原因了 因為我的物件是放在另一個類別庫專案 使用delploy的時候不會把xml一起帶過來 我後來在屬性的封裝/發怖Web tab中,將部屬的項目選單選擇"此專案資料夾中全部的檔案"就可以了 只不過他也會把全部原始碼一起發佈就是@@ 目前只查到這個方式