我对消息传递相当陌生,我决定使用EasyNetQ(RabbitMQ .Net)构建原型。
我创建了发布者和订阅者,所有似乎都运行良好。我在我的Web服务应用程序中有Publisher,捕获发送到DB的所有命令。我在控制台应用程序中有订阅者接收消息。
但是,当订阅者选择Command对象时,它会抛出错误:
一个类应该有一个默认的构造函数,一个带参数的构造函数或一个用JsonConstructor属性标记的构造函数。
在我的原型中,我有一个类似的Command类:
[Serializable]
public class Command
{
private Type _type;
private string _method;
private object[] _params;
public Command(){
}
public Command(Type type, string method, params object[] Params)
{
_type = type;
_method = method;
_params = Params;
}
public Command(Type type, string method, params object[] Params)
{
_type = type;
_method = method;
_params = Params;
}
public Type Type { get { return _type; } }
public string Method { get { return _method; } }
public object[] Params { get { return _params; } }
}
我将此命令对象传递给发布者:
public void Publish(Command message){
using(var publishChannel = RabbitManager.Instance.OpenPublishChannel()){
publishChannel.Publish(message);
}
}
订阅者收到消息:
public void SubscribeCommand(){
RabbitManager.Instance.Subscribe<Command>("my_subscription_id", msg => Console.WriteLine(msg.Method));
}
当我运行此命令并由订阅服务器处理Command对象时,我收到错误:
错误:订阅calback抛出异常。
交流:'Entities_Command:BL'
路由键:'' Redelivered:'False'
消息: {“Type”:“BL.DataAccess.XXX,BL,Version = 1.2.0.0,Culture = neutral,PublicKeyToken = xxx”,“Method”:“GET”,“Params”: [1,为真,3]}
的 BasicProperties:
ContentType = NULL,ContentEncoding = NULL,Headers = [],DeliveryMode = 2,Priority = 0,CorrelationId = 8aa21f39-4020-4904-b90d-4cb123d3cac0,ReplyTo = NULL,Expiration = NULL,MessageId = NULL,Timestamp = 0,Type = Entities_Command:BL,UserId = NULL,AppId = NULL,ClusterId = NULL 异常:Newtonsoft.Json.JsonSerializationException:无法找到用于类型Entities.Command的构造函数。一个类应该有一个默认的构造函数,一个带参数的构造函数或一个用JsonConstructor属性标记的构造函数。在Newtonsoft.Json.Serialization.JsonSerializerInternalReader的Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject(JsonReader reader,JsonObjectContract objectContract,JsonProperty containerMember,JsonProperty containerProperty,String id,Boolean&amp; createdFromNonDefaultConstructor)中的路径'Type',第1行,第8位。 Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader,Type objectType,JsonContract contract,JsonProperty成员,JsonContainerContract containerContract,JsonProperty)中的CreateObject(JsonReader reader,Type objectType,JsonContract contract,JsonProperty成员,JsonContainerContract containerContract,JsonProperty containerMember,Object existingValue)在Newtonsoft.Json.Json.JsonSerializer.DeserializeInternal(JsonRe)的Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader,Type objectType,Boolean checkAdditionalContent)中的containerMember,Object existingValue)在Newtonsoft.Json.Json.Json.Json.IserializeObject [T]中的Newtonsoft.Json.JsonConvert.DeserializeObject(字符串值,类型类型,JsonSerializerSettings设置)中的Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader,Type objectType)上的ader reader,Type objectType) EasyNetQ.RybitAdvancedBus上的EasyNetQ.JsonSerializer.BytesToMessage [T](字节[]字节)的(字符串值,JsonSerializerSettings设置)。&lt;&gt; c_ DisplayClass5`1.b _4(Byte [] body EasyNetQ.Consumer.HandlerRunner.InvokeUserMessageHandler(ConsumerExecution Context context)中的,MessageProperties属性,MessageReceivedInfo messageRecievedInfo)
我在Command类中有一个默认构造函数,但我仍然不确定为什么会这样。
我试过只传递一个Object类型(而不是Command),它工作正常。
有人可以解释我在这里做错了吗?
答案 0 :(得分:1)
内部EasyNetQ使用Newtonsoft.JSON序列化程序。它期望消息类型是带有默认构造函数的简单DTO(即没有构造函数,或者没有参数的构造函数)和读写属性。您的消息类型Command类具有只读属性,这就是序列化失败的原因。
序列化程序的另一个限制是它不处理多态类型。如果您希望能够将对象[] params转换为可用的东西,那么它就不会起作用。
虽然值得考虑使用Advanced API并进行自定义序列化,但命令模式不是EasyNetQ 目前设计支持的命令模式。计划是在不久的将来发布一个支持多态命令的版本。