ProblemYou are implementing a service that implements streamed requests. The service is stateless. You want to pass additional information to streaming operations together with the data stream.
Operations that implement streamed requests can only take a single parameter containing the data to be streamed. If a service requires additional information, such as a name or identifier to associate with the streamed data, then this information cannot be passed as a parameter to the same operation. One common technique to circumvent this issue is to implement an additional operation that the client can use to specify the name or identifier, but this strategy requires that the service is able to retain state between operations. Not all bindings support sessions. For example, if you are using the BasicHttpBinding then sessions are not available. An alternative technique is to retain state in static variables in the service, but this solution is not suitable for scalable services that need to handle requests from multiple concurrent clients.
- You want to provide an operation that implements streamed requests.
- You need to provide additional information about the stream as well as the streamed data.
- The binding used by the service does not support sessions.
- You do not want to use static data in the service to retain state information.
Example ScenarioA WCF service uses transport security over the BasicHttBinding binding. For performance reasons, one operation named UploadData exposed by the service expects a streamed request. The operation also requires the name of the video so that the service can save the stream in a file with an appropriate name. The BasicHttpBinding binding does not support sessions.
SolutionImplement a custom message contract for the streaming operation. Provide the name of the video as metadata in the message header. Specify the streamed data as the message body. When WCF streams data, the message header is transmitted at the start of the data, so the operation can access the message metadata and retrieve the message name before it receives the streamed data.
ImplementationThe sample implementation shown in this section comprises three elements:
- The message contract. The TaggedStream class specifies the name to associate with the streamed data by using the MessageHeader attribute. The streamed data forms the body of the message and is tagged with the MessageBodyMember attribute.
- The streaming service. This service implements the UploadData streaming operation. The operation retrieves the data from the stream and saves it to a file based on the metadata retrieved from the message header.
- The client application. This application creates an instance of the TaggedStream class and populates it with a stream and the name to associate with the stream. The client application uses this object as the parameter to the UploadData operation.
Message ContractThe TaggedStream class implements the message contract. The Name field is transmitted as part of the message header, and the StreamData field constitutes the body of the message.
Streaming ServiceThe streaming service in this example implements the IStreamService interface shown below. The UploadData operation enables a client application to send data to the service as a streamed request. The message type specified as the parameter to the UploadData operation is TaggedStream.
The following code shows an example implementation of the streaming service. In this example, the streamed data is assumed to be a bitmap which is saved to a “.bmp” file. Replace this code with your own business logic, and handle exceptions as necessary.