WCF and Streaming data made easy

3.May.08 – 8:47

Wcf is great when it comes to message exchange. But Wcf even contains functionality when you want to stream data.

This is especially useful if you want to transmit a huge amount of data (think about the maxBufferSize option in Wcf configuration) or you want your clients to start processing data before the Wcf operation call has finished.

Using Wcf for streaming data is incredibly easy. Let’s look at a small example. We define our ServiceContract in the same way we are used to ist except the fact that we can just return a System.IO.Stream (or inherited) object to our clients: 

[ServiceContract]
    public interface IStreamService
    {
        [OperationContract]
        Stream GetData(string fileName);
    }

We now want to define a service that just takes a filename as an argument and returns the data the file contains in a stream. Therefore our implementation of IStreamService is quite easy too:

  public class StreamService : IStreamService
    {
        public Stream GetData(string filename)
        {
            FileStream fs = new FileStream(filename, FileMode.Open)
            return fs;
        }
    }

That’s everything we have to do on the service side (exception configuration). When you want to use streaming, be sure to use one of the following bindings:

  • BasicHttpBinding
  • NetTcpBinding
  • NetNamedPipeBinding

These bindings expose a Property called “TransferMode” where you can specify how you want to transmit your data. This could be either “Buffered” (default) or “Streamed” (or even StreamedResponse/StreamedRequest if you want to stream just in one direction).

Next just add a service reference to your client (within visual studio).You way also want to set the maxReceivedMessageSize property of your binding to a value high enough to contain your whole stream data, as everything transmitted via your stream is regarded as one huge message. But you can leave maxBufferSize to its default (64k bytes) as this indicates only the amout that is buffered before it gets processed.

Then we can just use the stream as we did years ago :

StreamDemo.StreamServiceClient client = new WcfStreamDemoClient.StreamDemo.StreamServiceClient();
Stream str = client.GetData(@"c:\path\to\myfile.dat");
FileStream fs = new FileStream(@"c:\wcf\transmitted\copy.dat", FileMode.Create);

int b,i=0;
do
{
      b = str.ReadByte(); //read next byte from stream
      fs.WriteByte((byte)b); //write byte to local file
      i++;
} while (b != -1);
Console.Write("\rRead {0} bytes.", i);
str.Close();
fs.Close();

That’s it!
I can imagine a lot of distributed applications where this could be really useful. Maybe this micro tutorial can be useful too ;)

  1. 4 Responses to “WCF and Streaming data made easy”

  2. Hi Joachim.
    Do you know how to return a custom stream with custom Read method. Return a basic filestream is always works but i receive stream with 0 byte stuff at Client when return a custom stream. Secondly, i recognized that server always prefetch stream before any Read called from Client, is it right?

    By Duy Doan on May 4, 2008

  3. Hi Duy,

    maybe you have to trim down your custom stream to a plain System.IO.Stream object.
    I tried Stream, FileStream and BufferedStream with success. But i was not able to get GZipStream, DeflateStream or MemoryStream working out of the box. There may be some way but i haven’t figured out yet ;)
    I guess your observation is right that the stream is prefetched as it is logically still one message.(that’s why you need to set maxReceivedMessageSize greater than the size your stream length will be)
    let me know if you found a solution to transmit more complex streams.
    regards
    j.

    By jkersch on May 4, 2008

  4. I know this thread is old, but, since I encountered the problem, and found no solutions elsewhere, I’ll post my solution.

    Usually, when you return a MemoryStream object, you have filled the object with data. This leaves the object’s Position property at a non-zero value. WCF doesn’t reset the Position property before it begins reading the data it will return to a caller. After loading the MemoryStream object, use the Seek method or Position property to move to the beginning of the stream.

    By Somebody on Oct 14, 2008

  5. thank’s for this, now i’ve learned something too ;)

    By jkersch on Oct 14, 2008

Post a Comment

Comment spam protected by SpamBam