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放入默认的序列化程序,但我没有尝试过.