在 Azure 逻辑应用中反序列化服务总线内容



我正在尝试读取 Azure 逻辑应用中消息的内容正文,但没有取得多大成功。我看到很多建议说正文是base64编码的,并建议使用以下方法进行解码:

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

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

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

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

无效模板。无法在 中处理模板语言表达式 操作"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)));

如何在逻辑应用中将其作为 JSON 对象正确读取?

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

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

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

通过使用具有

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

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

有两种替代方法可以解决此问题:

  • 确保接收方可以处理二进制 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);

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

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

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

有关如何使用这些函数的详细信息,请参阅此处。

呵呵

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。

更新

我们发现,偶尔(几百次运行中的两次(我们要丢弃的文本可以包含"{"字符。 我修改了我们的表达式以明确定位数据段的开头,对我来说是:

'{"IntegrationRequest"'

所以替换变成:

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

相关内容

  • 没有找到相关文章

最新更新