Monday, November 1, 2010

Getting Started with NServiceBus Part 8: Message Versioning

So now you've gone live with your first system based on NSB. Time goes by and you have a new requirement to add some data to a published event. How will we provide backwards compatibility? How will we upgrade? What if legacy subscribers don't care about the new information? Luckily for us NSB handles this given we modeled our messages as interfaces, giving us an inheritance structure we can use to our advantage. This article will how how easily this can be done.

Let's begin given our current message:
public interface IProductUpdatedEvent : IProductChangedEvent
    public interface IProductChangedEvent : IEvent
        Int32 ProductNumber { get; set; }
        String Name { get; set; }
        String Description { get; set; }       
Now let's say we want to add a new field to our event. We create the new event in a different namespace so we can use the same interface name and add our new field after we implement the old interface:
public interface IProductUpdatedEvent : Messages.IProductUpdatedEvent
        Int32 DepartmentNumber { get; set; }
So now we have two distinct messages that have different data sets. This means our legacy clients can continue to receive the legacy message and our new clients can receive the new message. Here is an example of a handler pointing to the new message type:
public class EventMessageHandler : IMessageHandler<Messages.New.IProductUpdatedEvent>
        private static ILog log = LogManager.GetLogger(typeof(EventMessageHandler));

        public void Handle(Messages.New.IProductUpdatedEvent message)
            log.Debug(String.Format("{0} Event Received for Product {1}: {2} : {3}", message.GetType().UnderlyingSystemType.Name, message.ProductNumber, message.Name, message.DepartmentNumber));
The rest of our Subscribers remain the same. All that is left is to update the Publisher to publish the new event. In the example code there is a Windows Forms app(UI) that pushes all events to a common Publisher endpoint. See the Documentation directory for a diagram. In the example all we have to do is add the new field and publish the new event.
Messages.New.IProductUpdatedEvent pu = new Messages.New.ProductUpdatedMessage
                ProductNumber = Int32.Parse(textBoxUpdateID.Text),
                Description = textBoxUpdateDesc.Text,
                Name = textBoxUpdateName.Text,
                EventId = Guid.NewGuid(),
                Time = DateTime.Now,                
                DepartmentNumber = 10

If you pull down the sample and look in the PubSub directory, fire up the BusServer, UI, Subscriber1, and Subscriber3 projects. From the UI simple type in second group box and hit the "Update" button. This will send the new message to the "BusServer" Publisher endpoint which will do the actual Bus.Publish(). From there you will see Subscriber1 receive the legacy event and Subscriber3 receive the new event with the new data.

NSB allows us to gracefully support new message types and uphold backwards compatibility. We were able to introduce new data and rely upon inheritance to handle the rest. Full code can be found here:

No comments:

Post a Comment