Messages - rebus-org/Rebus GitHub Wiki
To Rebus, a message is just a serializable object. Whether your particular object is serializable, depends on the layout of the object and which serializer you are using, but Rebus comes with a sturdy and tolerant built-in JSON serializer.
Since Rebus likes to route messages based on their types, you will most likely create a class for each type of message you want to send. An example event message could look like this in C# 6:
public class InventoryItemMoved
{
public InventoryItemMoved(string itemId, string newLocationId)
{
ItemId = itemId;
NewLocationId = newLocationId;
}
public string ItemId { get; }
public string NewLocationId { get; }
}
which you would then publish like this:
await bus.Publish(new InventoryItemMoved(someItemId, someNewLocationId));
in order to broadcast it to anyone who did this:
await bus.Subscribe<InventoryItemMoved>();
That's basically all there is to it - although there are some things you need to observe in order to avoid breaking the serialization of the messages. Please read on 😁
Unless you explicitly do something to change the serializer, Rebus will use a pretty robust and tolerant JSON serialization based on Newtonsoft JSON.NET.
It utilizes JSON.NET's ability to include FULL TYPE INFORMATION, which means that an instance of the InventoryItemMoved
event above will be serialized to this (just assuming that it is residing in the Events
namespace of the InventoryManagement.Messages
assembly):
{"$type":"InventoryManagement.Messages.Events.InventoryItemMoved, InventoryManagement.Messages","ItemId":"item-234-abc","NewLocationId":"LOC87484-A"}
which looks a little prettier if we add some indentation:
{
"$type": "InventoryManagement.Messages.Events.InventoryItemMoved, InventoryManagement.Messages",
"ItemId": "item-234-abc",
"NewLocationId": "LOC87484-A"
}
As you can see, the $type
property specifies an assembly-qualified type name for the message type, making it possible for the receiving end to deserialize the message to its proper type.
BUT PLEASE NOTE that each of the property names in the JSON text must correspond to either
- a publicly settable property with the same name and a compatible type, or
- a constructor parameter with the same name (possibly camelCase) and a compatible type
In other words, you would ALSO be able to deserialize the JSON shown above with this class:
public class InventoryItemMoved
{
public string ItemId { get; set; }
public string NewLocationId { get; set; }
}
where the following classes would FAIL to deserialize the JSON text shown above:
public class InventoryItemMoved
{
// \/ should have been 'itemId'!!
public InventoryItemMoved(string relevantItemId, string newLocationId)
{
ItemId = relevantItemId;
NewLocationId = newLocationId;
}
public string ItemId { get; }
public string NewLocationId { get; }
}
public class InventoryItemMoved
{
public string Item { get; set; } // << missing 'Id' in name!
public string NewLocationId { get; set; }
}
Another thing with messages is that it is usually advised to keep them small! This is because big messages can end up clogging the queues, leading to unpredictable latencies when processing them, etc.
It also this realization that has caused most queueing systems to have a hard cap on how big messages can be - e.g. MSMQ allows for maximum 4 MB messages (which is actually pretty big!) where Azure Service Bus has a maximum of 64 kB.
If you need to transfer bigger chunks of data with Rebus, you should probably look into using Rebus' data bus.