WCF - 以编程方式测量近似消息大小

时间:2009-07-02 12:09:50

标签: wcf datacontractserializer

给出一个课程:

[DataContract]
public sealed class ChangedField
{
    [DataMember(Name="I")] public ushort FieldId { get; set; }
    [DataMember(Name="V")] public object Value { get; set; }
}

WireShark显示,当通过WCF TCP绑定发送时,消息的编码是二进制的(仅可打印字符,但您明白了):

  

ChangedFielda.I..a.V....e:double..e http://www.w3.org/2001/XMLSchema.s.....a.

但如果我像这样序列化这种类型的实例......

var ser = new DataContractSerializer(typeof(ChangedField));
var stream = new MemoryStream();
ser.WriteObject(stream, new ChangedField { FieldId = 1, Value = 1.23d });

...然后该流包含类似于此的SOAP XML:

<ChangedField>
  <I>1</I>
  <V i:type="a:double" xmlns:a="http://www.w3.org/2001/XMLSchema">1.23</V>
</ChangedField>

所以我的问题是如何控制DataContractSerializer在我自己的代码中生成这个二进制表示?

暂且不说:

正如您所看到的,由于object属性必须对其类型进行编码(因此为URI),因此消息会膨胀。我将更改此选项以使用自定义二进制编码,在我的方案中,字段ID确定类型(在本例中为double)。

4 个答案:

答案 0 :(得分:3)

TCP绑定默认使用二进制消息编码器,在第二个示例中,您只是将数据协定序列化为XML。二进制消息编码器发生的情况是,它基本上为数据协定序列化程序提供了一个自定义XmlWriter实现,该实现生成专有的二进制格式,而不是XML。

如果要将其与不同的绑定(例如,HTTP)一起使用,则需要创建自定义绑定,并添加BinaryMessageEncodingElement元素而不是正常的TextMessageEncodingElement。

答案 1 :(得分:1)

您无法控制DataContractSerializer - 但您可以在WCF绑定中控制它是否序列化为文本格式或二进制文件。

正如您自己注意到的那样,NetTcpBinding默认为二进制,因此非常紧凑和快速。为了互操作性,基于Http的绑定默认为Text,因此更冗长,性能更差。

但是没有什么可以阻止你创建自己的基于二进制的HTTP绑定 - IF 你愿意接受如果你这样做,那么与外部客户端的互操作性已经不在了。这仅适用于使用相同自定义绑定的内部客户端。

基本上,您需要做的是从头开始构建自己的自定义绑定 - 在代码或配置中。在配置中它非常简单:

<system.serviceModel>
  <bindings>
     <customBinding name="binaryHttpBinding">
        <binaryMessageEncoding />
        <httpTransport />
     </customBinding>
  </bindings>
</system.serviceModel>

必须指定的两个最小部分是邮件编码和传输协议 - 其他任何内容都是可选的。

现在,您可以指定您的WCF服务和客户端,以便他们使用这个新的自定义二进制HTTP绑定:

<system.serviceModel>
   <services>
      <service name="YourService">
         <endpoint address="http://whatever.com:8888/YourAddress"
                   binding=binaryHttpBinding"
                   contract="IYourContract" />
      </service>
   </services>
</system.serviceModel>

(当然,同样适用于<client>部分的客户端。)

你有它 - 它不是以任何方式,形状或形式控制代码中的DataContractSerializer的问题 - 只需创建一个自定义绑定并使用它。

马克

编辑(评论结束后):
好吧,WCF确实是非常可扩展的,所以你可以在客户端的出路上像消息检查员那样做。您可以编写这样的消息检查器(派生自IClientMessageInspector),它只检查消息并测量其大小并将其写入文件或数据库

答案 2 :(得分:0)

您是否阅读了DataContractSerializer上的文档?

  

要使用DataContractSerializer,   首先创建一个类的实例   和适合写作的对象   或阅读格式;例如,一个   XmlDictionaryWriter的实例。   然后调用WriteObject方法   坚持数据。要检索数据,   创建一个适合的对象   阅读数据格式(如   XML的XmlDictionaryReader   文档)并调用ReadObject   方法

然后,您需要阅读XmlDictionaryWriter

答案 3 :(得分:0)

这是我能找到的最简单的解决方案:

static byte[] Serialise(object obj, MessageEncodingBindingElement encoding)
{
    encoding.MessageVersion = MessageVersion.Soap12;
    var stream = new MemoryStream();
    var message = Message.CreateMessage(MessageVersion.Soap12, "", obj, 
       new DataContractSerializer(obj.GetType()));
    encoding.CreateMessageEncoderFactory().Encoder.WriteMessage(message, stream);
    return stream.ToArray();
}

... encoding参数是:

new TextMessageEncodingBindingElement()

...或...

new BinaryMessageEncodingBindingElement()

...取决于您是想要文本格式还是二进制格式化。

感谢tomasrlink to his article on this topic