In the post about the raw mode for the WCF Web programming model, I showed how to use a content-type mapper to tell WCF to treat all incoming requests as “raw” requests, so we could map any content, including those supported by the formatter, to a Stream parameter. This is done at the encoder level, so all operations in the contract basically share the same raw mode. But if you want to mix / match operations with “normal” parameters with operations with a stream parameter, then it becomes a problem, like in the contract below. If we don’t use a content-type mapper, requests with JSON or XML content cannot reach the Upload operation; if we do use one (to map incoming requests to raw), requests of that same content-type cannot be made to the Add operation.
One possible solution for this is to split the contract in two (and have them as interfaces), have the service implement both interfaces and have two endpoints. This works, but it has the drawback of splitting the URI space between the two contracts, since two endpoints cannot share the same address.
But it’s possible to implement that behavior as well, with a formatter which a trick that will use another encoder to read the input in the format required by the “typed” operations, and we’ll be able to tag the operations for which we can opt-out of the raw format:
The NonRawAttribute class is simply an empty attribute class which implements IOperationBehavior, so I’ll skip it here. The interesting part happens at a new formatter which we’ll implement to do the conversion, and is shown below. When deserializing the request, if the operation with which the formatter is associated it is tagged with the [NonRaw] attribute, we’ll write the message back, and then read with the encoder – which does not have any content-type mapper set. That will create a message tagged with the format corresponding to the request’s Content-Type header, which is what we need for the “typed” operations. There is a big drawback of this process, though – there will be a performance hit (both for execution time and memory usage) for those [NonRaw] operations, since there will be an additional encoding / decoding of the message done in the formatter. For small requests this should not be significant, though.
We also need to set this formatter, and the easiest way is to create a class derived from WebHttpBehavior for that.
We can now test this code. Notice that we’re sending typed (JSON) request to the Add operation, and both typed (JSON) and untyped (text) to the stream operation.
And that’s it. The full code for this post can be found in GitHub at https://github.com/carlosfigueira/WCFSamples/tree/master/MessageFormatter/PerOperationContentTypeMapper.