周遭幾個系統正面臨相似抉擇:使用.NET Remoting的舊程式,需與伺服器建立連線進行高頻率雙向傳輸,計劃翻寫新版本。.NET Remoting是.NET 2.0時代的技術,十年後多了不少選擇:WCF、Web API、SingalR… 選擇變多煩惱跟著來,該怎麼選擇才對?

面對這道選擇題,我只有模糊的概念,趁此機會整理我的個人看法,也歡迎大家回饋。

.NET Remoting是2.0時代的產物,在微軟Roadmap中已被WCF取代(.NET Remoting做得到的事,理論上WCF都可以實現):參考來源

.NET Framework 2.0以及前版本中,微軟發展了Web ServiceSOAP with HTTP communication),.NET RemotingTCP/HTTP/Pipeline communication)以及基礎的Winsock等通訊支援,由於各個通訊方法的設計方法不同,而且彼此之間也有相互的重疊性(例如.NET Remoting可以開發SOAP, HTTP通訊),對於開發人員來說,不同的選擇會有不同的程式設計模型,而且必須要重新學習,讓開發人員在使用者有許多不便。同時,服務導向架構Service-Oriented Architecture)也開始盛行於軟體工業中,因此微軟重新檢視了這些通訊方法,並設計了一個統一的程式開發模型,對於資料通訊提供了最基本最有彈性的支援,這就是Windows Communication Foundation

基於這點,.NET Remoting選項應該可以剔除,因此它屬於.NET 2.0,微軟策略上以WCF取而代之,未來不再投入資源開發,可用資源(文件、KB)只會愈來愈少。依據微軟一份效能測試,WCF在效能上比ASP.NET Web Service快了25%-50%,比.NET Remoting快25%,棄.NET Remoting改用WCF將有效能上的突破。最後,就由微軟.NET Remoting官方介紹加註於文首的聲明來補最後一刀:

This topic is specific to a legacy technology that is retained for backward compatibility with existing applications and is not recommended for new development. Distributed applications should now be developed using theWindows Communication Foundation (WCF).
【翻譯】此文所言乃古物,未刪只因相容故;君若有緣開新局,勿疑逕取WCF

由此說來,WCF是取代Web Service及.NET Remoting的接班人無誤。這些年來,Web/HTTP的各式應用當紅,WCF仍持續發展,但熱度及受矚目程度明顯不如可以輕鬆跨平台接軌的Web API。然而,Web API能全面取代 WCF嗎?倒也未必,MSDN有張比較表,指明二者特色:參考

WCF ASP.NET Web 應用程式開發介面
能支援多重傳輸通訊協定 (HTTP、TCP、UDP 和自訂傳輸) 的建置服務,並允許兩者切換。 僅限 HTTP。 適用於 HTTP 的第一級程式設計模型。更適合從各種不同的瀏覽器、行動裝置等項目進行存取,確保廣泛連線。
適用於支援相同訊息型別之多重編碼 (文字、MTOM 和 Binary) 的建置服務,並允許兩者切換。 能建置支援各種媒體型別的 Web 應用程式開發介面,包括 XML、JSON 等。
支援 WS-* 標準的建置服務,例如可信賴傳訊、交易、訊息安全性。 使用基本通訊協定和格式,例如 HTTP、WebSockets、SSL、JQuery、JSON 和 XML。不支援層級較高的通訊協定,例如可信賴傳訊或交易。
支援要求-回覆、單向和雙工訊息交換模式。 HTTP 可進行要求/回應,其他模式則可透過 SignalR 和 WebSockets 整合來支援。
您可在 WSDL 中說明 WCF SOAP 服務,以利自動化工具產生用戶端 Proxy (亦適用於包含複雜結構描述的服務)。 不論是從自動 HTML 說明頁面說明片段到 OData 整合之應用程式開發介面的結構化中繼資料,都有各種說明 Web 應用程式開發介面的方式。
隨附於 .NET Framework。 隨附於 .NET Framework,但為開放原始碼且可透過頻外個別下載取得

二者相比,WCF功能強大許多,支援各種通訊協定、訊息編碼格式、安全管控,透過設定檔就能自由切換,且Visual Studio支援完整,加入WCF參照就會自動產生Proxy類別,用起來跟本地物件沒兩樣,但是,WCF設定過於複雜一直為人垢病。(我的觀察啦)

WFC因功能強大,支援協定、格式眾多,設定複雜度直逼747儀錶板,有數十上百個參數可供組合調整,稍有不慎便可能出錯,光處理設定茶包就飽了,踩過雷者莫不聞風喪膽。這窘境或許起因於很少人下功夫研究過WCF設定(Visual Studio使用者已習慣凡事拖拖拉拉點點選選就該搞定,花上一天讀文件學習「如何調設定檔」?成何體統!),缺少人性化GUI設定介面,系統出錯時,往往「不知道哪裡沒設好,瞎試一通搞定又不知為什麼就變好」,挫折經驗一多,WCF就像陰晴不定、喜怒無常的公主病女王,若非受虐狂,誰會有好感?換個角度,若能徹底搞懂serviceBehaviors、endpoint、wsHttpBinding、mexHttpBinding… 這堆鬼東西,熟悉其代表意義(我直接承認我不懂),WCF設定或許沒這麼可怕,遇到系統出錯馬上有明確追查方向,狀況應會改觀。

