WCF roundtripping and message relay

In some cases you may need to pass a message to a client, have the client enrich some of it’s data and then return the enriched message back. Alternatively you may have a relay scenario, where a message is passed from A to B, it is enriched and then B is passing the enriched message to C.

In both cases we should make our implementation tolerant to message definition changes. Typically B is aware of a subset of properties in the message. The rest of the properties are to be returned (or relayed) “as is” (back to A or to C respectively). The unknown to B subset of properties may be changed, but still we need this to be returned or passed intact. If you are confronting with a situation like that it’s time to use (or at least consider using) the

 ExtensionDataObject

(resides under System.Runtime.Serialization).

The following code snippet implements the roundtripping scenario:

The request message

 [DataContract]
    public class TestServiceRequest : IExtensibleDataObject
    {
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public int Age { get; set; }

        #region IExtensibleDataObject Members
        private ExtensionDataObject _value;
        public ExtensionDataObject ExtensionData
        {
            get { return this._value; }
            set { this._value = value; }
        }

        #endregion
    }

The response message (note that is contains the original request message):

 [DataContract]
    public class TestServiceResponse
    {
        [DataMember]
        public int Code { get; set; }

        [DataMember]
        public TestServiceRequest OriginalRequest { get; set; }
    }

The service definition should be something like this:

 [ServiceContract]
    public interface ITestService
    {
        [OperationContract]
        DataContracts.TestServiceResponse TestMethod(DataContracts.TestServiceRequest request);
    }

So B enriches the request by inserting a “Code”, the rest of the message should be returned to the caller as –is (or relayed to C as-is).

 

Now if you create a client for this service (via svcutil for example) and alter the request message so

as to pass an additional parameter (a field called Surname for instance) , this will be passed and returned as is to the caller. If we hadn’t have the  TestServiceRequest  implementing the IExtensibleDataObject  then the additional field will always return null to the caller.

So despite the fact that DataContractSerializer is based on an opt-in approach –that is, it ignores and does not serialize any unknown field-, in this case it does the opposite. Actually the

 IExtensibleDataObject

interface defines a placeholder for storing unknown data during serialization/de-serialization, so under the hood, the Data Contract Serializer stores all unknown values (the surname field in our example) into this place holder.