Doxygen程式碼文件產生器
有個需求,需要提供API文件給其他團隊。評估線上與離線方案:
線上式:
- Postman:適合團隊協同合作。但團隊外不是很合適。
- Swagger:需額外在專案裡開Endpoint與還會造成額外的(安全)維護成本。
離線式:
- DocFX
- Sandcastle
都有在考慮範圍,但試過之後效果不理想。
有個需求,需要提供API文件給其他團隊。評估線上與離線方案:
線上式:
離線式:
都有在考慮範圍,但試過之後效果不理想。
教學上,我一直認為沒有爛問題。只有懂與不懂。實務問題都是好問題。
原始問題是,他想要對一個簡單型別進行取值的動作,我們快速打造出第一版原型ASP.NET Core Web API程式碼:
教學上,我一直認為沒有爛問題。只有懂與不懂。
平常我們在課程上設計的範例為求簡單好懂,通常都會盡量簡化。但回去之後的實務問題,在我眼裡都非常有價值。API 的開發可以很簡單,也可以很複雜,例如,只是單純從後端資料庫取資料,資料表與Model的對應關係通常都是一對一(1:1)的,輸出入也很單純只會有一層,除非你導入了如 Entity Framework 之類 ORM,產生了一對多(1:n)或多對多(n:n)的情境。
{
"filter":{
"name":"bruce",
"currentPage":1,
"pageSize":5
}
}
以同學提問的情況,感覺比較像 Front-End First(或稱 JSON First),也就是 JSON 規格是由前端定義。我們一步一步來解決。
在將一個 ASP.NET Web API 應用程式進行容器化(Containerization)發現一個問題,原先的 Web API 部署至 IIS 應用程式之下,我們會區分開發區(Develop)、測試區(Staging)、正式區(Production),而原始的請求因為 IIS 應用程式的關係,路由都會被加上應用程式的前綴(Route Prefix),例如:
前情提要:參考(1)(2),之前測試發現 ASP.NET Web API 有個查詢資料量不小(1.92 MB),並且會有同等級的上傳行為,在 ASP.NET Web API 加入 GZIP/Deflate (解)壓縮來改善效能,資料由 1.92 MB → 50 KB 壓縮率約 40 倍,這是用一點 CPU 來改善效能的好範例。
同事回報,在測試區當資料量提升至 3.3 MB(3338506 bytes) 後,程式有機會(隨機)出錯(Exception)。
先來看 HTTP POST 流程:
RestSharp (RawData: Over 3.3 MB) → GZIP → GZIP ByteArray (79515 bytes) → HTTP POST → ASP.NET Web API
這是個 VSTO 的 Excel 應用程式,在讀取 Web API 資料之後,原封不同進行上傳(HTTP POST)動作,由側錄取得離線 RawData 約 3.3 MB,經過 GZIP 壓縮後得到約 78 KB 的 Byte Array 資料,最後使用參考(2)程式碼送出:
request.AddParameter("application/json", content.ToArray(), ParameterType.RequestBody);
接收流程:
ASP.NET Web API → DecompressionHandler → RawData → Web API life cycle
Web API 收到請求後安排一個 Message Handler 進行解壓縮後取得 RawData 之後,按 Web API 生命流程往下進行。
程式穩定運作,經過許多分析與測試後,在終於在 Web API 側錄到錯誤發生時的資訊:
在 DecompressionHandler 取得的 GZIP ByteArray 大小為 77889,很明顯小於原始的 79515,把解壓縮的 RawData 資料 Dump 出來後確實資料短少被截斷了,造成後續 Web API 在進行 ModelBinding 時的不正常 Exception。
在 dzone.com 看到一篇比較 SOAP 與 REST 的文章整理的覺得不錯,簡單翻譯做個筆記。
SOAP 和 REST 都是 Web Service 通訊協定,在 REST 未風行之前,SOAP 長期以來都是 Web Service 服務介面的標準方法。不過,根據 Stormpath 的統計,目前已有超過 70% 的公開 API。
SOAP 與 REST 主要差異
當你在 Internet 上公開一個 API,REST 通過獨立且一致的介面進行操作,用以訪問命名資源。而 SOAP 將應用程式邏輯的元件公開為服務,而不是資料,並且它通過不同的介面來操作。簡而言之,REST 訪問資料,SOAP 透過更標準化的訊息模式集來操作。在大多數情況下,可以使用 SOAP 與 REST 來實現相同結果。
看到一篇 8 ways to improve ASP.NET Web API performance 覺得整理的不錯,順手簡單整理與寫點心得。
ASP.NET Web API 預設採用 JSON.NET。JSON.NET 求穩不求快,如果要求快,透過 ASP.NET Web API 優秀擴充點機制,可隨時更換序列化套件。
之前在 Blog 介紹過 Jil:
8 Ways作者則是採用 ServiceStack.Text 套件。

