2009-08-15 137 views
16

我有一個客戶端 - 服務器應用程序,它使用WCF進行通信,並使用NetDataContractSerializer來序列化對象圖。由於大量數據在服務器和客戶端之間傳輸,我試圖通過微調數據成員的大小(例如,將int更改爲short,long更改爲int等)來減小其大小。以二進制方式序列化WCF消息,而不是SOAP消息

完成調整後,我發現傳輸的數據量沒有變化!
問題是,NetDataContractSerializer會將對象圖形序列化爲XML,因此無論數據成員的大小如何,唯一重要的是其值的大小。例如,Int16數據成員的值10023將被串行化爲字符串「10023」(0x3130303233),而不是10023(0x2727)。

我記得在Remoting中,我可以使用BinaryFormatter根據數據成員的類型對值進行序列化,但我不知道是否有可能將它與WCF結合使用。

有人有解決方案嗎?

回答

35

WCF使用SOAP消息,但是使用什麼樣的消息編碼,完全取決於您。

基本上,開箱即用,您有兩種:文本編碼(XML消息的文本表示)或二進制編碼。如果您確實需要並且需要,您可以編寫自己的消息編碼。

開箱即用,basicHttp和wsHttp綁定使用文本編碼 - 但如果需要,您可以更改它。 netTcp綁定(這是企業防火牆背後的首選)將默認使用二進制。

您還可以定義(只是在配置)自己的「二元HTTP」協議,如果你想:

<bindings> 
     <customBinding> 
     <binding name="BinaryHttpBinding"> 
      <binaryMessageEncoding /> 
      <httpTransport /> 
     </binding> 
     </customBinding> 
    </bindings> 

,然後在服務和客戶端的配置使用它:

<services> 
     <service name="YourService"> 
     <endpoint 
      address="http://localhost:8888/YourService/" 
      binding="customBinding" 
      bindingConfiguration="BinaryHttpBinding" 
      contract="IYourService" 
      name="YourService" /> 
     </service> 
    </services> 

現在你有一個基於http的傳輸協議,它將以緊湊的二進制編碼你的消息,供你使用和享受!

沒有額外的編碼或凌亂的黑客或大量的手動XML序列化代碼需要 - 只需將它插在一起,並使用它!啊,WCF靈活的快樂!

+0

因此,沒有二進制消息編碼提供了顯著的性能提升?序列化時間是否縮短,還是僅僅減少了消息大小? – 2012-08-02 15:08:07

+0

我已經使用這個自定義綁定以及帶命名管道傳輸的binaryMessageEncoding,並且消息仍然是按照跟蹤偵聽器中的消息日誌以及WCF測試客戶端的XML編碼。我不是100%確信他們沒有做他們自己的XML序列化對象來記錄他們,而是採取原始信息。 WCF很難將原始請求/響應與WebAPI掛鉤,從而使其變得簡單。 – AaronLS 2014-10-31 06:11:34

+0

這個答案很有幫助,但請注意,二進制編碼只會改變消息在線路上的發送方式,即在串行化之後。雖然這肯定會減少數據大小,但它不會更改序列化方法。二進制編碼可以與壓縮一起使用以獲得更好的結果。 – 2017-01-04 13:32:46

6

首先想到的;你有沒有啓用傳輸壓縮?

數據有多複雜?如果它適用於常規的DataContractSerializer(即簡單的對象樹),那麼protobuf-net可能有用。這是一個非常有效的二進制序列化庫通過服務合同上的附加屬性爲WCF的支持 - 例如:

[ServiceContract] 
public interface IFoo 
{ 
    [OperationContract, ProtoBehavior] 
    Test3 Bar(Test1 value); 
} 

(該[ProtoBehaviour]就是在不同的串行交換此方法)

但是:

  • 它需要能夠識別數字標籤爲每個屬性 - 或者通過額外的屬性,或者它可以在[DataMember(Order = x)]屬性使用Order
  • 繼承(如果你正在使用它)需要額外的屬性
  • 它效果最好,如果你正在使用組件共享(「MEX」不愛它...)

得很漂亮,它也可以與MTOM,降低大型郵件的基礎64成本。

1

二進制編碼器不會以二進制序列化您的對象,因爲它與序列化完全無關!它是在較低層工作並決定如何在服務器和客戶端之間傳輸消息。

換句話說,對象將首先被序列化(例如DataContractSerializer),然後被編碼(通過BinaryEncoder)。因此,只要涉及到DataContractSerializer,您的對象將始終採用XML格式。

如果你想要一個更緊湊的數據和更好的性能,請閱讀這篇博客:

https://blogs.msdn.microsoft.com/dmetzgar/2011/03/29/protocol-buffers-and-wcf/

1

下面是如何使這裏自定義編碼https://www.codeproject.com/Articles/434665/WCF-Serialization-A-Case-Study

的例子值得一提的是,實際上什麼獲取發送的結果與您使用默認編碼發送byte []的服務方法相同。無論如何配置序列化,通過連線的消息仍然使用SOAP XML信封。

它看起來像這樣:

POST http://127.0.0.1:12345/forSwerGup182948/Client HTTP/1.1 
Content-Type: text/xml; charset=utf-8 
VsDebuggerCausalityData: uIDPo+WkoDpet/JOtGlW+EHdpDQAAAAAvFs5XOJ0tEW0wTvNVRDUIiabR6u+p+JNnd5Z+SWl1NcACQAA 
SOAPAction: "http://tempuri.org/ITransmissionService/SendData" 
Host: 127.0.0.1:12345 
Expect: 100-continue 
Accept-Encoding: gzip, deflate 
Content-Length: 2890 

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><SendData xmlns="http://tempuri.org/"><message>eyI8Q2FsbGJhY2tJZD5rX19CYWNraW5nRmllbGQiOiJlYTQ3ZWIzMS1iYjIzLTRkODItODljNS1hNTZmNjdiYmQ4MTQiLCI8RnJvbT5rX19CYWNraW5nRmllbGQiOnsiPENoYW5uZWxOYW1lPmtfX0JhY2tpbmdGaWVsZCI6Ikdyb3VwMSIsIjxOYW1lPmtfX0==</message></SendData></s:Body></s:Envelope>