【问题标题】:WCF - Measuring approximate message sizes programmaticallyWCF - 以编程方式测量近似消息大小
【发布时间】:2009-07-02 12:09:49
【问题描述】:

给定一个类:

[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)。

【问题讨论】:

    标签: wcf datacontractserializer


    【解决方案1】:

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

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

    【讨论】:

    • 感谢 tomasr。我不想更改绑定。我想做的是写一些测试用例来证明消息大小的差异,但我不想每次都用 WireShark 窥探。
    • Drew:这也是可能的。我在这里发布了一个示例应用程序,展示了如何做到这一点:winterdom.com/2009/07/…
    • 啊,这看起来更像我所追求的。我明天上班试试,然后回复你。非常感谢!
    • 我在另一个答案中总结了代码中的方法:stackoverflow.com/questions/1074008/…
    【解决方案2】:

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

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

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

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

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

    (当然,&lt;client&gt; 部分中的客户端同样适用)。

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

    马克

    编辑(留下评论后):
    好吧,WCF 确实是非常可扩展的,因此您可以像消息检查器一样在离开客户端时执行此操作。您可以编写这样一个消息检查器(源自IClientMessageInspector),它只检查消息并测量其大小并将其写入文件或数据库

    【讨论】:

    • 感谢 Marc 的回答。这很有趣,但不是我要问的。我真的只想使用 NetTcpBinding 使用的任何二进制格式来测量将为特定对象发送的字节数,但来自代码。我正在努力减少在线大小,使用小型应用程序或单元测试比使用客户端/服务器和数据包嗅探器更容易做到这一点。
    【解决方案3】:

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

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

    然后你会想了解XmlDictionaryWriter

    【讨论】:

    • @John - 我看不出 XmlDictionaryWriter 有什么帮助。它是一种具有许多抽象成员的抽象类型,我在框架中找不到它的任何公共实现。你能详细说明一下吗?
    【解决方案4】:

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

    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

    【讨论】:

    • 你和消息检查器一起使用吗?我的意思是,你在哪里挂钩该方法。
    猜你喜欢
    • 1970-01-01
    • 2012-03-18
    • 2011-12-12
    • 1970-01-01
    • 2010-09-27
    • 1970-01-01
    • 1970-01-01
    • 2010-10-28
    • 2011-11-27
    相关资源
    最近更新 更多