Share via


Get the Message

When I talk about lowercase-m messages in the channel model, mentally you should translate these to the uppercase-M Message class.  A message is the fundamental data type for channels.  Input channels return a Message from receive operations and output channels take a Message for send operations.  In the channel stack, protocol channels will have the concept of a message on both the top and bottom, while a transport channel has a message on one side and the network on the other.

At first sight of our Message base class, don't be frightened by the huge number of methods.  Instead, concentrate on the few concepts that the message abstraction exposes.

 public abstract class Message : IDisposable
{
   protected Message();

   public abstract MessageHeaders Headers { get; }
   protected bool IsDisposed { get; }
   public virtual bool IsEmpty { get; }
   public virtual bool IsFault { get; }
   public abstract MessageProperties Properties { get; }
   public MessageState State { get; }
   public abstract MessageVersion Version { get; }

   public void Close();
   public MessageBuffer CreateBufferedCopy(int maxBufferSize);
   public static Message CreateMessage(MessageVersion version, string action);
   public static Message CreateMessage(System.Xml.XmlReader envelopeReader, int maxSizeOfHeaders);
   public static Message CreateMessage(XmlDictionaryReader envelopeReader, int maxSizeOfHeaders);
   public static Message CreateMessage(MessageVersion version, MessageFault fault, string action);
   public static Message CreateMessage(MessageVersion version, string action, BodyWriter body);
   public static Message CreateMessage(MessageVersion version, string action, object body);
   public static Message CreateMessage(MessageVersion version, string action, System.Xml.XmlReader body);
   public static Message CreateMessage(MessageVersion version, string action, XmlDictionaryReader body);
   public static Message CreateMessage(System.Xml.XmlReader envelopeReader, int maxSizeOfHeaders, MessageVersion version);
   public static Message CreateMessage(XmlDictionaryReader envelopeReader, int maxSizeOfHeaders, MessageVersion version);
   public static Message CreateMessage(MessageVersion version, FaultCode faultCode, string reason, string action);
   public static Message CreateMessage(MessageVersion version, string action, object body, XmlObjectSerializer serializer);
   public static Message CreateMessage(MessageVersion version, FaultCode faultCode, string reason, object detail, string action);
   public T GetBody<T>();
   public T GetBody<T>(XmlObjectSerializer serializer);
   public string GetBodyAttribute(string localName, string ns);
   public XmlDictionaryReader GetReaderAtBodyContents();
   protected virtual void OnBodyToString(XmlDictionaryWriter writer);
   protected virtual void OnClose();
   protected virtual MessageBuffer OnCreateBufferedCopy(int maxBufferSize);
   protected virtual string OnGetBodyAttribute(string localName, string ns);
   protected virtual XmlDictionaryReader OnGetReaderAtBodyContents();
   protected abstract void OnWriteBodyContents(XmlDictionaryWriter writer);
   protected virtual void OnWriteMessage(XmlDictionaryWriter writer);
   protected virtual void OnWriteStartBody(XmlDictionaryWriter writer);
   protected virtual void OnWriteStartEnvelope(XmlDictionaryWriter writer);
   protected virtual void OnWriteStartHeaders(XmlDictionaryWriter writer);
   public override string ToString();
   public void WriteBody(System.Xml.XmlWriter writer);
   public void WriteBody(XmlDictionaryWriter writer);
   public void WriteBodyContents(XmlDictionaryWriter writer);
   public void WriteMessage(System.Xml.XmlWriter writer);
   public void WriteMessage(XmlDictionaryWriter writer);
   public void WriteStartBody(System.Xml.XmlWriter writer);
   public void WriteStartBody(XmlDictionaryWriter writer);
   public void WriteStartEnvelope(XmlDictionaryWriter writer);
}

That's probably more methods than all the previous classes we've looked at combined!  Let's start consolidating these into concepts.

The interesting part of a SOAP message is generally the body, which is normally where your data will live.  We have a bunch of CreateMessage overloads for generating messages from existing data, GetBody and GetReaderAtBodyContents methods for cracking open a message, and CreateBufferedCopy and write methods for extruding the message to other consumers.  For extenders of the Message class, we also have a bunch of hooks for overriding behavior during the message consumer's requests.  There's some asymmetry between treating messages as a blob in memory and treating messages as a stream, but these four buckets have just covered almost all of the methods.

Then, there are the parts of the message that float outside the body.  We have a version property to describe the SOAP and addressing standards that this message conforms to.  Like channels, messages have a lifecycle for resource tracking, so we have a state property that tracks that lifecycle and a Close method for cleaning up.  Finally, we have headers and properties that provide information about the message.

There is certainly going to be some learning curve for becoming comfortable using WCF messages.  A good way to ease into it is to focus on the body at first since that is likely to have a direct connection with what your application is doing.  The three methods to think about are CreateMessage, GetBody, and Close.  Learn about the rest of the concepts when you need them.  For example, if you need to work with the message action, which is a header, go learn about that property, but don't feel like you have to understand everything about headers before building an application.

Next time: A POX on Us, Redux