Protocol Buffers是Google內部使用的跨語言資料格式標準,在資料體積及序列化/反序列化速度上表現亮眼,相信以下的Benchmark圖表已具備足夠的說服力,說明本文的研究動機:(Protocol Buffers拿下速度及資料量雙料冠軍)
圖表來源:http://theburningmonk.com/2014/08/json-serializers-benchmarks-updated-2/
protobuf-net是Protobol Buffers的.NET版實作,只需簡單的程序,我們就能在WCF以Protocol Buffers取代SOAP及WCF原有的二進位序列化。好啦,我騙大家的,換用protobuf-net有不少眉角,測試過程我還踩到雷。但在這次經驗也讓我體認到,WCF架構的彈性與周全,允許開發者抽換組裝處理程序的各個環節,設定複雜背後是有收獲的。
我們繼續沿用先前觀察SOAP XML資料傳輸量的IService1專案,動手改裝成protobuf-net版。第一步要將CompositeType抽取成獨立DLL給WCF Service及WCF Client參照,因為參照WCF服務自動產生的CompositeType型別無法保留protobuf-net設定。
將IService1.cs的CompositeType搬到獨立的WcfDto專案,先透過NuGet加入protobuf-net:
在原本的[DataContract] [DataMember]之外,再加入[ProtoContract]及[ProtoMember(n)]:
using ProtoBuf;
using System.Runtime.Serialization;
namespace WcfDto
{
[DataContract]
[ProtoContract]
publicclass CompositeType
{
bool boolValue = true;
string stringValue = "Hello ";
int intValue = 1;
[DataMember]
[ProtoMember(1)]
publicbool BoolValue
{
get { return boolValue; }
set { boolValue = value; }
}
[DataMember]
[ProtoMember(2)]
publicstring StringValue
{
get { return stringValue; }
set { stringValue = value; }
}
[DataMember]
[ProtoMember(3)]
publicint IntValue
{
get { return intValue; }
set { intValue = value; }
}
}
}
WCF Service參照WcfDto專案並用NuGet加入protobuf-net,接著要調整WCF Service端web.config設定,最終目的要調成如下設定。新増BehaviorExtension、EndpointBehavior,Service的Endpoint設定再指向新増的EndpointBehavior。
感覺有點複雜,用來示範WCF設定GUI編輯器操作好了。
開啟編輯器後先找到Advanced/Extensions/behavior element extensions,按New新増一筆。
名稱輸入protobuf,型別則可靠瀏覽protobuf.dll找出完整型別名稱。
下一步要新増Endpoint Behavior:
名稱輸入protoEndpointBehavior(可自由命名),按下Add鈕會帶出可用的擴充項目清單。
清單裡可找到剛才新増的protobuf:
接著再回到服務的兩個Service Endpoint設定,BehaviorConfiguration下拉選單就有protoEndpointBehavior可選,到這裡web.config設定就完成了,可以得到如先前擷圖的設定結果。
實做的心得是WCF設定編輯器提供了不少指引、提示,但效率遠不如直接編輯config檔,度過新手探索期, 大家應該還是會選擇直接編輯config吧。
這裡分享我踩到的一個雷:protobuf-net不支援陣列格式的序列化,先前程式範例的
CompositeType[] GetDataUsingDataContract(CompositeType composite)
要改成
List<CompositeType> GetDataUsingDataContract(CompositeType composite)
(或IEnumerable<CompositeType>也可以,不要用陣列就對了,否則傳回結果會維持SOAP XML,參考)
另外,WCF Client加入服務參照時,預設會將List<T>視為T[],繼續踩到protobuf-net的痛處,要記得調設定:(以上兩點花了我兩個小時才學會)
WCF Client也要比照WCF Service端,先NuGet安裝protobuf-net,並app.config加上behaviorExtension,behaviorConfiguration,Service的endpoint設定指向behaviorConfiguration。
一切設定妥當,用MNM觀察,可看到原本的SOAP XML:
變成<protobuf>CgKIARIF… 的特殊資料格式。
看起來節省不少體積,至於資料量有多少改善?賣個關子,下回再談。
歸納WCF改用protobuf-net序列化的重點:
- 將WCF參數或結果用到的自訂型別放到獨立DLL專案,WCF Service及WCF Client改參照獨立DLL
- 獨立DLL、WCF Client、WCF Service都要參照protobuf-net(可用NuGet安裝)
- 在自訂型別加上[ProtoContract]、[ProtoMember]
- 修改WCF Service設定,最終要為Service Endpoint加上behaviorConfiguration
- protonet-buf不支援陣列型別的序列化,若WCF參數或傳回值用到陣列, 需改用List<T>或IEnumerable<T> ,並記得在參照WCF服務時修改Collection Type
- 確認WCF Client的Endpoint設定也加上behaviorConfiguration