35

When you are using the brokered message in the Azure Service Bus, you can retrieve the body of the message with the call .GetBody. The code is simple:

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

However, is there a way to retrieve the Body without explicitly knowing the class of the body object?

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

var payload = msg.GetBody<bodyType>();
Nikolai Samteladze
  • 7,699
  • 6
  • 44
  • 70
yamspog
  • 18,173
  • 17
  • 63
  • 95

3 Answers3

81

If the intent is to only grab the message body regardless of the content you can get it as a stream.

Stream stream = message.GetBody<Stream>();
StreamReader reader = new StreamReader(stream);
string s = reader.ReadToEnd();
Nikolai Samteladze
  • 7,699
  • 6
  • 44
  • 70
ckross01
  • 1,681
  • 2
  • 17
  • 26
  • 2
    Nice tip! This should have been part of the MSDN documentation :) – Hector Correa Nov 08 '13 at 16:51
  • 1
    This is also really useful for inter-op with Node where you might want to send around JSON in the body of a message – Peter M Oct 26 '15 at 21:28
  • 1
    which gives extra string char with my output like `@string3http://schemas.microsoft.com/2003/10/Serialization/�h {"MyID":"121"}` – Neo Sep 03 '18 at 07:57
  • @Neo yes, that's right, I get this additional text as soon as I do GetBody(). Is there a clean way to remove this? Is this something to do with encoding? – Vinod Jun 09 '20 at 13:35
  • Ok, someone looking to get rid of it, I refer to the following answer, worked like a charm :-) https://stackoverflow.com/a/47429841/419556 – Vinod Jun 09 '20 at 17:53
  • 1
    Since this is using the `Stream` classes... should `using` be used? Or does this not require disposing? – MBender Nov 27 '20 at 09:06
31

Here is the complete code to deserialize from the 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;
}
yamspog
  • 18,173
  • 17
  • 63
  • 95
  • 3
    This depends on brokeredMessage.ContentType. If we just send string this property may or may not be set. Are there any way to identify its a simple string,stream or class type? – Joy George Kunjikkuru Jun 25 '13 at 14:03
  • 1
    This answer helped solve serialization errors using GetBody() on a WebWorkerRole in Azure trying to access the body of a brokeredmessage. Thanks. – TombMedia Jul 02 '13 at 09:41
  • @Joymon Not sure if it's good practice, but you can set the ContentType when you send the message: var message = new BrokeredMessage(request); message.ContentType = request.GetType().Name; – Dunc May 06 '15 at 18:34
  • It's possible simplify with this: var bodyType = System.Type.GetType("System.String"); – Fernando JS Jan 16 '18 at 18:51
6

In sample before ContentType utilized to detect body type. I believe ContentType should be set by sender. I do similar logic, I set one of message properties to type of object on sender side and call GetBody<>() on receiver with type retrived from message property. like this:

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);
    }

Message property "messageType" has full name of type.

On receiving side I do like this:

 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();
                    }
                }
Vitaliy Markitanov
  • 2,205
  • 1
  • 24
  • 23