這幾年工作都繞著瀏覽器、行動裝置打轉,讓我偏愛Web API。最主要考量是Web API在不同開發平台都能找到現成程式庫及技術資源,只要有能力發送HTTP Request跟解析JSON就能引用,寫Web API時不必操心客戶端能否支援。(我最愛的一點是「都走Web API還不知道怎麼接,要嘛是客戶端開發者能力不足,要嘛是他們的語言工具太鳥,絕對與我們無關」XD)

撇開客戶端是手機或非.NET平台的案例不談,拉回服務端與客戶端都是.NET的情境,此時Web API的跨語言支援廣泛優勢不再,反過頭來還損失Visual Studio為WCF自動建立強型別資料物件及Proxy類別的一整套便利機制。為此,我多半會自己搞Code Gen機制在Web API C#端、TypeScript端同時建立對應的強型別物件,順帶產生C# Proxy供.NET Web API客戶端使用,自己做完一堆粗活。即便如此,採用Web API仍有不少好處-部署設定方便,失敗率極低,最吸引人的一點是,只要開個瀏覽器就能測試偵錯,不像WCF還得依賴WCF Storm之類的第三方工具(即使用現成工具還是常常觸礁)才能查問題,這點深得我心。不過,這個比較觀點忽略「為Web API量身打造類似Visual Studio WCF自動類別/Proxy產生器」所投入成本,並不全然客觀。

重新拉回服務端與客戶端都是.NET的場景,若你不想自己處理TCP連線、序列化反序列化、產生強型別物件、Proxy…等細節,WCF仍是較佳的選擇,可享受現成的Framework、開發工具支援,至於WCF難以駕御的問題,恐得花點時間搞懂WCF設定的諸多細節,等能玩弄其於股掌之間,或許能和WCF做好朋友。

若需求涉及高頻率的資料交換,還有另一種選擇:「自訂封閉式傳輸協定」。最典型做法是Client/Server間建Socket傳資料,依據系統需求自訂通訊協定,理論上如此可達到最佳傳輸效率,但得自已搞定通訊協定、序列化規則、TCP連線處理(容錯、斷線重連)等細節,有一定的複雜度,若能做到夠穩定夠強韌,在速度及效率上得到的回報將能徹底擊敗WCF,但要付出相當的開發成本。若要選擇自訂傳輸協定,有一些Framwork可以協助處理底層的TCP/Socket傳輸細節,省去可觀的功夫。例如:

最後,總結我的抉擇觀點:

  • 速度!速度!速度!
    自建Socket連線是較佳的選擇,但要寫出強韌可靠的Socket底層難度不低,可考慮借用現有Framework。
  • 彈性+速度
    WCF使用TCP加二進位格式,效能可直追Socket,也可掛在網站跨越網際網路溝通。不動程式只改設定就能切換不同傳輸通道,如果你沒被設定檔搞瘋的話,但需花點心思研究設定才能成功駕御。
  • 跨平台跨語言跨裝置+簡單
    如果客戶端很多樣化跨越多種平台、語言、裝置,Web API是最佳選擇。或者你不喜歡太複雜的設定,加上HTTP協定+JSON的效能表現就能滿足要求,Web API只要懂Web就能寫、只要有瀏覽器就能測,應是最容易上手的選項。
  • 鍾愛古玩+能忍孤寂
    就選.NET Remoting吧!願原力與你同在~

Comments

# by jerfong

怎麼沒有比較 WCF的雙向溝通 及 ASP.NET SignalR?

# by Jeffrey

to jerfong, 好問題。依我的看法,WCF跟SignalR都能實現雙向溝通,SignalR倨限於HTTP協定,WCF則提供較多的彈性(TCP Socket、HTTP都行);但如果Client端是JavaScript,SignalR有現成的Library可用,WCF則需要自己從C#再串接到JavaScript端。

# by 毛豆

需與伺服器建立連線進行高頻率雙向傳輸,計劃翻寫新版劃(x)。 需與伺服器建立連線進行高頻率雙向傳輸,計劃翻寫新版本(o)。 socket 每寫一次挫折感就多一次,最後只得自己寫個簡易的架構,讓其它模組只把需要傳的訊息丟進核心,讓核心進行溝通就好了。

# by Jeffrey

to 毛豆,感謝指正。處理Socket必須留意的細節真的很多,但要求速度時,很難找到比它更有效率的結果方案。

Post a comment