近兩年看到很多介紹WCF分布式開發的文章,很少看到有深入介紹.NET Remoting開發的文章,似乎Remoting技術逐漸從大眾的視野中消失了一樣。自從2005年發布這個名稱為Indigo的技術以來,WCF逐漸成為.NET分布式開發的事實標准。然後微軟沒有推崇和更新的技術,像我們這樣的第三世界國家,唯微軟馬首是瞻,也紛紛轉向WCF技術的實踐與開發。近期看到世界對SilverLight技術前展的擔憂,就看到很明顯的傾向。一個以擅長開發平台(Platform,.NET)和開發工具(Visual Studio,SQL Sever)的公司,居然也能控制大量的中下游開發商的技術選擇傾向,一想到最近在做的工作流WF的升級(.NET 3.0到.NET 4.0)的尴尬處境,令人歎息不已,這也許是IT產業鏈的特色。
我要提出的的觀點是,作為通訊技術架構的.NET Remoting,並沒有從我們的視野中消失,反而有很多產品還是繼續使用和維護以.NET Remoting作為通訊架構方式。我所看到的產品,是上市公司的產品,年收入是百萬級別的產品,不用懷疑它是小企業的小應用。所以,我要討論一下,為什麼.NET Remoting沒有過時,更沒有out。
先來看一下,要能成為企業應用的通訊架構技術基礎,要滿足的條件
抽象的說了這幾點,不容易理解,來舉例說明。在ERP系統中,是如何做到簡單靈活的應用通訊技術的。以銷售系統為例子,來看看它的架構方式。
消息格式定義 銷售單
[Serializable] public partial class SalesOrderEntity : CommonEntityBase { public virtual System.String PriceCode { get { return (System.String)GetValue((int)SalesOrderFieldIndex.PriceCode, true); } set { SetValue((int)SalesOrderFieldIndex.PriceCode, value); } } public virtual System.String VendorNo { get { return (System.String)GetValue((int)SalesOrderFieldIndex.VendorNo, true); } set { SetValue((int)SalesOrderFieldIndex.VendorNo, value); } } }
銷售單只舉例了兩個屬性,賣價編碼和供應商商編碼,在定義實體時,加Serializable特性表示可以序列化傳遞。
服務接口定義 保存銷售單
public interface ISalesOrderManager { SalesOrderEntity SaveSalesOrder(SalesOrderEntity salesOrder); }
服務實現 保存銷售單
public sealed partial class SalesOrderManager : ISalesOrderManager { public SalesOrderEntity SaveSalesOrder(SalesOrderEntity salesOrder) { ..... } }
應用服務,保存銷售單的窗體
ISalesOrderManager salesOrderManager = ClientProxyFactory.CreateProxyInstance<ISalesOrderManager>();
這就是所有的代碼,從銷售單的消息格式定義到定義服務和接口與實現,最後是如何應用服務,這四塊代碼,包含了上面所講的全部內容,而它的實現,就是運用.NET Remoting來作為通訊技術平台。
我想肯定有很多第三方的工具廠商,也已經實現類似於.NET Remoting和WCF的的通訊框架,但是考慮到成本(cost),效率,可維護性,WCF和.NET Remoting是免費的,不需要任何成本,普及性好,名家出身,這會排擠大量的中小企業的商業的通訊框架。
從上面的代碼可以看出來,一部分是標准的做法,定義接口和實現,另一部分,有一個關鍵的類型ClientProxyFactory,來充當了通訊的橋梁,它就是基於.NET Remoting技術而構建的通訊框架。這個框架可以處理好下面的場景:
1 客戶端的連接,服務器要能控制。服務器可以控制是否接受客戶端的連接請求,以保證系統不會負荷過載。
2 服務器崩潰,客戶端要得到通知,並能重新連接。這一點很重要。服務器因各種原因停止運行後,客戶端要可以馬上得到消息,並保存當前操作,阻止用戶繼續使用系統。試想一下,服務器因為斷電停止運行後,客戶端程序還在繼續輸入銷售單,當用戶准備保存時,卻又提示服務器拒絕請求。
3 可以打包數據,加密,到服務器段解析出來。對於重要的數據,這個功能點很重要。
4 並發控制,控制可以並發使用的用戶數量。同時在線的用戶,允許執行的功能,服務器都有記錄。
5 安全控制,阻止其它類型的應用程序連接服務器,防止攻擊
6 傳送功能 客戶端向服務器,傳送大文件,傳送圖片,傳送需要的內容,文字,傳送錯誤報告,傳送截屏。
7 廣播功能,一個客戶端可以向連接中的其它所有客戶端傳送消息。比如,ERP系統管理員,可以通知所有的正在連接並使用系統的用戶,暫時退出,需要更新系統。服務器可以對所有客戶端廣播,前面提到的服務器停止運行,所有客戶端要中斷運行,也是服務器向客戶端的廣播。
有了這麼多的現成的解決方案,所以公司的通訊框架一直都是用.NET Remoting,而不會升級到WCF。而且一旦穩定之後,把.NET Remoting技術升級為另一種技術WCF,對系統而言,簡直是一場災難。要知道,大量的測試,是通過一個個byte來比較過的,確認無誤的才投入使用。
如果你有基於WCF的成熟的通訊架構的應用,應該把它應用到產品中,並且不斷的改善,精進。如果沒有,我還是推薦你看一下那7條需求列表,對比一下,如何在WCF或是Remoting技術來實現它,應用它,而不是總在說WCF是如何的好,如何的靈活方便。我研究了WCF之後,反而覺得它太靈活了,需要你做出選擇的地方太多了。這並不總是好事情。
在升級WCF時,我遇到這個問題,與你分享我的經驗。在.NET Remoting中,標准的接口定義成這樣:
public interface IVendorManager { VendorEntity GetVendor(String VendorNo); VendorEntity GetVendor(String VendorNo, IPrefetchPath2 prefetchPath); }
把它升級成WCF的接口,就要這樣:
[ServiceContract()] [ServiceKnownType(typeof(VendorEntity))] public interface IVendorManager { [OperationContract(Name = "VendorNo")] VendorEntity GetVendor(String VendorNo); [OperationContract(Name = "VendorNoPrefetchPath")] VendorEntity GetVendor(String VendorNo,IPrefetchPath2 prefetchPath); }
原因是WCF不支持方法重載(overload),要加上Name特性才行。現在,要變成WCF方式的調用,這樣的代碼就跑不通,
IVendorManager vendorManager = ClientProxyFactory.CreateProxyInstance<IVendorManager>();
VendorEntity express=vendorManager.GetVendor(“DHL”);
因為在WCF中,給一個參數的GetVendor方法加了別名為VendorNo,它的調用應該是這樣的:
VendorEntity express=vendorManager.VendorNo(“DHL”);
框架是運行時來綁定的,而在編譯時,我又不希望WCF來幫忙我生成IVendorManager接口的VendorNo方法,
那上面的代碼就無法通過編譯,要用到反射,獲取GetVendor的特性VendorNo值,並以VendorNo為方法名來調用。這樣,客戶端接口不用做任何改變,就可以把.NET Remoting升級到WCF,秘密全都在ClientProxyFactory類型的CreateProxyInstance方法裡面,也就是一個成熟的通訊框架。
讀過這篇文章後,你或許可以體會到了,把系統從.NET Remoting升級到WCF,客戶端代碼幾乎不用改動,很有效率。
讀大學時,看到設計模式的作者,推薦按照接口編程,我也向你推薦這種方式,按照接口編程。