【问题标题】:How can I tell two JSON objects apart on one RabbitMQ queue?如何在一个 RabbitMQ 队列上区分两个 JSON 对象?
【发布时间】:2014-04-08 14:13:50
【问题描述】:

我希望能够在一个队列上发送两条不同的 JSON 消息。在 C# 中,我如何确定接收到的消息类型,以便我可以将消息反序列化为正确的对象?我应该使用消息头还是创建另一个队列?每种消息类型的队列对我来说似乎过多。谢谢!

额外细节: 我有一个处理“运行”的 Windows 服务。运行 ID 由另一个系统分配,该 ID 被放入队列中。我的服务获取 ID 并开始工作。每次运行都会创建一个对象。现在,如果我想取消工作,我必须停止服务。但是,这会停止所有工作。我想添加一个 CancelRun 类型的方法,但我只需要运行 ID。所以,我可以使用完全相同的 JSON(所以相同的类)。两个队列并不可怕,但我认为将类型或其他内容添加到自定义标头可能很聪明。

【问题讨论】:

    标签: c# json rabbitmq deserialization


    【解决方案1】:

    这就是我的选择。我喜欢这种技术,因为我不会向 JSON 添加不属于模型的内容。

    IBasicProperties props = model.CreateBasicProperties();
    props.Headers = new Dictionary<string, object>();
    props.Headers.Add("RequestType", "CancelRunRequest");
    

    然后,在接收端,我这样做(我正在使用自定义 EventArg obj 引发一个事件):

    // Raise message received event
    var args = new MessageReceivedArgs();
    args.CorrelationId = response.BasicProperties.CorrelationId;
    args.Message = Encoding.UTF8.GetString(response.Body);
    args.Exchange = response.Exchange;
    args.RoutingKey = response.RoutingKey;
    
    if (response.BasicProperties.Headers != null && response.BasicProperties.Headers.ContainsKey("RequestType"))
    {
    args.RequestType = Encoding.UTF8.GetString((byte[])response.BasicProperties.Headers["RequestType"]);
    }
    
    MessageReceived(this, args);
    model.BasicAck(response.DeliveryTag, false);
    

    项目的其他地方:

    private void NewRunIdReceived(object p, MessageReceivedArgs e)
    {
    
    if(e.RequestType.ToUpper() == "CANCELRUNREQUEST")
    {
        // This is a cancellation request
        CancelRun(e);
    }
    else
    {
        // Default to startrun request for backwards compatibility.
        StartRun(e);
    }
    }
    

    【讨论】:

    • 我不知道为什么没有人标记这个正确的答案,这是最好的方法,保持邮件正文干净,并按应有的方式使用元数据。对我来说正确的答案。干得好
    • @sacha 谢谢!我不想在没有其他输入的情况下接受我自己的答案。感谢您的反馈!
    【解决方案2】:

    如果订购或接收和处理这些消息不是问题,我想建议为每种类型使用单独的队列,兔子处理大量队列不是问题。 如果不是,那么顺序对您来说至关重要,您可以在消息的标题中放置标记来定义它的类型,但这会将您的业务逻辑与传输层绑定。如果您想稍后在应用程序中更改传输层,则必须采用这部分代码以使其正常工作。取而代之的是,您可以为这两种对象类型制作某种包装器,它隐藏了内部内容,看起来相同,并且可以在它包含的类型中淡化自身。

    【讨论】:

    • 我确实考虑过单独的队列,但这在当时对我来说似乎太过分了。我真的很喜欢你的包装类的想法,它可以找出要生成的正​​确对象。听起来有点像工厂模式。
    • 处理rabbit的多个队列在性能方面不是问题,直到它有界而不是持续增长。
    • 我并不担心性能问题。我不想养成每次定义新消息类时都创建新队列的习惯。
    • 如果性能不是问题 - 只需专注于良好的设计和代码布局。请记住,稍后您可能希望通过系统中的同一管道发送第三种类型的 JSON 对象,只需使其更易于添加而无需更改大量代码。
    【解决方案3】:

    按照 sphair 的建议添加运行时类型信息是可行的,但我不喜欢这样做,因为您失去了拥有弱类型的可移植性价值。您还可以考虑让反序列化的 C# 对象足够通用以处理所有风格,然后从那里分支。

    【讨论】:

    • 我也想过这个问题。我可以为 CancelRun 添加一个布尔值,让新工作为假,取消工作为真,但这对我来说似乎有点麻烦。
    【解决方案4】:

    您可以将它们全部添加到数组中,然后根据类型进行反序列化,您必须手动添加类型属性,或者您可以创建 Object IHaveType 然后在正在使用的对象中从它继承,但这是一种可怕的方式这样做。

    ObjectType1 : HaveType 
    
    public class HaveType { public string Type { get { this.GetType(); }}}
    

    json

    [{Type: 'ObjectType1', ...[other object stuff]},{Type : 'ObjectType2',...}]
    

    【讨论】:

      【解决方案5】:

      JSON 不会说明它是从什么类型进行序列化的,除非序列化程序本身向 JSON 添加了一些信息。

      您可以在 JSON 中添加一些结构,以便可以推断类型。

      【讨论】:

      • 既然类型不在 JSON 中,将类型添加到消息头是否合适?
      猜你喜欢
      • 2015-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-13
      • 1970-01-01
      • 2018-07-28
      • 2014-10-30
      相关资源
      最近更新 更多