System.ServiceModel.Channels.Message

When you call a REST service, behind the scenes the network message is wrapped in an object that the rest of the WCF infrastructure can understand. This object is an instance of System.ServiceModel.Channels.Message. Although Message is modeled somewhat after a SOAP message pattern, with a header and a body, it isn’t necessarily tied to the SOAP protocol. The Message object can be used to deserialize a message into a .NET object or retrieve it as XML.

A colleague suggested that it’s better to use the channel message as a parameter in a REST post method instead of a typed message. First of all, using the channel message directly saves you from deserializing the message into a .Net object (performance win). Secondly, using a channel message means every message is accepted and prevents the caller from getting a generic http 404 “bad request” message which doesn’t give the caller any clue as to what’s exactly wrong with the message.

Although the correctness of my colleague’s argument can be debated, I took the challenge to try out the concept. Because the channel message is not a typed message, I had to change the URI template to include the source system and message type. In that way, I no longer had to retrieve those routing fields from the message. Retrieving the fields from the message, would mean I had to deserialize the message into a typed object or process the message via streaming. That was exactly what I not wanted to do.

Anyway. Here is the new message signature:
[OperationContract]
[WebInvoke(UriTemplate = “/{sourcesystem}/{messagetype}”, Method = “POST”)]
void PostMessage(string sourcesystem,string messagetype, Message incomingmsg)

When I changed the service and deployed the service to IIS I found out this approach doesn’t work. I received the following error: Operation ‘PostUntypedMessage’ in contract ‘IMessageService’ uses UriTemplate parameters, but also uses a Message parameter. Message and UriTemplate parameters are incompatible. The error is self explaining. If you want to prevent from using a typed message, it’s better to use a stream as an input parameter.

[OperationContract]
[WebInvoke(UriTemplate = “{sourceSystemCode}/{messageType}”, Method = “POST”, BodyStyle=WebMessageBodyStyle.Bare)]
void PostUntypedMessage(string sourceSystemCode, string messageType, Stream untypedMessage);

Note: If you want to test this method via SoapUI you will have to add a header Content-Type text/plain. Also note that when you browse to the service from IIS, you will receive an error about an invalid WSDL extension. Don’t know exactly why this occurs, but this will have to do with the Stream input parameter.

Leave a comment