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]
    public class CompositeType
    {
        bool boolValue = true;
        string stringValue = "Hello ";
        int intValue = 1;
 
        [DataMember]
        [ProtoMember(1)]
        public bool BoolValue
        {
            get { return boolValue; }
            set { boolValue = value; }
        }
 
        [DataMember]
        [ProtoMember(2)]
        public string StringValue
        {
            get { return stringValue; }
            set { stringValue = value; }
        }
 
        [DataMember]
        [ProtoMember(3)]
        public int 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不支援陣列格式的序列化,先前程式範例的

[OperationContract]
CompositeType[] GetDataUsingDataContract(CompositeType composite)

要改成

[OperationContract]
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序列化的重點:

  1. 將WCF參數或結果用到的自訂型別放到獨立DLL專案,WCF Service及WCF Client改參照獨立DLL
  2. 獨立DLL、WCF Client、WCF Service都要參照protobuf-net(可用NuGet安裝)
  3. 在自訂型別加上[ProtoContract]、[ProtoMember]
  4. 修改WCF Service設定,最終要為Service Endpoint加上behaviorConfiguration
  5. protonet-buf不支援陣列型別的序列化,若WCF參數或傳回值用到陣列, 需改用List<T>或IEnumerable<T> ,並記得在參照WCF服務時修改Collection Type
  6. 確認WCF Client的Endpoint設定也加上behaviorConfiguration

Comments

# by 小 B

Blog 文章字有點小,雖說瀏覽器可以放大,但總覺不方便。 如果可以大一些,看起來不會那麼累。

# by Jeffrey

to 小 B,謝謝建議,陸續接到不少類似反應,近期會試著調整。

Post a comment