Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserializing ServiceBus content in Azure Logic App

I'm trying to read the content body of a message in an Azure Logic App, but I'm not having much success. I have seen a lot of suggestions which say that the body is base64 encoded, and suggest using the following to decode:

@{json(base64ToString(triggerBody()?['ContentData']))}

The base64ToString(...) part is decoding the content into a string correctly, but the string appears to contain a prefix with some extra serialization information at the start:

@string3http://schemas.microsoft.com/2003/10/Serialization/�3{"Foo":"Bar"}

There are also some extra characters in that string that are not being displayed in my browser. So the json(...) function doesn't accept the input, and gives an error instead.

InvalidTemplate. Unable to process template language expressions in action 'HTTP' inputs at line '1' and column '2451': 'The template language function 'json' parameter is not valid. The provided value @string3http://schemas.microsoft.com/2003/10/Serialization/�3{"Foo":"bar" } cannot be parsed: Unexpected character encountered while parsing value: @. Path '', line 0, position 0.. Please see https://aka.ms/logicexpressions#json for usage details.'.

For reference, the messages are added to the topic using the .NET service bus client (the client shouldn't matter, but this looks rather C#-ish):

await TopicClient.SendAsync(new BrokeredMessage(JsonConvert.SerializeObject(item)));

How can I read this correctly as a JSON object in my Logic App?

like image 711
Andrew Williamson Avatar asked May 07 '18 22:05

Andrew Williamson


2 Answers

This is caused by how the message is placed on the ServiceBus, specifically in the C# code. I was using the following code to add a new message:

var json = JsonConvert.SerializeObject(item);
var message = new BrokeredMessage(json);
await TopicClient.SendAsync(message);

This code looks fine, and works between different C# services no problem. The problem is caused by the way the BrokeredMessage(Object) constructor serializes the payload given to it:

Initializes a new instance of the BrokeredMessage class from a given object by using DataContractSerializer with a binary XmlDictionaryWriter.

That means the content is serialized as binary XML, which explains the prefix and the unrecognizable characters. This is hidden by the C# implementation when deserializing, and it returns the object you were expecting, but it becomes apparent when using a different library (such as the one used by Azure Logic Apps).

There are two alternatives to handle this problem:

  • Make sure the receiver can handle messages in binary XML format
  • Make sure the sender actually uses the format we want, e.g. JSON.

Paco de la Cruz's answer handles the first case, using substring, indexOf and lastIndexOf:

@json(substring(base64ToString(triggerBody()?['ContentData']), indexof(base64ToString(triggerBody()?['ContentData']), '{'), add(1, sub(lastindexof(base64ToString(triggerBody()?['ContentData']), '}'), indexof(base64ToString(triggerBody()?['ContentData']), '}')))))

As for the second case, fixing the problem at the source simply involves using the BrokeredMessage(Stream) constructor instead. That way, we have direct control over the content:

var json = JsonConvert.SerializeObject(item);
var bytes = Encoding.UTF8.GetBytes(json);
var stream = new MemoryStream(bytes);
var message = new BrokeredMessage(stream, true);
await TopicClient.SendAsync(message);
like image 182
Andrew Williamson Avatar answered Nov 02 '22 19:11

Andrew Williamson


You can use the substring function together with indexOf and lastIndexOf to get only the JSON substring.

Unfortunately, it's rather complex, but it should look something like this:

@json(substring(base64ToString(triggerBody()?['ContentData']), indexof(base64ToString(triggerBody()?['ContentData']), '{'), add(1, sub(lastindexof(base64ToString(triggerBody()?['ContentData']), '}'), indexof(base64ToString(triggerBody()?['ContentData']), '}')))))

More info on how to use these functions here.

HTH

like image 35
Paco de la Cruz Avatar answered Nov 02 '22 19:11

Paco de la Cruz