WCF provides the support for Stream object. It typically recommends the
developer to handle the message which size is too large as Stream object for the
sake of high performance.
However, there are some constraints on Stream operation to note:
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 about the
security of message, this way is not a good choice.
2. The constraint of Stream object
The object, 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 of transform between FileStream and Stream class. For
example, the following implementation of the operation in a service:
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 ture type should be FileStream. Due to FileStream is the subclass of Stream,
so it is no problem according to polymorphism of OO. When the client want to
invoke TransferDocument() method, we can’t assign the return value to FileStream
object in fact:
FileStream stream = m_service.TransferDocument(doc);
The value of stream object is null now. So we must do like this:
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 can not use the Length property. If you want to do, it
will throw a NotSupportedException.
3. The constraint of TransferMode
The default value of TransferMode is setted 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 64kb. If the size of
transported stream object exceeds the setting value of MaxReceiveMessage, It
will throw a CommunicationException during 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 can not
be compiled successfully. Set its value in programmatic:
binding.MaxReceivedMessageSize = 120000;
And set it in administrative:
<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:
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, it will occur the run-time error.
6. The constraint of Instance Activation
Because we can only use the BasicHttpBinding, NetTcpBinding or
NetNamedPipeBinding in the stream operaiton, 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 the 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 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 by OperationContext.Current.SessionId) should be null
at this time.
Finally, I recommend you increase the value of SendTimeOut property because
the calling a large stream object will last too long time. For example, set its
value to 10 minutes in programmatic:
binding.SendTimeout = TimeSpan.FromMinutes(10);
Or set it in administrative:
<binding …… sendTimeout=“00:10:00“/>
Note, the configuration of Binding on the service and client side must keep
in consistent.