There are 2 settings on bindings in WCF related to encoding. Could someone please explain the conceptual difference between these 2 settings?
Thanks!
MSDN states the following:
TextEncoding: Gets or sets the character encoding that is used for the message text.
MessageEncoding: Gets or sets whether MTOM or Text/XML is used to encode SOAP messages.
So the first one (textEncoding) refers to the encoding of the characters in the message, and the second one (messageEncoding) specifies whether the SOAP message is encoded as text or MTOM (Machine Transmission Optimization Mechanism).
textEncoding allows you to specify a specific character set encoding of the text of the SOAP message, independent of what messageEncoding is set to. For messageEncoding, MTOM is used for " efficiently encoding binary XML elements within the context of a SOAP envelope", whereas Text is used for interoperability purposes.
The default for textEncoding is UTF8Encoding and the default for messageEncoding is Text.
Other listed options for textEncoding include:
ASCIIEncoding
UnicodeEncoding
UTF32Encoding
UTF7Encoding
Related
When invoking a service, my client code passes in data. One of the data members is a byte array, so WCF will automatically encode this into a base-64 string during serialization. The problem is, the data contract of the service is expecting a byte array, not a string, so deserialization of the data will result in an exception: Expecting state 'Element'.. Encountered 'Text' with name '', namespace ''
How do I work around this glitch?
I'm not sure I understand what you mean? What does the contract for your service look like? I very much doubt the problem is the base-64 serialization, unless your service is expecting the binary data encoded in hexbinary format instead.
Remember, you're using XML here, so binary data can't travel unencoded; it needs to be serialized into a text format that can be embedded in the SOAP envelope (unless you're using MTOM), and that's usually Base-64.
It can be caused by a mismatch between client and service. Did you try refreshing your client proxy (by updating the service reference for example)?
My solution was to manually alter the autogenerated data contracts from byte[] to int[]. The XML now passes validation because each element of the int array is put inside a separate element.
The drawback is having to manually alter the data contracts if you regenerate the files from WSDLs again.
I need to send byte[] array using WCF services and I care about message size and performance. My question is: Does WCF convert my binary data to Base64 string internally? (I use netTcpBinding) If it does, how to prevent it?
My contract looks almost as simple as
IMyService
{
byte[] GetData()
}
In terms of the actual XML, byte arrays are serialized as xs:base64Binary, which is a Base64 encoding (obviously).
However, when you specify the netTcpBinding, WCF uses a binary message encoding of that XML (BinaryMessageEncodingBindingElement) which will encode those bytes as a binary stream.
It's a bit of a convoluted process, but at the end of the day, if you're using any of the net* bindings, byte arrays will go over the wire as raw bytes, not base64 strings. That's one of many reasons why it's generally more efficient to use the TCP or Named Pipe bindings, if you can.
I have a client-server application, which communicates using WCF, and uses NetDataContractSerializer to serialize the objects graph.
Since a lot of data is transferred between the server and the client, I tried to decrease its size by fine tuning the size of the data members (e.g. changed int to short, long to int, etc.).
After finishing the tuning, I found out, that the amount of transferred data hasn't changed! The problem is, that the NetDataContractSerializer serializes the objects graph to XML, so no matter what's the size of the data-member, the only thing that matters is the size of its value. For example, the value 10023 of a Int16 data member will be serialized as the string "10023" (0x3130303233), instead of just 10023 (0x2727).
I remember that in Remoting I could use the BinaryFormatter which serialized the values according to the type of the data member, but I don't know if it's possible to use it with WCF.
Does someone have a solution?
WCF uses SOAP messages, but what kind of message encoding is used, is totally up to you.
Basically, out of the box, you have two: text encoding (text representation of XML message) or binary encoding. You can write your own message encoding, if you really must and need to.
Out of the box, the basicHttp and wsHttp bindings use text encoding - but you can change that if you want to. The netTcp binding (which is the clear preferred choice behind corporate firewalls) will use binary by default.
You can also define (just in config) your own "binary http" protocol, if you wish:
<bindings>
<customBinding>
<binding name="BinaryHttpBinding">
<binaryMessageEncoding />
<httpTransport />
</binding>
</customBinding>
</bindings>
and then use it in your service and client side config:
<services>
<service name="YourService">
<endpoint
address="http://localhost:8888/YourService/"
binding="customBinding"
bindingConfiguration="BinaryHttpBinding"
contract="IYourService"
name="YourService" />
</service>
</services>
Now you have a http-based transport protocol, which will encode your message in compact binary, for you to use and enjoy!
No additional coding or messy hacks or lots of manual XML serialization code needed - just plug it together and use it! Ah, the joy of WCF flexibility!
First thought; have you enabled transport compression?
How complex is the data? If it is something that would work with the regular DataContractSerializer (i.e. a simple object tree), then protobuf-net may be of use. It is a very efficient binary serialization library with support for WCF via additional attributes on the service contract - for example:
[ServiceContract]
public interface IFoo
{
[OperationContract, ProtoBehavior]
Test3 Bar(Test1 value);
}
(the [ProtoBehaviour] is what swaps in the different serializer for this method)
However:
it needs to be able to identify a numeric tag for each property - either via extra attributes, or it can use the Order on a [DataMember(Order = x)] attribute
inheritance (if you are using it) requires extra attributes
it works best if you are using assembly sharing ("mex" doesn't love it...)
Nicely, it also works with MTOM, reducing the base-64 cost for larger messages.
Here is an example of how to make custom encoding here https://www.codeproject.com/Articles/434665/WCF-Serialization-A-Case-Study
It's worth noting that what actually gets sent is the same as if you had a service method sending byte[] with default encoding. The message going over the wire still uses a SOAP XML envelope regardless of how you configure serialization.
It looks like this:
POST http://127.0.0.1:12345/forSwerGup182948/Client HTTP/1.1
Content-Type: text/xml; charset=utf-8
VsDebuggerCausalityData: uIDPo+WkoDpet/JOtGlW+EHdpDQAAAAAvFs5XOJ0tEW0wTvNVRDUIiabR6u+p+JNnd5Z+SWl1NcACQAA
SOAPAction: "http://tempuri.org/ITransmissionService/SendData"
Host: 127.0.0.1:12345
Expect: 100-continue
Accept-Encoding: gzip, deflate
Content-Length: 2890
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><SendData xmlns="http://tempuri.org/"><message>eyI8Q2FsbGJhY2tJZD5rX19CYWNraW5nRmllbGQiOiJlYTQ3ZWIzMS1iYjIzLTRkODItODljNS1hNTZmNjdiYmQ4MTQiLCI8RnJvbT5rX19CYWNraW5nRmllbGQiOnsiPENoYW5uZWxOYW1lPmtfX0JhY2tpbmdGaWVsZCI6Ikdyb3VwMSIsIjxOYW1lPmtfX0==</message></SendData></s:Body></s:Envelope>
The binary encoder will NOT serialize your object in binary, because it has nothing to do with serialization at all! It is something working at a lower layer and decides how message is transported between server and client.
In other words, the object will first be serialized (by DataContractSerializer, for example) and then encoded (by BinaryEncoder). So your object will always be in XML format as long as DataContractSerializer is involved.
If you want a more compact data and better performance, read this blog:
https://blogs.msdn.microsoft.com/dmetzgar/2011/03/29/protocol-buffers-and-wcf/
I need to retrieve binary (non-XML) documents as Messages in a custom WCF LOB Adapter (for consumption by BizTalk). The messages need to be represented as instances of System.ServiceModel.Channel.Message.
I can't find how to create an instance of this class when the content is binary (by "binary" I mean any arbitrary byte array or Stream, and not only binary representations of XML documents).
Is this possible? Or would wraping the binary contents in an XML enveloppe be the only way to do this in WCF?
Fundamentally, WCF messages are XML, since the S.S.C.Message class uses the Xml InfoSet as the base message representation.
So yes, in some way you need to "wrap" your binary content into an XML envelope (which doesn't need to be a SOAP envelope, mind you, depending on how your binding is configured).
That said, note that this doesn't preclude streaming to deal with large message payloads without buffering the entire message in memory; WCF still allows you to do this, though sometimes it's not greatly obvious how it works.
Since you're working with a custom channel, you've got one of two choices, I think:
Have your own channel add the XML wrapper around your binary content before passing it upwards or
Create a custom MessageEncoder that adds it in for you automatically.
In either case, if you're dealing with large messages, you'll want to make sure you use the MessageEncoder overloads that handle Streams instead of buffers, as they are the ones that give you the option of doing coordinated streaming with the service implementation.
WCF offers some ways to send binary attachments and stream data in various ways. We have an application at work that does this, but I haven't had a chance to dig through the code, so I can't offer too much help. Here are a few links that might get you started (Nicholas Allen's Indigo Blog is a great place for WCF info):
http://blogs.msdn.com/drnick/archive/2006/03/31/565558.aspx
http://weblogs.asp.net/cibrax/archive/2007/08/29/sending-attachments-with-wcf.aspx
I'm building a WCF service based on a W3C specification which defines a RESTful web service endpoint that accepts "application/x-www-form-urlencoded" post data. WCF doesn't support this type of message encoding by default and I have found a number of different examples of creating a contract that looks like this:
XElement Query_Post(Stream postData);
And then within the implementation decoding the postData stream using the HttpUtility.ParseQueryString method.
Does anyone know of a more strongly typed way of supporting "application/x-www-form-urlencoded" in WCF?
I would like my operation contract to be:
XElement Query_Post(string query, string [] params);
The best way is to use Stream like Raw HTTP POST with WCF or what you are saying.
The reason is because WCF abstracts all the communication-level physical layout stuff out from the service code. Ideally, you would want to make a service that could turn into SOAP or REST just by flipping the switch.
To support it natively, you probably have to extend WebHttpBinding or make your own binding and implement custom encoder. This is symmetric to the output like the linked post says. You have to twist its arms to get WCF to output non-XML/JSON stuff.
The WCF REST Contrib library enables this functionality:
https://github.com/mikeobrien/WcfRestContrib
It includes a POX formatter and form url encoded formatter and allows you to easily create your own. Formatters are mapped to mime types and automatically selected to serialize/deserialize the entity body based on the content type and accept headers.