One of the things that can help keeping service interfaces stable are well defined messages. However, it is very likely that at some point in the lifecycle of a service, adjustments in the messages are needed to support new functionality. These versioning problems in messages can be handled very easily by making use of the [XmlAnyElement] and [XmlAnyAttribute] in the messages.
When we have a look at the XML schema standard we can see that it defines the “<any/>” item for arbitrary xml content and the “<anyattribute />” item for undefined attributes inside an xml document. We can use these two items to define XML schemas that are highly extensible. By using the .NET [XmlAnyElement] and [XmlAnyAttribute] attributes we can deliver this extensibility feature of the xml schema in the messages used by our services.
Using the above mentioned attributes is very simple. We can add the attributes to a field in our message. The “NormalMessageContent” field on the “SampleMessage” class below is the only field that is a fixed part of the message.The other two field are there to hold de “custom xml” (FlexibleMessageContent) and the “custom attributes” (FlexibleMessageAttributes).
[Serializable]
public class SampleMessage
{
public string NormalMessageContent;
[XmlAnyAttribute]
public XmlAttribute[] FlexibleMessageAttributes;
[XmlAnyElement]
public XmlElement[] FlexibleMessageContent;
}
The XmlSerializer (deserialize) will store all unmapped (unrecognized) XML elements in the “FlexibleMessageContent” field. All unrecognized attributes are stored in the “FlexibleMessageAttributes” field. Basically any content in an xml document other than the “NormalMessageContent” element will be available in our service through the two “flexible” fields.
So, By adding two fields to our message and tag them with the above mentioned attributes we can create messages that support versioning very well. Besides using this technique for versioning we can also use this to standardize messages. By using the above approach it is also possible to create a message with a few standard fields (messageId, timestamp, etc.) and one field that is used for the actual message content. In theory this message can be send to every service. It’s up to the service to decide if it understands the message that is stored in the message content field of the message. Creating service interfaces with these kinds of standardized messages might be a good way to keep the services interface stable!