Stream

The Stream sample demonstrates the use of streaming transfer mode communication. The service exposes several operations that send and receive streams. This sample is self-hosted. Both the client and service are console programs.

Note

The setup procedure and build instructions for this sample are located at the end of this topic.

Windows Communication Foundation (WCF) can communicate in two transfer modes—buffered or streaming. In the default buffered transfer mode, a message must be completely delivered before a receiver can read it. In the streaming transfer mode, the receiver can begin to process the message before it is completely delivered. The streaming mode is useful when the information that is passed is lengthy and can be processed serially. Streaming mode is also useful when the message is too large to be entirely buffered.

Streaming and Service Contracts

Streaming is something to be considered when designing a service contract. If an operation receives or returns large amounts of data, you should consider streaming this data to avoid high memory utilization due to buffering of input or output messages. To stream data, the parameter that holds that data must be the only parameter in the message. For example, if the input message is the one to be streamed, the operation must have exactly one input parameter. Similarly, if the output message is to be streamed, the operation must have either exactly one output parameter or a return value. In either case, the parameter or return value type must be either Stream, Message, or IXmlSerializable. The following is the service contract used in this streaming sample.

[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface IStreamingSample
{
    [OperationContract]
    Stream GetStream(string data);
    [OperationContract]
    bool UploadStream(Stream stream);
    [OperationContract]
    Stream EchoStream(Stream stream);
    [OperationContract]
    Stream GetReversedStream();

}

The GetStream operation receives some input data as a string, which is buffered, and returns a Stream, which is streamed. Conversely, UploadStream takes in a Stream (streamed) and returns a bool (buffered). EchoStream takes and returns Stream and is an example of an operation whose input and output messages are both streamed. Finally, GetReversedStream takes no inputs and returns a Stream (streamed).

Enabling Streamed Transfers

Defining operation contracts as previously described provides streaming at the programming model level. If you stop there, the transport still buffers the entire message content. To enable transport streaming, select a transfer mode on the binding element of the transport. The binding element has a TransferMode property that can be set to Buffered, Streamed, StreamedRequest, or StreamedResponse. Setting the transfer mode to Streamed enables streaming communication in both directions. Setting the transfer mode to StreamedRequest or StreamedResponse enables streaming communication in only the request or response, respectively.

The basicHttpBinding exposes the TransferMode property on the binding as does NetTcpBinding and NetNamedPipeBinding. For other transports, you must create a custom binding to set the transfer mode.

The following configuration code from the sample shows setting the TransferMode property to streaming on the basicHttpBinding and a custom HTTP binding:

<!-- An example basicHttpBinding using streaming. -->
<basicHttpBinding>
  <binding name="HttpStreaming" maxReceivedMessageSize="67108864"
           transferMode="Streamed"/>
</basicHttpBinding>
<!-- An example customBinding using HTTP and streaming.-->
<customBinding>
  <binding name="Soap12">
    <textMessageEncoding messageVersion="Soap12WSAddressing10" />
    <httpTransport transferMode="Streamed"
                   maxReceivedMessageSize="67108864"/>
  </binding>
</customBinding>

In addition to setting the transferMode to Streamed, the previous configuration code sets the maxReceivedMessageSize to 64MB. As a defense mechanism, maxReceivedMessageSize places a cap on the maximum allowable size of messages on receive. The default maxReceivedMessageSize is 64 KB, which is usually too low for streaming scenarios.

Processing Data As It Is Streamed

The operations GetStream, UploadStream and EchoStream all deal with sending data directly from a file or saving received data directly to a file. However in some cases, there is a requirement to send or receive large amounts of data and perform some processing on chunks of the data as it is being sent or received. One way to address such scenarios is to write a custom stream (a class that derives from Stream) that processes data as it is read or written. The GetReversedStream operation and ReverseStream class are an example of this.

GetReversedStream creates and returns a new instance of ReverseStream. The actual processing happens as the system reads from that ReverseStream object. The ReverseStream.Read implementation reads a chunk of bytes from the underlying file, reverses them, then returns the reversed bytes. This does not reverse the entire file content; it reverses one chunk of bytes at a time. This is an example to show how you can perform stream processing as the content is being read or written from and to the stream.

class ReverseStream : Stream
{

    FileStream inStream;
    internal ReverseStream(string filePath)
    {
        //Opens the file and places a StreamReader around it.
        inStream = File.OpenRead(filePath);
    }

    // Other methods removed for brevity.

    public override int Read(byte[] buffer, int offset, int count)
    {
        int countRead=inStream.Read(buffer, offset,count);
        ReverseBuffer(buffer, offset, countRead);
        return countRead;
    }

    public override void Close()
    {
        inStream.Close();
        base.Close();
    }
    protected override void Dispose(bool disposing)
    {
        inStream.Dispose();
        base.Dispose(disposing);
    }
    void ReverseBuffer(byte[] buffer, int offset, int count)
    {
        int i, j;
        for (i = offset, j = offset + count - 1; i < j; i++, j--)
        {
            byte currenti = buffer[i];
            buffer[i] = buffer[j];
            buffer[j] = currenti;
        }

    }
}

Running the Sample

To run the sample, first build both the service and the client by following the directions at the end of this document. Then start the service and the client in two different console windows. When the client starts, it waits for you to press ENTER when the service is ready. The client then calls the methods GetStream(), UploadStream() and GetReversedStream() first over HTTP and then over TCP. Here is an example output from the service followed by example output from the client:

Service Output:

The streaming service is ready.
Press <ENTER> to terminate service.

Saving to file D:\...\uploadedfile
......................
File D:\...\uploadedfile saved
Saving to file D:\...\uploadedfile
...............
File D:\...\uploadedfile saved

Client Output:

Press <ENTER> when service is ready
------ Using HTTP ------
Calling GetStream()
Saving to file D:\...\clientfile
......................
Wrote 33405 bytes to stream

File D:\...\clientfile saved
Calling UploadStream()
Calling GetReversedStream()
Saving to file D:\...\clientfile
......................
Wrote 33405 bytes to stream

File D:\...\clientfile saved
------ Using Custom HTTP ------
Calling GetStream()
Saving to file D:\...\clientfile
...............
Wrote 33405 bytes to stream

File D:\...\clientfile saved
Calling UploadStream()
Calling GetReversedStream()
Saving to file D:\...\clientfile
...............
Wrote 33405 bytes to stream

File D:\...\clientfile saved

Press <ENTER> to terminate client.

To set up, build, and run the sample

  1. Ensure that you have performed the One-Time Setup Procedure for the Windows Communication Foundation Samples.

  2. To build the C# or Visual Basic .NET edition of the solution, follow the instructions in Building the Windows Communication Foundation Samples.

  3. To run the sample in a single- or cross-machine configuration, follow the instructions in Running the Windows Communication Foundation Samples.

Note

If you use Svcutil.exe to regenerate the configuration for this sample, be sure to modify the endpoint name in the client configuration to match the client code.