Search code examples
c#jsonxmlnservicebus

Publish NServiceBus event from v6 JSON to v4 XML environment


I'm looking for a way to publish events from our new NServiceBus 6 endpoint environment to an older v4 endpoint environment. To make matters more interesting, the v6 is using JSON and the v4 is using XML.

  • Do I need to simply add a mutator on the incoming v4 endpoint?
  • How do I convert the JSON message to an XML message? In the above mentioned mutator?
  • Do I need to add any specific v4 message headers on the outgoing event message?

I'm using MSMQ as the underlying transport layer.


Solution

  • Potentially the simplest way to move forward is to write a custom serializer definition. The following example assumes the default XmlSerializer and JsonSerializer available in NServiceBus v6 are used.

    Write a custom serializer definition

    public class CustomJsonSerializer : SerializationDefinition
    {
        public override Func<IMessageMapper, IMessageSerializer> Configure(ReadOnlySettings settings)
        {
            var xmlSerializerDefinition = new XmlSerializer();
            var xmlSerializerFactory = xmlSerializerDefinition.Configure(settings);
    
            var jsonSerializerDefinition = new JsonSerializer();
            var jsonSerializerFactory = jsonSerializerDefinition.Configure(settings);
            return mapper => new DecoratorSerializer(xmlSerializerFactory(mapper), jsonSerializerFactory(mapper));
        }
    }
    

    Write a serializer decorator that has custom logic to forward message types to the XmlSerializer if they are targetted towards the V4 endpoint.

    class DecoratorSerializer : IMessageSerializer
    {
        IMessageSerializer xmlSerializer;
        IMessageSerializer jsonSerializer;
    
        public DecoratorSerializer(IMessageSerializer xmlSerializer, IMessageSerializer jsonSerializer)
        {
            this.xmlSerializer = xmlSerializer;
            this.jsonSerializer = jsonSerializer;
        }
    
        public void Serialize(object message, Stream stream)
        {
            if (message.GetType() == typeof(MyMessage))
            {
                xmlSerializer.Serialize(message, stream);
            }
            else
            {
                jsonSerializer.Serialize(message, stream);
            }
        }
    
        public object[] Deserialize(Stream stream, IList<Type> messageTypes = null)
        {
            return jsonSerializer.Deserialize(stream, messageTypes);
        }
    
        public string ContentType
        {
            get { return jsonSerializer.ContentType; }
        }
    }
    

    use the CustomSerializer like the following

    endpointConfiguration.UseSerializer<CustomJsonSerializer>();
    

    A working sample can be found on this github repo. The sample uses commands but the approach should also work for PubSub. The only caveat is that a specific message type will always use one format. So it is not possible to publish the same event once in Xml and for other publishes in Json.