HelloWorld示例,用于通过EasyNetQ在两个不同的应用程序之间通过RabbitMQ发送对象

yme*_*rej 5 c# rabbitmq easynetq

嗨,我试图通过EasyNetQ通过RabbitMQ发送一个简单的对象.我在订阅方面反序列化该对象时遇到问题.任何人都能告诉我一个如何工作的样本.请记住,正在发送的对象是在其自己的项目中定义的,而不是在发布者和订阅者之间共享.这是我的样本,也许你可以告诉我它有什么问题?

计划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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

方案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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我收到的错误:

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)<---
Run Code Online (Sandbox Code Playgroud)

为了能够正确反序列化,我需要做MessageA什么?

Fur*_*may 11

据我所知,EasyNetQ 的默认设置要求序列化对象的类型在应用程序之间保持一致.例如,您可以像String一样轻松地发送任何已知的.NET类型:

 bus.Publish<String>("Excellent.");
Run Code Online (Sandbox Code Playgroud)

这两个项目都会很开心.

如果将其放入公共库(dll),则可以使用自己的Message .由于您特别提到它们位于不同的项目中,我建议您自己序列化和转换对象.

EasyNetQ通过内部使用Newtonsoft Json.NET来序列化这样的对象.如您所见,您的消息已被序列化为:

消息:{"Text":"Hello World"}

要自己执行此操作,您仍需要添加对Json.NET的引用,因为EasyNetQ使用ilrepack隐藏此引用.

这应该工作:

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

和

bus.Subscribe<string>("", HandleClusterNodes);

private static void HandleClusterNodes(string obj)
{
    var myMessage = (MessageB)JsonConvert.DeserializeObject<MessageB>(obj);
    Console.WriteLine(myMessage.Text);
}
Run Code Online (Sandbox Code Playgroud)

但是你会丢失基于属性的路由,并且可能想要修改你的方法.

如果您想继续使用基本方法,可以像这样设置主题:

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")));
Run Code Online (Sandbox Code Playgroud)

但要完全控制,您需要使用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);
Run Code Online (Sandbox Code Playgroud)

在订户部分:

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));
Run Code Online (Sandbox Code Playgroud)

这与原始的RabbitMQ C#Client API几乎相同.


详细分析:

主要问题是这个例外:

EasyNetQ.EasyNetQException:找不到类型EasyNetQSample.ProgramA + MessageA:EasyNetQSample

这是由EasyNetQ引发的,因为它无法在端点上找到特殊类.

如果我们查看TypeNameSerializer.cs的源代码,您将看到

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

这是它试图找到EasyNetQSample.ProgramA.Message 一对类型第二个项目,而只知道EasyNetQSample.ProgramB.Message 乙.

或者,您可以推出自己的自定义ISerializer或将ITypeNameSerializer放入默认的序列化程序,但我没有尝试过.