Search code examples
c#rabbitmqrebus

Rebus RabbitMQ Object serialization


How come when I send a message to RabbitMQ through rebus that it is adding extra object data like below, primarily the $type.

{"$type":"ThreeSquared.VTGPAM.Objects.Wagon, ThreeSquared.VTGPAM.Objects","WagonId":"a98a06ab-33b9-4a11-9de2-df0b8787b713","WamosId":12324,"Description":"test","YearBuilt":1982,"Token":"3cce443c-249f-4fd2-9882-5830fb308b6b"}

We have a client that will just be using the Java RabbitMQ library with no rebus. This approach I believe we just send the JSON without the type declarations. This therefore doesn't work when I try and read in simple JSON object. How can we make it work so that it doesn't define the $type in the message?


Solution

  • It's simply because Rebus by default uses Newtonsoft JSON.NET with TypeNameHandling.All, which means that the $type field is included in every serialized object containing the full .NET type name of the type serialized.

    The benefit is that you can serialize almost anything, even though it may contain instances referenced by (possibly abstract) supertypes, and even by interfaces.

    E.g. this command message type

    public class ProcessFile
    {
        public ProcessFile(string filePath, IEnumerable<IFileProcessingTask> tasks)
        {
            FilePath = filePath;
            Tasks = tasks;
        }
    
        public string FilePath { get; }
    
        public IReadOnlyCollection<IFileProcessingTask> Tasks { get; }
    }
    

    could contain arbitrary implementations of IFileProcessingTask, e.g. something like

    public class GZipFileProcessingTask : IFileProcessingTask
    {
        // ...    
    }
    

    as long as the recipient can find the type by looking it up via the value of the $type field.

    If you want to process this type of message on another platform, you can simply make it ignore the $type field of every object. This may be easy/hard/impossible, depending on how flexible your JSON serializer is.

    Another option is to simply replace Rebus' serializer with your own implementation by doing this

    Configure.With(...)
        .(...)
        .Serialization(s => s.UseCustomJsonSerialization())
        .Start();
    

    where UseCustomJsonSerialization is an extension method that you implement like this:

    public static class RebusConfigEx
    {
        public static void UseCustomJsonSerialization(this StandardConfigurer<ISerializer> configurer)
        {
            configurer.Register(c => new YourCustomJsonSerializer());
        }
    }
    

    and then all there is left to do is to create the class YourCustomJsonSerializer as an implementation of ISerializer.