The WCF framework exposes the so-called extension points through which it is possible to implement additional functionalities in the WCF pipeline. One such extension point is MessageInspector object that can be used to change messages after they have been received at the service endpoint or before they are sent from it. BizTalk offers registration of WCF extension points in WCF-Custom adapter.

WCF Message Inspectors

IMessageInspector consists of two interfaces:

  • IClientMessageInspector interface exposes methods for modifying a message before sending a message or receiving a response from the client side
  • IDispatchMessageInspector interface exposes methods for modifying a message after receiving it on the server side or before sending a it as a response

The following code snippet shows MessageInspector interfaces.

public interface IClientMessageInspector
{
    object BeforeSendRequest(ref Message request, IClientChannel channel);
    void AfterReceiveReply(ref Message reply, object correlationState);
}

public interface IDispatchMessageInspector
{
    object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext);
    void BeforeSendReply(ref Message reply, object correlationState);
}

It is important to note that the message is transmitted to the IMessageInspector interfaces as a reference to the object of type Message, which ensures that changes to the message object are propagated to the caller. The body of message can be read only once, so if implementation details require multiple writing or reading of messages, it is neccessary to call the CreateBufferedCopy method that saves the entire message in the memory buffer which can then be manipulated as needed. The return value of the BeforeSendRequest and AfterReceiveReply methods can be any arbitrary object and it will later be used as corellation parameter in BeforeSendReply and AfterReceiveReply methods. If no correlation is required, it is sufficient to return null value.

Fetching BizTalk message context properties in WCF inspector

BizTalk context properties have name, namespace and value. it is possible to fetch these properties in WCF MessageInspector from Properties collection on Message object. Each message property in this collection is saved as key-value pair, where key is formed as namespace#name.

The following code snippet shows ReceivedFileName property retrieval from the context of the message.

public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
    var propNS = "http://schemas.microsoft.com/BizTalk/2003/file-properties";
    var propName = "ReceivedFileName";
    string key = propNS + "#" + propName;

    object propValue = null;
    if (request.Properties.TryGetValue(key, out propValue)) 
    {
        // property is stored in propValue variable
        // do something with fetched value...
    }
}

Copying properties from WCF message to the context of BizTalk message

Properties that are written to the context of BizTalk messages are key-value pairs, namely the collection of KeyValuePair<XmlQualifiedName, object> objects whose key is the full name of the property, formed as namespace:name, and the value is exactly the value of the property to be written. Properties are written in the context of a BizTalk message by adding this collection of the KeyValuePair objects in the Properties collection of Message object with key http://schemas.microsoft.com/BizTalk/2003/file-properties. Similarly, promoting properties in the context of the BizTalk message is done by adding the properties in the same format, in the same Properties collection, but with the key http://schemas.microsoft.com/BizTalk/2006/01/Adapters/WCF-properties/Promote.

The following code snippet shows how custom WCF property can be written and promoted to context of BizTalk message as ReceivedFileName property.

public void AfterReceiveReply(ref Message reply, object correlationState) 
{
    // List and namespace for writing properties
    var writePropertiesList = new List<KeyValuePair<XmlQualifiedName, object>>();
    var writePropertiesNS = "http://schemas.microsoft.com/BizTalk/2006/01/Adapters/WCF-properties/WriteToContext";

    // List and namespace for promoting properties
    var promotePropertiesList = new List<KeyValuePair<XmlQualifiedName, object>>();
    var promotePropertiesNS = "http://schemas.microsoft.com/BizTalk/2006/01/Adapters/WCF-properties/Promote";

    // Property to write and promote
    var propNS = "http://schemas.microsoft.com/BizTalk/2003/file-properties";
    var propName = "RecivedFileName";
    var propValue = "YourCustomFileName.xml";
    var property = new KeyValuePair<XmlQualifiedName, object>(new XmlQualifiedName(propName, propNS), propValue);

    // write
    writePropertiesList.Add(property);            

    if (reply.Properties.ContainsKey(writePropertiesNS))
        reply.Properties[writePropertiesNS] = writePropertiesList;
    else
        reply.Properties.Add(writePropertiesNS, writePropertiesList);

    // promote
    promotePropertiesList.Add(property);     

    if (reply.Properties.ContainsKey(promotePropertiesNS))
        reply.Properties[promotePropertiesNS] = promotePropertiesList;
    else
        reply.Properties.Add(promotePropertiesNS, promotePropertiesList);
}