nservicebusnservicebus5

NServiceBus & IoT - place a message from client directly in queue and process with NServiceBus at server side


Out back-end is written in .NET using NServiceBus (version 5). Until now, our clients (both .NET clients and c++ clients) were sending messages to a WCF service that has NServiceBus, and the WCF service send the NServiceBus message to the right worker.

Right now we are doing some changes to our architecture and would like some clients to put messages directly in queue and skip the WCF. We have many devices (most are written in c++).

I know that NServiceBus wraps the messages it puts in queue with it's own object. My question is if there is any way for NServiceBus to work in IoT environments - where devices are putting messages directly in to queue, without an adapter in the middle? or for the server side (worker) to handle "regular" messages not wrapped with the NServiceBus object?


Solution

  • You didn't mention what's your Transport, if you're trying to just Send a message to a destination or Publish an event? Some of these choices might change the answer here, but you should get a gist of it.

    You can integrate with NServiceBus directly by putting messages into the queue. If you look at the documentation you'll see there is 'Scripting' section under each transport which shows you how to put messages directly into the queue. If you want to integrate with MSMQ you can find the documentation page here.

    NSB messages come with Headers. Most of the values in the header is optional and they come with a sensible default values so all you really need is the message type (the actual type name for the message payload). Assuming you want to do a Send, you can see all the headers that's at play here. Again you don't need all of that.

    To answer your question: To integrate with NSB from your C++ code, you can translate this C# code to C++ and that's all you need:

    public static void SendMessage(string queuePath, string messageBody, List<HeaderInfo> headers)
    {
        using (var scope = new TransactionScope())
        {
            using (var queue = new MessageQueue(queuePath))
            using (Message message = new Message())
            {
                message.BodyStream = new MemoryStream(Encoding.UTF8.GetBytes(messageBody));
                message.Extension = CreateHeaders(headers);
                queue.Send(message, MessageQueueTransactionType.Automatic);
            }
            scope.Complete();
        }
    }
    
    public static byte[] CreateHeaders(List<HeaderInfo> headerInfos)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(List<HeaderInfo>));
        using (var stream = new MemoryStream())
        {
            serializer.Serialize(stream, headerInfos);
            return stream.ToArray();
        }
    }
    
    public class HeaderInfo
    {
        public string Key { get; set; }
        public string Value { get; set; }
    }
    

    Things to note:

    If you've chosen SQL transport, it'd have made this integration much easier as all you had to do was to write a record in the db (which you can also find a script for here).