Sunday, January 24, 2010

The Most Important WCF Class

Even fairly experienced WCF programmers may never have had to deal with this little gem, however, it is the single most important class in the WCF framework. Why is that? Because the message class provides the fundamental abstraction which represents all data sent or received from any WCF endpoint.

Key Parts

There are four key parts to the message class:

  • Version - The version property contains information about the SOAP and Addressing versions used by the message. WCF fully supports use of non-SOAP messages for which this property is will be None to indicate the lack of any special formatting.
  • Properties - Message properties contain processing information about the message which will not be written to the underlying transport stream as part of the message content. One example of what message properties can be used for is controlling things like HTTP verbs and status codes.
  • Headers - A collection of message headers. A few common headers such as To and Action can be accessed via shortcut properties in the headers collection.
  • Body - You can’t actually access the message body because the Message class abstraction is mean to be used as if the content of the Message was a stream.

It’s Abstract

This will come as a surprise to many people, because the WCF framework does a very good job of hiding this fact, but the Message class itself is an abstract class. So put away any preconceived notions you might have had about how WCF at it’s core can only be used for web services and XML based communication. The fact is that you could create a message class backed directly by a raw binary array if you didn’t want any kind of performance hit for loading the data… as a matter of fact you probably wouldn’t want to even waste your time doing that, because WCF does exactly that when you are using many of the default settings! Actually… it does it even more efficiently than you would probably do it on your own by taking advantage of buffer managers to reduce the number of allocations that need to be made as messages are being created and disposed. So, despite the fact that the underlying abstraction is streaming, WCF actually buffers messages into a byte array by default to allow for higher performance.

It’s Streaming

Once you read the message, it cannot be read again. For this reason, all custom message classes must also provide a MessageBuffer implementation. I won’t talk much about the MessageBuffer class at this point, other than to say that it is also abstract and it is responsible for creating additional “copies” of the message. I say “copies” because the default implementations that are most commonly used by the standard bindings won’t actually “copy” anything. They just return another instance backed by the same internal byte array. This makes for ultra efficient message copying, but is only possible because of another trait of the message… The reason Message implementers must provide their own MessageBuffer implementations is so that the copy operation itself can be as optimized as possible.

It’s Immutable

Well… sort of. The properties and headers of the message can be modified at will, making things like routing logic and header processing much easier to deal with, but the message body itself cannot be modified using the Message or MessageBuffer classes. For this reason, many hooks in the WCF internals where a Message might need to by modified will pass the message as a ref parameter so it can be swapped for another message.

It’s Not XML

The last basic thing you need to know about the Message class which I already touched on, but should make clear again… the Message class does have to not represent XML data! This may seem like a strange statement if you’ve looked casually at the methods provided by the message class. However, this is only due to the unfortunate naming that the WCF team chose for XmlDictionaryReader and XmlDictionaryWriter, which have a lot of methods for reading and writing XML data, but fully support reading and writing raw binary content as well.