IDispatchMessageFormatter – How to customize reply Messages on the server side?

Posted on March 3, 2011 by

0


The IDispatchMessageFormatter extensibility hook is very similar to the client’s IClientMessageFormatter which was described in the previous post iclientmessageformatter.

On the server side,  WCF converts requests into Message objects which are later on converted to a strongly typed operation parameters.

image

The IDispatchMessageFormatter allows us to interfere in the later conversion (Message to operation parameters). It contains two methods (similar to its corresponding interface IClientMessageFormatter) which are responsible for deserializing requests and serializing responses:

public interface IDispatchMessageFormatter
{
    void DeserializeRequest(
        Message message,
        object[] parameters);

    Message SerializeReply(
        MessageVersion messageVersion,
        object[] parameters,
        object result);
}

The DeserializeRequest method is invoked on incoming requests. It accepts a Message object and expected to provide an array of parameters.

The SerializeReply is invoked on outgoing replies. It accepts an array of parameter and is expected to construct a Message object (Usually we won’t create Message objects directly, and use the Message.CreateMessage instead).

Attaching this extension to the WCF pipeline is done by creating IOperationBehavior implementation as described in the following post http://wcfpro.wordpress.com/2010/12/22/ioperationbehavior/.

IDispatchMessageFormatter Sample

This sample adds to the server side the behavior of desterilizing Message objects using XmlSerializer.

Our contract is the same as the one from the previous post  (http://wcfpro.wordpress.com/2011/02/04/IClientMessageFormatter). It contains one method with one parameter,and is marked with ‘IsOneWay=true’, which means no reply is expected (just for simplicity):

    [ServiceContract]
    public interface IPing
    {
        [OperationContract(IsOneWay = true, Action = "*")]
        void Foo(MyRequest request);
    }

This behavior will also be added through MyFormatterBehavior:

    /// <summary>
    /// Adds custom formatter to the server which uses the xmlserializer to serialize the body
    /// </summary>
    public class MyFormatterBehavior : IOperationBehavior
    {
        public void AddBindingParameters(
            OperationDescription operationDescription,
            BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(
            OperationDescription operationDescription,
            ClientOperation clientOperation)
        {
        }

        public void ApplyDispatchBehavior(
            OperationDescription operationDescription,
            DispatchOperation dispatchOperation)
        {
            dispatchOperation.Formatter = new MyXmlSerializerServerFormatter();
        }

        public void Validate(OperationDescription operationDescription)
        {
        }
    }

    /// <summary>
    /// Formatter which deserialize request messages and serialize response messages in the server side
    /// </summary>
    internal class MyXmlSerializerServerFormatter : IDispatchMessageFormatter
    {
        #region fields

        private CustomXmlObjectSerializer m_bodySerializer;

        #endregion

        #region constructor

        public MyXmlSerializerServerFormatter()
        {
            m_bodySerializer = new CustomXmlObjectSerializer(typeof(MyRequest));
        }

        #endregion

        #region IDispatchMessageFormatter Members

        /// <summary>
        /// Deserializes a message into an array of parameters
        /// </summary>
        /// <param name="message">The incoming message.</param>
        /// <param name="parameters">The objects that are passed to the operation as parameters</param>
        public void DeserializeRequest(
            Message message,
            object[] parameters)
        {
            var bodyReader = message.GetReaderAtBodyContents();

            using (bodyReader)
            {
                parameters[0] = m_bodySerializer.ReadObject(bodyReader);
                Debug.Assert(parameters[0] != null);
            }
        }

        /// <summary>
        /// Serializes a reply message from a specified message version, array of parameters, and a return value
        /// </summary>
        /// <param name="messageVersion">The SOAP message version</param>
        /// <param name="parameters">The out parameters</param>
        /// <param name="result">The return value</param>
        /// <returns>The serialized reply message</returns>
        public Message SerializeReply(
            MessageVersion messageVersion,
            object[] parameters,
            object result)
        {
            // In this sample we defined our operations as OneWay, therefore, this method
            // will not get invoked.
            throw new NotSupportedException(
                "This formatter is meant to be used on OneWay operations...");
        }

        #endregion
    }

    

About these ads
Posted in: WCF Extensions