Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Stream Operation in WCF

3.82/5 (15 votes)
4 Jun 2009CPOL3 min read 87.1K  
WCF provides support for Stream object. It typically recommends the developer to handle the message whose size is too large as Stream object for the sake of high performance. However, there are some constraints on Stream operation that need to be noted.

Introduction

WCF provides support for Stream object. It typically recommends the developer to handle the message whose size is too large as Stream object for the sake of high performance.

However, there are some constraints on Stream operation that need to be noted. They are listed below.

1. The Constraint of Binding

The valid bindings include BasicHttpBinding, NetTcpBinding and NetNamePipeBinding for Stream operation. In addition, we can't use Reliable Messaging while handling the Stream object. If you are considering security of the message, this method is not a good choice.

2. The Constraint of Stream Object

The object that you want to transport as a parameter with WCF Operation must be serializable. Unfortunately, FileStream class can't be serialized. We have to use Stream, MemoryStream. The Stream class is the main option for handling a stream object.

It is very interesting to transform between FileStream and Stream class. For example, the following implementation of the operation in a service:

C#
public Stream TransferDocument(Document document)
{
     FileStream stream = new FileStream
                             (document.LocalPath, FileMode.Open, FileAccess.Read);
     return stream;
}

Note, the type of return value of TransferDocument() method is Stream. But the true type should be FileStream. As FileStream is the subclass of Stream, it is no problem according to polymorphism of OO. When the client wants to invoke TransferDocument() method, we can't assign the return value to FileStream object, in fact:

C#
FileStream stream = m_service.TransferDocument(doc);

The value of stream object is null now. So we must do like this:

C#
Stream stream = m_service.TransferDocument(doc);

It is strange that WCF can't serialize the Length property of Stream object. On the client side, we cannot use the Length property. If you want to do so, it will throw a NotSupportedException.

3. The Constraint of TransferMode

The default value of TransferMode is set to Buffered. If you want to use Stream operation, you must change the default setting of TransferMode. We can set it to Streamed, StreamedRequest or StreamedResponse according to the different cases.

4. The Constraint of MaxReceiveMessage

The default value of MaxReceiveMessage property is 64 KB. If the size of transported stream object exceeds the setting value of MaxReceiveMessage, it will throw a CommunicationException when the client invokes the operation of service to handle this stream object. So we should change the value depending on the specific situation. The value ranges from 1 to 9223372036854775807 (i.e. Int32.MaxValue). If the setting value is outside the range, the program cannot be compiled successfully. Set its value in programmatic:

C#
binding.MaxReceivedMessageSize = 120000;

And set it in administrative:

XML
<binding …… maxReceivedMessageSize="120000"/>

5. The Constraint of Operation Parameters

WCF applies the strict constraint on the parameters of operation including stream objects. There can be only one stream object as the parameter(in, out, ref parameter or return value) in the method signature. So these definitions of the method are all invalid as below:

C#
void Transfer(Stream s1, Stream s2);
void Transfer(Stream s1, out Stream s2);
void Transfer(Stream s1, ref Stream s2);
Stream Transfer(Stream stream);

If you define the method like above, the run-time error will occur.

6. The Constraint of Instance Activation

Because we can only use the BasicHttpBinding, NetTcpBinding or NetNamedPipeBinding in the stream operation, it will impact on the mode of instance activation, in particular Session mode. First, BasicHttpBinding doesn't support Session mode. Secondly, although the other bindings (NetTcpBinding or NetNamedPipeBinding) support Session mode, we can't set the value of ReliableSession to true because the stream operation doesn't support reliable messaging. So if you set the value of SessionMode to SessionMode.Required for the service, it will throw an exception.

In fact, the stream operation (i.e. the value of TransferMode is not Buffered) itself doesn't support Session mode. Even if we set the value of SessionMode to Allowed, and set the value of InstanceContextMode to PerSession while using NetTcpBinding, the behavior of service is still PerCall mode. And the value of SessionId (get it through OperationContext.Current.SessionId) should be null at this time.

Finally, I recommend you increase the value of SendTimeOut property because calling a large stream object will last for a very long time. For example, set its value to 10 minutes in programmatic:

C#
binding.SendTimeout = TimeSpan.FromMinutes(10);

Or set it in administrative:

XML
<binding …… sendTimeout="00:10:00"/>

Note, the configuration of Binding on the service and client side must be kept consistent.

History

  • 4th June, 2009: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)