2009-08-15 123 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>