WCF - Measuring approximate message sizes programmatically

Given the class:

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

WireShark shows that when sending via WCF TCP binding, the message encoding is in binary format (only for printed characters, but you get the idea):

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

But if I serialize an instance of this type, for example ...

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

... then the stream contains SOAP XML resembling this:

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

So my question is: how can I control a DataContractSerializer to create this binary representation in my own code?

Aside:

As you can see, the message is inflated by the fact that the object property must have its type encoded (therefore, a URI). I am going to change this to use a custom binary encoding, as in my scenario, the field identifier determines the type (in this case, double ).

+4
source share
4 answers

TCP binding uses a binary message encoder by default, where, as you simply serialize the data contract in XML in the second example. What happens to the binary message encoder is that it basically provides a data contract serializer with a custom implementation of XmlWriter that generates its own binary format instead of XML.

If you want to use this with a different binding (say HTTP), then you need to create a custom binding and add a BinaryMessageEncodingElement instead of the regular TextMessageEncodingElement element.

+3
source

You cannot control the DataContractSerializer, but you can control your WCF binding, whether it will be serialized to text or binary.

As you noticed, NetTcpBinding is binary by default and therefore very compact and fast. For Http-based bindings, the default text is the interaction text, and therefore more verbose and less efficient.

But nothing prevents you from creating your own HTTP binding based on binary code - if you agree that compatibility with external clients leaves the window if you do so. This will ONLY work with your own internal clients that use the same custom binding.

Basically, you need to create your own custom binding from scratch - in the code or in the config. In config, this is pretty easy:

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

The two minimum parts that you must specify are the message encoding and the transport protocol — everything else is optional.

Now you can specify your WCF service and client to use this new, custom binary binding over HTTP:

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

(and the same also works for the client in the <client> section, of course).

You have it - it's not a matter of managing the DataContractSerializer in your code in any way, form or form - just create a custom binding and use it.

Mark

EDIT (after comments on the left):
Well, WCF is really very extensible, so you can do this as message inspectors when you exit the client. You can write a message inspector (derived from IClientMessageInspector ) that does nothing but check the message and measure its size and write its file or database

+1
source

Have you read the documentation on the DataContractSerializer ?

To use the DataContractSerializer, first create an instance of the class and an object suitable for writing or reading the format; for example, an instance of XmlDictionaryWriter. Then call the WriteObject method to save the data. To get the data, create an object corresponding to the reading of the data format (for example, XmlDictionaryReader for an XML document) and call the ReadObject Method.

Then you will want to read the XmlDictionaryWriter .

0
source

Here is the simplest solution I could find in this problem:

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

... where is the encoding parameter:

 new TextMessageEncodingBindingElement() 

... or...

 new BinaryMessageEncodingBindingElement() 

... depending on whether you want text or binary formatting.

Thanks to tomasr for a link to his article on this topic .

0
source

All Articles