I have a WCF Service with HTTP bindings which returns dataset on 500k size. When using WCF default logging I can see the messages and data being transfered with each message
<system.serviceModel>
<!-- add trace logging -->
<diagnostics wmiProviderEnabled="true">
<messageLogging
logEntireMessage="true"
logMalformedMessages="true"
logMessagesAtServiceLevel="true"
logMessagesAtTransportLevel="true"
maxMessagesToLog="3000"
/>
</diagnostics>
....
<system.diagnostics>
<sources>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add type="System.Diagnostics.DefaultTraceListener" name="Default">
<filter type="" />
</add>
<add initializeData="c:\nettcpTestLOCALToTEST.xml" type="System.Diagnostics.XmlWriterTraceListener"
name="messages">
<filter type="" />
</add>
</listeners>
</source>
</sources>
</system.diagnostics>
Point is, I am looking for a way to reduce the traffic between server and client, and I have been told that NetTCP is transferring the data binary? Is that correct?
I have set up a test scenario with a NetTCPBinding and when I read the WCF on the client side, the Response Message includes the whole dataset schema and data in XML format. Is it just serialized so the can be written to a log, or was this message transfered binary?
Is the amount of data being transfered with a NetTCP binding smaller than with HTTPBinding? Is it text or binary?
thanks in advance
yes the message will be transfered binary but the Serializer (Datacontractserializer I assume) will serialize the data in XML format:
Use the DataContractSerializer class to serialize and deserialize instances of a type into an XML stream or document
DataContractSerializer From the docu:
The NetTcpBinding generates a run-time communication stack by default, which uses transport security, TCP for message delivery, and a binary message encoding. This binding is an appropriate system-provided choice for communicating over an Intranet.
If you opt to implement ISerializable you can use WCF too but you have to implement an DataContractResolver to resolve the types: if the client "knows" the Types (for example you put them into a dll and add them to the client-app) you can use the following example-code (sorry I only have this in F# around but you should find it easy to translate) This should yield the serialization in more compact form.
type internal SharedTypeResolver() =
inherit System.Runtime.Serialization.DataContractResolver()
let dict = new Xml.XmlDictionary()
override this.TryResolveType(t : Type, declaredT : Type, knownTypeResolver : System.Runtime.Serialization.DataContractResolver, typeName : Xml.XmlDictionaryString byref, typeNamespace : Xml.XmlDictionaryString byref) =
typeNamespace = dict.Add(t.Assembly.FullName)
typeName = dict.Add(t.FullName)
true
override this.ResolveName(typeName : string, typeNamespace : string, declaredType : Type, knownTypeResolver : System.Runtime.Serialization.DataContractResolver) =
let res = knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null)
if res = null then Type.GetType(typeName + ", " + typeNamespace) else res
PS: found the same in C#:
public class SharedTypeResolver : DataContractResolver
{
#region Overrides of DataContractResolver
///
/// Override this method to map a data contract type to an xsi:type name and namespace during serialization.
///
///
/// true if mapping succeeded; otherwise, false.
///
/// The type to map.The type declared in the data contract.The known type resolver.The xsi:type name.The xsi:type namespace.
public override bool TryResolveType(Type type, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace)
{
if (!knownTypeResolver.TryResolveType(type, declaredType, null, out typeName, out typeNamespace))
{
var dict = new XmlDictionary(); // nice trick to get the right type for typeName
if (type != null)
{
typeNamespace = dict.Add(type.Assembly.FullName);
typeName = dict.Add(type.FullName);
}
else
{
typeNamespace = dict.Add("noAss");
typeName = dict.Add("noType");
}
}
return true;
}
///
/// Override this method to map the specified xsi:type name and namespace to a data contract type during deserialization.
///
///
/// The type the xsi:type name and namespace is mapped to.
///
/// The xsi:type name to map.The xsi:type namespace to map.The type declared in the data contract.The known type resolver.
public override Type ResolveName(string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver)
{
return knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null) ??
Type.GetType(typeName + ", " + typeNamespace);
}
(Please note: stackoverflow don't like the assignmentoperator "<-" from F# and i don't know how to circumvent - therefore I used "=") oh well - I guess I have to say how to add those resolvers to your host:
private static void AddResolver(OperationDescription operationDescription)
{
if (operationDescription == null)
throw new ArgumentNullException();
var serializationBehavior = operationDescription.Behaviors.Find();
if (serializationBehavior == null)
{
serializationBehavior = new DataContractSerializerOperationBehavior(operationDescription);
operationDescription.Behaviors.Add(serializationBehavior);
}
serializationBehavior.DataContractResolver = new SharedTypeResolver();
}
use this with:
var contrDescription = _host.Description.Endpoints[0].Contract;
var description= contrDescription.Operations.Find("MyServiceMethod");
AddResolver(description);
replacing "MyServiceMethod" by the name of your service-method (on call per method or you iterate over all of them)