By writing of custom Message Inspectors (classes derived
from IClientMessageInspector and IDispatchMessageInspector ) you will for sure need to
manipulate the message entering your callbacks. For example, imagine there is a
custom dispatcher and you need to perform some change on the message in one of
two methods shown bellow.
public interface
IDispatchMessageInspector
{
object AfterReceiveRequest(ref Message
request,
IClientChannel channel,
InstanceContext instanceContext);
void BeforeSendReply(ref Message
reply, object correlationState);
}
|
The Message object is unfortunately not very easy to
manipulate. To illustrate what operations and how can be performed on one
message instance please take a look here.
To make it simple, imagine the message should not be changed
at all. Instead in this post the message will be just cloned and sent back to
the dispatcher. This may sound trivial, but it is not. The idea behind
following example is to show what information one message can hide from you,
but which has to be copied during clone operation.
Easiest way to make a copy of the message is shown in the next
example:
public Message
SimpleClone(Message message)
{
MemoryStream memStream = new MemoryStream();
XmlWriter xmlWriter = XmlWriter.Create(memStream);
message.WriteMessage(xmlWriter);
xmlWriter.Close();
memStream.Position = 0;
XmlDocument messageDoc = new XmlDocument();
messageDoc.Load(memStream);
return Message.CreateMessage(new XmlNodeReader(messageDoc.DocumentElement),
int.MaxValue,
message.Version);
}
|
The crucial thing in this example is that when message is
once read, there is no possibility to do anything else with the message.
Because of that the whole content of the message is read in the memory stream
and then loaded in the xml document. After that the new message with the same
content is created. By using of BasicHttpBinding this will work fine. Now, one could ask, “why is this operation dependent on binding?” The copied
message in the previous example is not the same one as the message which has entered
the method. This sounds strange, but it is true. It is important to know that
the original message could be of some other type than just Message. For example
by using of BasicHttpBinding
the message is of derived type BufferedMessage. But by using of WSHttpBinding the message is of
internal type SecurityVerifiedMessage.
Note that all information contained in the message are
reflected in the object (SecurityVerifiedMessage)
which encapsulate the massage. However, not all information contained in the
object are reflected in the message itself. This is a
reason, why the message copy cannot be made as in previous example. The BasicHttpBinding can deal with the message created this
way, but this is just a coincidence.
By creating of the copy of the message the message header
and all message properties have to be copied too, as shown in the next example:
public Message
SimpleClone(Message message)
{
document = new.XmlDocument();
document.Load(message.GetReaderAtBodyContents());
XmlNodeReader xmlReader = new XmlNodeReader(document.FirstChild);
Message newMsg = Message.CreateMessage(msg.Version, null,
xmlReader);
newMsg.Headers.CopyHeadersFrom(msg);
foreach (string
propertyKey in msg.Properties.Keys)
newMsg.Properties.Add(propertyKey, msg.Properties[propertyKey]);
// msg.Close();
return newMsg;
}
|
First we load the body of the message in the xml document.
Then we create the message with the same version and with the same body. Not that
this point would be the right place to manipulate the body. After that we copy
all headers by calling of CopyHeadersFrom and finally, all message properties
have to be copied too. Note that the commented line would be usually the right
place to close the original message. However, this must not be done, because
the closing of the message would dispose some properties, which are necessary for
processing of the message.
Hope this example make clear some hidden message specific
details.
Posted
Jan 25 2007, 01:17 PM
by
Damir Dobric