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.
Related
I have an understanding on how the format of the data will be when its sent on wire and before its sent over wire to the client while using WCF. Please let me know if its right and correct me if I am wrong.
Case 1 :HttpBinding is used. When returning a WCF service call to the client:
When a method returns a dot net object, it will be first serialized into netdatacontract serializer format. This serialized data will be put inside a soap envelope .This soap will be converted into binary when its sent to network wire.On the client end riverse of these steps will be done.
Case 2 :NetTcpbinding. When returning a WCF service call to the client:
When a method returns a dot net object, it will be first serialized into netdatacontract serializer format. This data will not be converted into soap format. Instead, the serialized format is directly converted into binary while putting the data on the wire. On the client side, reverse of the above is done.
If the above statements are right ,
Is this why they say netbinding uses binary encoding and is optimized for performance ?
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.
Is it a good practice to return a byte[] in a WCF service which will be invoked by many applications
below is the code
public byte[] GetDoc(string docParam)
{
byte[] doc;
doc = GenerateDoc(docParam);
}
Thanks
It's definitely possible to return byte[] and WCF allows you to do this using MTOM encoding.
If the size of the binary buffer is big you could use WCF streaming. In this case you would return Stream data type, and read from that Stream on the client side.
It's good practice to factor common code into a convenient method so that many callers could call this convenient method. This is regardless of return type. If the callers would need to manipulate the byte[], then this can become convenient and eliminate redundant code.
By the way, regarding the code that you posted, is that real code or just an example? If it's real code:
It won't compile, because it doesn't return a byte[].
If you were to call return doc; as the last line, why have GenerateDoc() inside GetDoc()? GetDoc() doesn't really provide any true benefit.
It's used when you want to transfer a binary buffer, and also perform Large Data Transfer using MTOM encoding (set on the Binding configuration). How to perform Large Data Transfer found here.
I'm trying to pull a large amount of data out of a WCF web service. The request is fairly small and the response message will be very big. Currently the web service is throwing SystemOutOfMemory exceptions due a limitation on IIS6 for the memory it can allocated (~1.4GB).
I have read in some blogs that implementing streaming will solve my problem.
Can anybody share their experiences with this topic? I'm most interested in any sample client-side & service-side code that can be shared or any recommendations/best practices. MemoryStream vs FileStream? Return type should be Stream, Message, Byte[]?
My operation looks like the following: (typically it will return a big number of elements in the response array, ~200K elements)
MediumSizeResponseClass[] GetData(SmallSizeRequestClass request)
If you want to stream back only the response, then use transferMode=streamedResponse in your binding configuration. This makes sure only the returned response will be streamed.
The return value of a streaming function must be a Stream. You can then read from that stream and do whatever you need to do with it (store it, analyse it, whatever).
So basically you'd have a service contract something like this:
[ServiceContract]
interface IYourService
{
[OperationContract]
Stream GetData(SmallSizeRequestClass request);
}
On the server, you basically just write to a stream, while on the client, you read from the stream.
Have you consulted the MSDN docs on WCF Streaming?
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