使用Azure BrokeredMessage获取消息体而不知道其类型

35

在使用 Azure Service Bus 中的经纪代理消息时,您可以通过调用 .GetBody 来检索消息的正文。代码很简单:

var msg = subscription.Receive();
MyPayload payload = msg.GetBody<MyPayload>();

但是,是否有一种方法可以在不显式知道 Body 对象类的情况下检索 Body?

var msg = subscription.Receive();
Type bodyType = Type.GetType( msg.ContentType);

var payload = msg.GetBody<bodyType>();
3个回答

81

如果意图仅是获取消息正文,而不考虑其内容,可以将其作为流获取。

Stream stream = message.GetBody<Stream>();
StreamReader reader = new StreamReader(stream);
string s = reader.ReadToEnd();

2
不错的提示!这应该是MSDN文档的一部分 :) - Hector Correa
1
这对于与 Node 进行互操作非常有用,特别是当您想在消息体中发送 JSON 数据时。 - Peter M
1
输出结果中出现了额外的字符串字符,例如 @string3http://schemas.microsoft.com/2003/10/Serialization/�h {"MyID":"121"} - Neo
@Neo 是的,没错,只要我执行 GetBody<Stream>() 就会得到这个额外的文本。有没有什么简单的方法可以去掉它?这是与编码有关的吗? - Vinod
好的,如果有人想要摆脱它,我推荐以下答案,它非常有效:-)https://dev59.com/vKbja4cB1Zd3GeqPofVV#47429841 - Vinod
1
由于这里使用了Stream类...应该使用using吗?还是不需要处理? - MBender

31
以下是从brokeredmessage反序列化的完整代码:
public T GetBody<T>(BrokeredMessage brokeredMessage)
{
  var ct = brokeredMessage.ContentType;
  Type bodyType = Type.GetType(ct, true);

  var stream = brokeredMessage.GetBody<Stream>();
  DataContractSerializer serializer = new DataContractSerializer(bodyType);
  XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(stream, XmlDictionaryReaderQuotas.Max);
  object deserializedBody = serializer.ReadObject(reader);
  T msgBase = (T)deserializedBody;
  return msgBase;
}

3
这取决于 brokeredMessage.ContentType。如果我们只发送字符串,则该属性可能已设置或未设置。是否有任何方法可以识别其是简单字符串、流还是类类型? - Joy George Kunjikkuru
1
这个答案帮助解决了在Azure的WebWorkerRole上使用GetBody<T>()访问brokeredmessage正文时出现序列化错误的问题。谢谢。 - TombMedia
@Joymon 我不确定这是否是最佳实践,但你可以在发送消息时设置ContentType:var message = new BrokeredMessage(request); message.ContentType = request.GetType().Name; - Dunc
可以使用以下简化代码:var bodyType = System.Type.GetType("System.String"); - Fernando JS

6

在使用ContentType之前,需要检测主体类型。我认为发送方应该设置ContentType。

我实现了类似的逻辑,在发送方将消息属性设置为对象类型,并从消息属性中恢复类型后,在接收方调用GetBody<>()方法。

public void SendData(object payloadData)
    {
        if (payloadData == null) return;

        var queueClient = QueueClient.CreateFromConnectionString(ConnectionString, _queueName);

        var brokeredMessage = new BrokeredMessage(payloadData);
        brokeredMessage.Properties["messageType"] = payloadData.GetType().AssemblyQualifiedName;
        queueClient.Send(brokeredMessage);
    }

消息属性"messageType"具有完整的类型名称。

在接收方,我会这样做:

 var messageBodyType = Type.GetType(receivedMessage.Properties["messageType"].ToString());
                if (messageBodyType == null)
                {
                    //Should never get here as a messagebodytype should
                    //always be set BEFORE putting the message on the queue
                    Trace.TraceError("Message does not have a messagebodytype" +
                                     " specified, message {0}", receivedMessage.MessageId);
                    receivedMessage.DeadLetter();
                }


                //read body only if event handler hooked
                    var method = typeof(BrokeredMessage).GetMethod("GetBody", new Type[] { });
                    var generic = method.MakeGenericMethod(messageBodyType);
                    try
                    {
                        var messageBody = generic.Invoke(receivedMessage, null);
                         DoSomethingWithYourData();
                        receivedMessage.Complete();
                    }
                    catch (Exception e)
                    {
                        Debug.Write("Can not handle message. Abandoning.");
                        receivedMessage.Abandon();
                    }
                }

谢谢您先生!这正是我在寻找的解决方案! - Casey Crookston

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接