Streaming with WCF - Sidebar: What is really going on with my stream?
Streaming with WCF
Sidebar - What is really going on with my stream?
This posting might not directly help you implement something, but it should give some insight as to what's going on under the hood with a stream sent to a client from a service.
Scenario
There's a WCF service with an operation which returns a Stream.
A WCF Client invokes this operation.
The Transfer Mode is Streamed.
So, here's what happens, diagram first:
To elaborate:
- The client call is received by the service. The service creates some custom stream in the operation and returns it.
- Because transfer mode is Streamed, the Encoder gets a wire stream handed to it from the transport layer.
- Using the wire stream and the stream handed from the service (which I'll call CustomStream from here on), the encoder then begins to create a message. It starts with all the Soap stuff, but when it comes to the body, it starts the streamed transfer. It calls a method which takes the two streams. This method basically gets a buffer from the wire stream and fills it up with bytes from the CustomStream. Then it calls Write on the wire stream, passing the buffer. This is what sends the bytes out on the wire. If the Read call on the CustomStream returned exactly the same value as that buffer, then we know there are more bytes to write. To make things more efficient, subsequent Read calls get a larger buffer allocated.
What if I used TransferMode.Buffered?
Instead of the Transport giving the WireStream to the encoder, the encoder will simply read the entire CustomStream, package it up in a single message, and hand that message off to the transport which will then send it on the wire. If your implementation is actually returning very small streams with many client calls, this might actually be optimal. Otherwise, TransferMode.Streamed is the better option.
Comments
Anonymous
June 19, 2011
Nice blogAnonymous
June 28, 2011
Suppose I have a service that expects a stream. How can I create the stream on the client and pass it to the service reference without having to load the entire file into the client. I"ve used your instructions above to build a pretty slick file-transfer service, but it fails when I want to transfer really big files since the client tries to load everything into the client before sending the stream to the service. Thanks, -ScottAnonymous
June 29, 2011
Scott, it should be possible to continuously stream to the server (up to MaxMessageSize, or some server-side read quota to prevent DOS attacks). What I'm trying to say is that the client shouldn't have to buffer the message before sending it to the service. First, and most obvious, is to make sure the TransportBindingElement's TransferMode is set to Streamed. But I'm assuming that's already done. What error message (and stack, if possible) are you getting on the client? I wonder if you're hitting a quota on message size, or if the stream is in fact getting buffered and it shouldn't be. Also, do you know if the server starts getting the stream and it fails while reading from the stream? This would indicate whether or not the client is truly streaming.Anonymous
July 16, 2011
James - assuming I'm making service calls to return images ranging from 1Mb to 10Mb, typically over a LAN, should I bother with streaming? Or just stick with buffering? I don't mind the extra work if it makes my app lightening fast but I don't want to create work for myself either. Thanks MarkAnonymous
July 21, 2011
Hi Mark, it sort of depends on what you want to do with the images on the client side. If you want to start processing the images before the entire image is received, then you'll require streaming. Otherwise, you can just use buffered transfer mode. As long as the memory consumption on the server isn't an issue, it should work fine. Just remember that if your service scales to multiple clients, it could end up consuming quite a bit of memory as multiple clients concurrently receive images from the server.