HelloWorld example for sending an object via RabbitMQ via EasyNetQ between two different applications

Hey. I am trying to send a simple object, for example via RabbitMQ via EasyNetQ. I am having problems deserializing this object on the subscription side. Anyone who can show me an example of how this works. Keep in mind that the sending object is defined in it by its own project and is not distributed among the publisher and subscriber. Here is my example, and perhaps you can tell me what is wrong with him?

Program A:

class ProgramA { static void Main(string[] args) { using (var bus = RabbitHutch.CreateBus("host=localhost")) { Console.WriteLine("Press any key to send the message"); Console.ReadKey(); bus.Publish(new MessageA { Text = "Hello World" }); Console.WriteLine("Press any key to quit"); Console.ReadKey(); } } public class MessageA { public string Text { get; set; } } } 

Program B:

 class ProgramB { static void Main(string[] args) { using (var bus = RabbitHutch.CreateBus("host=localhost")) { bus.Subscribe<MessageB>("", HandleClusterNodes); Console.WriteLine("Press any key to quit"); Console.ReadKey(); } } private static void HandleClusterNodes(MessageB obj) { Console.WriteLine(obj.Text); } [Queue("TestMessagesQueue", ExchangeName = "EasyNetQSample.ProgramA+MessageA:EasyNetQSample")] public class MessageB { public string Text { get; set; } } } 

