给出一个课程:
[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
)。
答案 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()
...取决于您是想要文本格式还是二进制格式化。