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:
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:
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 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:
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, 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:
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 be kept consistent.
History
- 4th June, 2009: Initial post