Here is the error I get:

 DEBUG: HandleBasicDeliver on consumer: f9ded52d-039c-411a-9b9f-5c8ee3301854, deliveryTag: 1 DEBUG: Received RoutingKey: '' CorrelationId: 'ec41faea-a0c8-4ffd-8163-2cbf85d45fcd' ConsumerTag: 'f9ded52d-039c-411a-9b9f-5c8ee3301854' DeliveryTag: 1 Redelivered: False ERROR: Exception thrown by subscription callback. Exchange: 'EasyNetQSample.ProgramA+MessageA:EasyNetQSample' Routing Key: '' Redelivered: 'False' Message: {"Text":"Hello World"} BasicProperties: ContentType=NULL, ContentEncoding=NULL, Headers=[], DeliveryMode=2, Priority=0, CorrelationId=ec41faea-a0c8-4ffd-8163-2cbf85d45fcd, ReplyTo=NULL, Expiration=NULL, MessageId=NULL, Timestamp=0, Type=EasyNetQSample.ProgramA+MessageA:EasyNetQSample, UserId=NULL, AppId=NULL, ClusterId=NULL Exception: System.AggregateException: One or more errors occurred. ---> EasyNetQ.EasyNetQException: Cannot find type EasyNetQSample.ProgramA+MessageA:EasyNetQSample at EasyNetQ.TypeNameSerializer.DeSerialize(String typeName) at EasyNetQ.DefaultMessageSerializationStrategy.DeserializeMessage(MessageProperties properties, Byte[] body) at EasyNetQ.RabbitAdvancedBus.<>c__DisplayClass19.<Consume>b__18(Byte[] body, MessageProperties properties, MessageReceivedInfo messageReceivedInfo) at EasyNetQ.RabbitAdvancedBus.<>c__DisplayClass1e.<Consume>b__1d(Byte[] body, MessageProperties properties, MessageReceivedInfo receviedInfo) at EasyNetQ.Consumer.HandlerRunner.InvokeUserMessageHandler(ConsumerExecutionContext context) --- End of inner exception stack trace --- ---> (Inner Exception #0) EasyNetQ.EasyNetQException: Cannot find type EasyNetQSample.ProgramA+MessageA:EasyNetQSample at EasyNetQ.TypeNameSerializer.DeSerialize(String typeName) at EasyNetQ.DefaultMessageSerializationStrategy.DeserializeMessage(MessageProperties properties, Byte[] body) at EasyNetQ.RabbitAdvancedBus.<>c__DisplayClass19.<Consume>b__18(Byte[] body, MessageProperties properties, MessageReceivedInfo messageReceivedInfo) at EasyNetQ.RabbitAdvancedBus.<>c__DisplayClass1e.<Consume>b__1d(Byte[] body, MessageProperties properties, MessageReceivedInfo receviedInfo) at EasyNetQ.Consumer.HandlerRunner.InvokeUserMessageHandler(ConsumerExecutionContext context)<--- 

What do I need to do to properly deserialize MessageA ?

+5
source share
3 answers

As far as I know, the default setting for "EasyNetQ" requires that the type of serialized object be consistent between applications. For example, you can send any known .NET type as String:

  bus.Publish<String>("Excellent."); 

and he will be happy in both projects.

You can use your own message if you put it in a shared library (dll). Since you specifically mentioned that they live in different projects, I would suggest serializing and pouring the objects yourself.

EasyNetQ uses interal Newtonsoft Json.NET to serialize such objects. As you can see, your message has already been serialized as:

Message: {"Text": "Hello World"}

To do this, you still need to add a link to Json.NET, because EasyNetQ hides this link using ilrepack .

This should work:

 bus.Publish<string>(JsonConvert.SerializeObject(new MessageA { Text = "Hello World" })); 

and

 bus.Subscribe<string>("", HandleClusterNodes); private static void HandleClusterNodes(string obj) { var myMessage = (MessageB)JsonConvert.DeserializeObject<MessageB>(obj); Console.WriteLine(myMessage.Text); } 

But you will lose your attribute-based routing, and you might want to change your methods.

If you want to use the basic methods, you can set the theme as follows:

 bus.Publish<string>(JsonConvert.SerializeObject(new MessageA { Text = "Hello World" }), "topic.name"); bus.Subscribe<string>("", HandleClusterNodes, new Action<EasyNetQ.FluentConfiguration.ISubscriptionConfiguration>( o => o.WithTopic("topic.name"))); 

But in order to have a complete control, you need to use the Advanced API ;

 var yourMessage = new Message<string>(JsonConvert.SerializeObject(new MessageA { Text = "Hello World" })); bus.Advanced.Publish<string>(new Exchange("YourExchangeName"), "your.routing.key", false, false, yourMessage); 

and on the subscriber part:

 IQueue yourQueue = bus.Advanced.QueueDeclare("AnotherTestMessagesQueue"); IExchange yourExchange = bus.Advanced.ExchangeDeclare("YourExchangeName", ExchangeType.Topic); bus.Advanced.Bind(yourExchange, yourQueue, "your.routing.key"); bus.Advanced.Consume<string>(yourQueue, (msg, info) => HandleClusterNodes(msg.Body)); 

which is almost the same as the original RabbitMQ C # API.


Detailed analysis:

The main problem is this exception:

EasyNetQ.EasyNetQException: cannot find type EasyNetQSample.ProgramA + MessageA: EasyNetQSample

This is called by EasyNetQ because it cannot find a special class on the endpoint.

If we look at the source code of TypeNameSerializer.cs , you will see

 var type = Type.GetType(nameParts[0] + ", " + nameParts[1]); if (type == null) { throw new EasyNetQException( "Cannot find type {0}", typeName); } 

here he tried to find the EasyNetQSample.ProgramA.Message A file in the second project, while he only knew EasyNetQSample.ProgramB.Message B.

Alternatively, you can deploy your own ISerializer or set ITypeNameSerializer to the default serializer , but I have not tried this.

+7
source

Furkan is correct that your problem is that the subscriber needs access to the MessageA type defined by your publisher so that he can deserialize the message to this type. From EasyNetQ Docs

When messages are serialized, EasyNetQ stores the message type name in the Type property of the message properties. This metadata is sent along with your message to all subscribers who can then use it to deserialize the message.

This means a limited general contract between the publisher and the consumer. If you want to ease this, you can do a few things:

  • You can publish and subscribe based on an interface (e.g. IMessage , from which you can get MessageA ). You still need access to the MessageA type in order to transmit the received message, but you can publish and subscribe without specifying a specific derived type.

  • You can create a single generic container type (e.g. MessageContainer ) and then serialize / deserialize your type into an instance of the container type as XML, JSON, whatever. Your subscriber can pull data from the container and analyze it, but he wants to. You can even include schema or version information in the container header to give some tips to the subscriber on how to analyze the data. That they should never turn it into a specific type and therefore do not need access to a set of types, just a MessageContainer type, so that they can receive serialized content.

+1
source

MessageA class must be within both applications.

 bus.Publish<MessageA>("Excellent."); 
+1
source

Source: https://habr.com/ru/post/1204872/


All Articles