在Azure Logic App中反序列化ServiceBus内容

时间:2018-05-07 22:07:09

标签: c# json servicebus azure-logic-apps

我正在尝试在Azure Logic App中阅读邮件的内容正文,但我没有取得多大成功。我看到很多建议说主体是base64编码的,建议使用以下代码进行解码:

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

base64ToString(...)部分正在将内容正确解码为字符串,但字符串似乎包含一个前缀,其中包含一些额外的序列化信息:

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

该字符串中还有一些额外字符未在我的浏览器中显示。因此json(...)函数不接受输入,而是给出错误。

  

InvalidTemplate。无法处理模板语言表达式   动作'HTTP'输入第'1行'和第'2451行:''模板   语言函数'json'参数无效。提供的价值   @string3http://schemas.microsoft.com/2003/10/Serialization/�3{"Foo":"bar" }       无法解析:Unexpected character encountered while parsing value: @. Path '', line 0, position 0.。有关使用详情,请参阅https://aka.ms/logicexpressions#json。'。

作为参考,使用.NET服务总线客户端将消息添加到主题中(客户端应该无关紧要,但这看起来更像C#-ish):

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

如何在我的Logic App中正确读取这个JSON对象?

3 个答案:

答案 0 :(得分:3)

您可以将substring函数与indexOflastIndexOf一起使用,仅获取JSON子字符串。

不幸的是,它相当复杂,但看起来应该是这样的:

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

有关如何使用这些功能的更多信息here

HTH

答案 1 :(得分:3)

由消息放置在ServiceBus上的方式引起,特别是在C#代码中。我使用以下代码添加新消息:

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

这段代码看起来很好,并且在不同的C#服务之间工作没问题。问题是由BrokeredMessage(Object)构造函数序列化给它的有效负载的方式引起的:

  

使用带有二进制XmlDictionaryWriter的DataContractSerializer,从给定对象初始化BrokeredMessage类的新实例。

这意味着内容被序列化为二进制XML,它解释了前缀和无法识别的字符。在反序列化时,C#实现会隐藏它,并返回您期望的对象,但在使用不同的库(例如Azure Logic Apps使用的库)时会变得明显。

有两种方法可以解决这个问题:

  • 确保接收方可以处理二进制XML格式的消息
  • 确保发件人实际使用我们想要的格式,例如JSON。

Paco de la Cruz的回答使用substringindexOflastIndexOf处理第一个案例:

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

至于第二种情况,在源处修复问题只需使用BrokeredMessage(Stream)构造函数。这样,我们可以直接控制内容:

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

答案 2 :(得分:0)

Paco de la Cruz解决方案为我工作,尽管我必须将表达式中的最后一个'}'换成'{',否则它将找到数据段的错误结尾。

我还将其分为两个步骤,以使其更易于管理。

首先,我使用以下命令将消息中的解码字符串转换为变量(我称为MC):

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

然后在另一个逻辑应用程序操作中执行子字符串提取:

@{substring(variables('MC'),indexof(variables('MC'),'{'),add(1,sub(lastindexof(variables('MC'),'}'),indexof(variables('MC'),'{'))))}

请注意,最后一个字符串文字'{'与Paco的解决方案相反。

这适用于我的测试用例,但是我不确定它的健壮性。

此外,我将其保留为字符串,稍后在逻辑应用程序中将其转换为JSON。