Can't receive rebus rabbitMQ messages when the object which is published is not shared

59 Views Asked by At

When trying to solve my issue with not receiving messages through RabbitMQ using Rebus, I tried playing with this sample: https://github.com/rebus-org/RebusSamples/tree/master/PubSubNative and found that the object, which is published from the publisher(pub) to the subscribers(subs), have to be the exact same shared object "StringMessage" for both subs and pub. It does not work when I create classes by the same name and properties in each project. I like it to not have the shared files but have their own classes - if it's possible?

2

There are 2 best solutions below

0
On BEST ANSWER

Yes it's possible, but you'll have to circumvent the deserialization on the receiving end to somehow resolve the receiver's definition of StringMessage even though it's the sender's StringMessage that got serialized.

You might want to check out the SharedNothing sample that demonstrates this particular thing.

The main part is the CustomMessageDeserializer that uses this dictionary to map from simple, assembly-qualified type names to the desired types.

0
On

I Can Send messages to rebus using RabbitMQ Client only without rebus or shared message types from the sender. However on the receiving side I have all classes defined. And this usually one way.

I use this in .net 4.6 project windows forms application which just needs to send message.

I have this helper:

using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
using RabbitMQ.Client;


namespace CMIS.Helpers
{
    public class RebusClient
    {

        public static void SendMessage<T>(string exchangeName, string queueName, string routingKey, Dictionary<string, object> headers, T message)
        {

            string[] qusvr = Context.Variables["QUSVR"].ToString().Split(':');
            string hostName = qusvr[0];
            string userName = qusvr[1];
            string password = qusvr[2];

            ConnectionFactory factory = new ConnectionFactory
            {
                HostName = hostName,
                UserName = userName,
                Password = password
            };

            using (IConnection connection = factory.CreateConnection("CMIS"))
            {
                using (IModel model = connection.CreateModel())
                {
                    model.ExchangeDeclare(exchangeName, "direct", true, false, null);

                    model.QueueDeclare(queueName, true, false, false, null);

                    model.QueueBind(queueName, exchangeName, routingKey, null);

                    var messageBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(message));

                    IBasicProperties props = model.CreateBasicProperties();
                    props.Persistent = true;
                    props.ContentType = "text/plain";
                    props.DeliveryMode = 2;
                    props.Headers = headers;
                    model.BasicPublish(exchangeName, routingKey, props, messageBytes);
                }
            }
        }
    }
}

And then I can Send Message this way

string facilityCode = claimDetails["FacilityCode"].ToString();
            int claimYear = claimDetails["ClaimYear"].ConvertTo<int>();
            int claimMonth = claimDetails["ClaimMonth"].ConvertTo<int>();
            string requestNo = string.Format("Queue-{0}-{1}{2}", facilityCode, claimYear, claimMonth < 10 ? $"0{claimMonth}" : claimMonth.ToString());
            JObject message = new JObject(
                                            new JProperty("$type", MessagingConstants.QueueUncapturedFolios),
                                            new JProperty("RequestNo", requestNo),
                                            new JProperty("FacilityCode", facilityCode),
                                            new JProperty("ClaimYear", claimYear),
                                            new JProperty("ClaimMonth", claimMonth)
                                         );

            Dictionary<string, object> headers = new Dictionary<string, object>
                                {
                                    { MessagingConstants.MessageTypeHeader, MessagingConstants.QueueUncapturedFolios },
                                    { MessagingConstants.ContentTypeHeader, MessagingConstants.ContentType }
                                };

            RebusClient.SendMessage("RebusDirect", "online_claims_processing", "online_claims_processing", headers, message);

And here are the constants used

public static class MessagingConstants
{
    public const string QueueDocuments = "NHIF.Shared.Messages.QueueDocuments,NHIF.Shared.Messages";
    public const string QueueUncapturedFolios = "NHIF.Shared.Messages.QueueUncapturedFolios,NHIF.Shared.Messages";
    public const string ProcessSkippedFolios = "NHIF.Shared.Messages.ProcessSkippedFolios,NHIF.Shared.Messages";
    public const string CloseSubmissionWindow = "NHIF.Shared.Messages.CloseSubmissionWindow,NHIF.Shared.Messages";
    public const string ContentType = "application/json;charset=utf-8";
    public const string MessageTypeHeader = "rbs2-msg-type";
    public const string ContentTypeHeader = "rbs2-content-type";
}

Although I might not be addressing your problem this way helps me evading sharing classes (Message Types) where there is no need for that. And in that way the message is serialized with all the headers and rebus will process them without any problem.

Raegards