代码之家  ›  专栏  ›  技术社区  ›  Drew Noakes

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

  •  4
  • Drew Noakes  · 技术社区  · 15 年前

    给定一个类:

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

    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 double ).

    4 回复  |  直到 15 年前
        1
  •  3
  •   tomasr    15 年前

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

    如果您想将它与其他绑定(比如HTTP)一起使用,那么您需要创建一个自定义绑定,并添加 BinaryMessageEncodingElement 元素而不是普通的TextMessageEncoding元素。

        2
  •  1
  •   marc_s    15 年前

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

    正如您自己所注意到的,NetTcpBinding默认为二进制,因此非常紧凑和快速。出于互操作性的考虑,基于Http的绑定默认为文本,因此更详细,性能更低。

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

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

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

    你所需要的两个最小部分 必须 指定消息编码和传输协议-其他任何内容都是可选的。

    现在,您可以指定您的WCF服务和客户端,以便它们使用此新的自定义二进制over 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 )它只会检查消息并测量其大小,然后将其写入文件或数据库

        3
  •  0
  •   John Saunders KB22    15 年前

    你有没有阅读网站上的文档 DataContractSerializer ?

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

    然后你会想读到 XmlDictionaryWriter .

        4
  •  0
  •   Community Egal    7 年前

    以下是我能找到的解决问题的最简单方法:

    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()
    

    …这取决于您想要的是文本格式还是二进制格式。

    幸亏 tomasr 对于 link to his article on this topic