【问题标题】:Deserializing ServiceBus content in Azure Logic App在 Azure 逻辑应用中反序列化 ServiceBus 内容
【发布时间】:2018-05-07 22:07:09
【问题描述】:

我正在尝试在 Azure 逻辑应用中读取消息的内容正文,但没有取得多大成功。我看到很多建议说body是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# json servicebus azure-logic-apps


【解决方案1】:

这是由消息在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 逻辑应用程序使用的库)时会变得很明显。

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

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

Paco de la Cruz 的回答处理第一种情况,使用 substring、indexOf 和 lastIndexOf:

@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】:

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

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

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

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

    HTH

    【讨论】:

      【解决方案3】:

      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"'))))}
      

      【讨论】:

        猜你喜欢
        • 2018-11-15
        • 1970-01-01
        • 2017-03-29
        • 1970-01-01
        • 1970-01-01
        • 2017-10-17
        • 2015-03-02
        • 2020-10-09
        • 2020-09-01
        相关资源
        最近更新 更多