圖片來源:theburningmonk.com
前一篇使用GZIP或DEFLATE壓縮,提升資料傳遞效能40倍,我們處理了查詢資料量大時,Web API 在傳遞未經壓縮的資料產生許多不必要的網路流量的問題。現在我們轉換方向,如果是用戶端要傳遞大量資料至 Web API 時,那麼我們要怎麼處理?這比較麻煩,有二個方向要討論,一是 Client 端進行發送請求時,必須先做 GZIP/Deflate 的壓縮,而 Web API 接收到 GZIP/Deflate 壓縮資料後需要解壓縮還原資料內容。
從這個方向來思考,你應該能發現另一件事,就是前一篇我們只專注在 GZIP/Deflate 的壓縮上,並無做任何解壓縮的工作,那是因為瀏覽器本身在協商過程與接收到的 Header 可以判定接收到的是 GZIP/Deflate 的內容,瀏覽器會直接幫我們進行 GZIP/Deflate 的解壓縮工作。
專案有個查詢資料量不小,基本測試資料每次約1.92 MB,透過 ASP.NET Web API 傳遞至 Client 端每次就是 1.92 MB 的網路傳遞量,而且未來上線後,資料量只會越來越大,直覺感到不對勁(壞味道)。
IIS的動態壓縮與靜態壓縮對 ASP.NET Web API 是無效的。而且,平常 ASP.NET Web API 的請求,資料負載量也不是很大,那種 KB 級的資料壓縮率不高,平常也就沒特別注意。不過在 MB 級的資料,有無啟用 GZIP 或 Deflate 壓縮的資料量差異,直接說結果,以我實測得到的數據差了40倍。
Visual Studio 2015 Update 3 的 Web 專案範本有個問題(更正確的說,是NuGet套件造成)。如果你新增一個 Web 應用程式然後更新所有 NuGet 套件,更新完成後會看到 "Microsoft.Net.Compilers.1.0.0 failed to uninstall. Restart Visual Studio to finish the process." 的提示訊息。
自從接觸到Agile/Scrum之後,有個東西會特別注意,那就是浪費。
上述的情況最少有兩種浪費:
由於經常需要寫寫測試程式或範例,套件 30 秒重開 30 秒就這樣不見了,這兩件浪費的事有時一天會發生好幾次,尤其是在寫文章或備課期間更是明顯。
有浪費不消滅,說不過去。
公司有個特別的 D 系統,我們需要透過 ASP.NET Web API 去存取它的 XML Web Service 來提供資源。這個 D 系統本身有個特別的限制,就是存取之前使用者需要先進行頁面 Login,然後才能存取 XML Web Service。Login 頁面很單純,就是一個帳號與密碼的組合,沒有其他特別驗證碼等保護。也就是使用者使用者輸入帳號密碼,而 ASP.NET Web API 透過使用者提供的帳號密碼透過程式方式進行登入,我們開發的 ASP.NET Web API 服務從一開始的 Beta 至 RC,這部分的程式碼都沒什麼問題,直到那令人鬼打牆的關鍵人物(暫稱他苦命的呆伯特好了)出現。
簡單說明一下,此 ASP.NET Web API 服務主要使用者在美國,美國下班台灣上班的黃金交接點,我們私下請呆伯特(美國)幫忙測試此 ASP.NET Web API 服務的同事,但幾星期以來僅呆伯特都一直反應無法 Login 服務,由日誌看出來,他確實是登入失敗。但所有幫忙測試的人員只有呆伯特會出現此狀況。D 系統我們無任何權限,我們能做的也只是不斷調整 ASP.NET Web API 程式並不斷請呆伯特幫忙 Login 與測試。但每每得到"不行"時,心情都低落到不行(測到呆伯特都生氣了),不過最後得到一條重要資訊,呆伯特的密碼含有數個的特殊符號。
我們為加解密演算法補上特殊符號的測試程式碼,先確保特殊符號在加密與解密過程正常。其中小心\與"這兩個符號,在C#的字串中,需要使用\\與\"進行轉義。
以這條線索測試到最後終於有了曙光。
網站開發到一定規模,你一定有經驗,開始在 Web.config 裡去註解A執行B設定,或註解C執行D設定,最常碰到的需求有:測試區與正式區的 appSettings 設定,測試區與正式區的 connectionStrings 設定等。當專案離開本機開始發行至測試區或正式區時,千萬不要還在用切換註解的方式,應該參考 Kevin:「發佈網站時依據組態設定的不同而轉換 Web.Config」的模式去進行發行時 *.config 的切換。這種動作的名稱「XML-Document-Transform」(XML文件轉換),簡單說,就是利用 Locator 找出要修改位置,再利用 Transform 屬性指定進行的動作。
發行可以利用「XML-Document-Transform」來解決不同區域不同配置的問題。但開發人員最常碰到卻是開發當下!開發除錯當下,你無法去只是簡單切換 Debug | Release 來達到或啟用XML文件轉換的功能,假設,你想將原本 SqlLocalDb 的連線字串切換至 SQL Server Express 連線字串進行測試時,好像只有註解、移除註解這條路。 :-(
這樣的路,其實走了好久好久,我累了,我想,是應該跟它分手了。(超假文青 XD)
這裡會利用如何:擴充 Visual Studio 建置處理序裡的技巧。以下技巧通用於 ASP.NET WebForms 與 ASP.NET MVC 與 ASP.NET Web API 專案。(照理說是只要是 XML 的 .config 都通用,但我沒一一嘗試就是了)
如果,你正要開發一個 Web API 來自用?
如果,你需要提供 Web API 讓第三方(例如,手機App)呼叫?
如果,你需要串接其他第三方 Web API 來使用?
隨著 client 越來越多樣化,Web API 的重要性不言而喻,還沒趕上或是充滿迷惘?
2016年重磅規劃的課程,業界實戰的內容,走過路過,真的不要錯過!
.NET Core(ASP.NET Core)與之前的 ASP.NET MVC / ASP.NET Web API 兩套不同的 Framework 不同,ASP.NET Core 中的 MVC 整合了 Web API,現在要建立 API 或 Web 都將更為簡單,因為整合後的 ASP.NET Core MVC 基於相同的程式碼與管線(pipeline)。
ASP.NET Core 的跨平台特性,使用開發工具與開發環境的選擇相當多元。
.NET Core SDK 安裝:
安裝頁面有各平台(Windows, Linux, Mac, Docker)的安裝指南,照步驟安裝即可。
開發工具方面:
使用 Windows 的開發者,地表最強的 Visual Studio 當然是最好的選擇,如果使用 MAC(Windows) 那 VS Code + C# 擴充套件後也不差。如果 Visual Studio 2015 Update 3 並安裝了最新的 .NET Core Tooling Preview 2 for Visual Studio 2015 ,那麼已包含 .NET Core SDK 的安裝。
如果 VS Code + C# 擴充套件,使用起來不是很順(例如,IntelliSense、提示加 using 等),看一下 OmniSharp Log (檢視 → 切換輸出)是否正常。重開幾次 VS Code 看看。
測試工具:
兩套測試工具都行,挑喜歡的用即可。
範本工具:
安裝指令:
npm install -g yo
npm install -g generator-aspnet
這是延伸自 yeoman 的範本產生器,在不使用 Visual Studio 的情況下,它會很有幫助。
以下範例,讓我們使用 VS Code 來走一次建立 ASP.NET Core - Web API 的過程。相同的過程,使用 Visual Studio 的體驗與以前沒有太大差異,更重要的是,使用 VS Code 可以讓我們更瞭解 .NET Core 運作流程(因為要下指令),所以選擇使用指令與 VS Code 來進行實作。
自從「ASP.NET MVC 4網站開發美學」一書的Web API章節介紹Postman開始,Postman一路穩扎穩打,從網頁版到Chrome App版一直都是Web API(RESTful)開發人員的首選,Postman一個人用,真的超級好用,而且後來加上的Sync(同步)功能後,只要註冊一個帳號,不管你有幾電腦,登入之後通通全部自動同步完畢。像我家裡有二台筆電、公司有一筆電一桌機,有了"Postman + Sync"幾乎是個人完美的解決方案了。
可以瑞凡-現在不是一個人的世界了。
ASP.NET Web API一開始就以JSON.NET來取代JavaScriptSerializer以完成世代交替,JSON.NET的表現一直是中規中矩,以我的認知他是求穩。ASP.NET Web API採用Formatter的設計方式,預設有JsonFormatter與XmlFormatter,在求快的過程,如同頭文字D的86,換上一顆新F1引擎是最快的方式,我們來替ASP.NET Web API安裝一顆JilFormatter的高速引擎。
之前提到過如何使用路由傳遞含"+"符號到ASP.NET Web API 2有二種方式,一是使用QueryString,一是修改allowDoubleEscaping,不過allowDoubleEscaping的修改會降低系統安全性,是個不得以的選項。重覆的問題又活生生出現在面前,只是這一次必須把這個含+符號的值放在路由中。怎麼辦?有無更好的方式解決這個問題呢?
首先,第一次處理如何使用路由傳遞含"+"符號到ASP.NET Web API 2問題時,那是一段對稱加密的程式,因為是中間接手處理,沒有細看實作細節,我們以DESCryptoServiceProvider (DES 的實作)為例來說明:
private string Encryption(string plainText)
{
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("cipherText");
byte[] b = Encoding.UTF8.GetBytes(plainText);
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
ICryptoTransform ict = des.CreateEncryptor(des.Key, des.IV);
byte[] desData = ict.TransformFinalBlock(b, 0, b.Length);
return Convert.ToBase64String(desData);
}
看出問題點了嗎?
我們先看看這個的字串如果使用在路由上會產生什麼問題,以/{controller}/{action}/{id}路由為例:/home/index/EZ7+/+wvla4=,怎麼+號(加號)都還沒處理就馬上出事了?
看的出來了嗎?
有在寫MVC或Web API的人,第二個問題很直覺就能看出來了,多了一個「/」符號,此時就算設置allowDoubleEscaping讓路由能正常處理+號,id透過ModelBinding後還是不正常的。
回到問題一,看出問題了嗎?
日前很高興有機會去參加SkillTree的UWP 與 Microsoft Azure 實戰課程(臺北場)課程,其中一個段落正是在介紹HttpClient APIs,我才知道目前的HttpClient在UWP有兩個實作:System.Net.Http.HttpClient 類別與Windows.Web.Http.HttpClient 類別。它們兩個都應優先於WebClient和HttpWebRequest來使用。
這引起了我的好奇。看了一些文章與討論區,都沒有感到滿意的回答。最近剛好看到一篇官方 Blog 的文章,正是討論兩者的差異,覺得交代的很清楚,以下是我不負責簡單翻譯加筆記。
我們需要傳遞一個加密過的參數,此加密方法產生有一定機會產出含"+"符號的亂數。"+"符號在網路傳遞過程中會有一些問題,常見的解決辦法是傳遞前後使用Encode與Decode方法來針對特殊符號進行加解密。但在Web API 2比較難處理。
在預設的Web API 2範本及預設的路由"api/{controller}/{id}"設置下,簡單進行兩個測試:
以QueryString方式"/api/values?id=1%2b1"進行請求。這裡的%2b是"+"符號Encode的代表號。這個測試可以順利到達Get(string id)方法之內。
BaseController與BaseApiController類別技巧不算是ASP.NET MVC或ASP.NET Web API的技術,它是一個OOP(Object-oriented programming,物件導向程式設計)繼承的應用,這在早期Web Forms就已經被大量使用,因為它只是單純的OOP繼承應用,並不會被語言或框架所限制。
我們先來看看我們在進行開發的Controller類別繼承關係:
ControllerBase類別繼承自IController介面,Controller類別繼承自ControllerBase類別,而ControllerBase與Controller都是抽象類別:
public abstract class ControllerBase : IController {}
public abstract class Controller : ControllerBase, IActionFilter, IAuthenticationFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IAsyncManagerContainer {}
而我們開發者所在的ASP.NET MVC的Controller都是繼承自Controller抽象類別,Controller抽象類別提供開發者所需的大部分功能:
public class HomeController : Controller {}
從程式設計的角度來看,ASP.NET MVC的Controller也只是一個類別。如果你發現自己在其他Controller寫了完全相同邏輯的程式碼(相同的成員、屬性或方法等),那麼我們有非常合理的理由來建立一個共用的基礎類別,之後將Controller裡相同的成員、屬性或方法往上層的基礎類別移動,Controller只需重新繼承此基礎類別,就能發揮物件導向的繼承的優勢。