将来自服务总线队列触发器的 JSON 消息反序列化为 C# 对象

Deserialize JSON message from Service Bus Queue Trigger to C# Object

我有一个如下所示的 Azure 函数:

public class SaveProductDataToDatabase
{
    private readonly IProductRepository _productRepository;

    public SaveProductDataToDatabase(IProductRepository productRepository)
    {
        _productRepository = productRepository;
    }

    [FunctionName("SaveProductDataToDatabase")]
    public void Run([ServiceBusTrigger("product-data-dev-01", Connection = "ServiceBusConnectionString")] string myQueueItem, ILogger log)
    {
        log.LogInformation($"Processed message: {myQueueItem}");
            
        // TODO : JSON Mapping will be added here once Service Bus Queue is Up and Running.
        _productRepository.Add(new Domain.Entities.Product());
    }
}

这里,myQueueItem会return一个复杂的嵌套JSON字符串

{
  "metadata": {
    "origin": "xyz-data",
    "dateCreated": "2022-03-17T12:48:04.511Z"
  },
  "version": 6,
  "messageId": "a44f23aa-bab4-4eed-a235-5820d966f669",
  "sWrapper": {
    "sid": "zzavqw18",
    "identifiers": [
      {
        "alias": "si-sku",
        "value": [
          "8086300"
        ]
      }
    ]
  },
  "itemType": "ITEM",
  "master": {
    "masterSource": "XYZ_PDS",
    "title": {
      "mainTitle": "XYZ - All Time Greats"
    },
    "description": {
      "longDescription": "XYZ - All Time Greats",
      "shortDescription": "XZY - All Time Greats"
    },
    "classification": {
      "identifier": "1pvfy"
    }
  }
}

在此,我想提取 sWrapper.sidsWrapper.identifiers.valueclassification.identifier 属性并将其分配给纯 C# 对象。该对象将传递给 _productRepository.Add(<C# object goes here>);

如何处理这个映射?什么是最好的方法?请指教

有多种方法。 选项 1 - 使用 class 反序列化并使用 class 属性使用 Newtonsoft.Json

JsonConvert.DeserializeObject<CLASS>(JSON_STRING)

选项 2 使用 System.Text.Json.Nodes 直接访问节点

var jn = JsonNode.Parse(j)["sWrapper"].Dump("node");
jn["sid"].GetValue<string>().Dump("Value of SID");

P.S> 同样,有可能的方法... 然后创建一个新的 class 并使用值填充 class 属性并将对象传递给函数。

这是使用 Cinchoo ETL 从 JSON 中选择节点的另一种方法 - 一个开源库

定义 POCO class 属性以及 JSON 路径

public class QueueItem
{
    [ChoJSONPath("sWrapper.sid")]
    public string SID { get; set; }
    [ChoJSONPath("sWrapper.identifiers[0].value[0]")]
    public string IdentifierValue { get; set; }
    [ChoJSONPath("master.classification.identifier")]
    public string ClassificationIdentifier { get; set; }
}

然后使用库反序列化JSON如下

using (var r = ChoJSONReader<QueueItem>.LoadText(json))
{
    r.Print();
}

样本fiddle:https://dotnetfiddle.net/K7GnT8

正如其他人所提到的,您可以创建一个 class/classes 来表示您希望从服务总线消息中获取的信息。

public class ServiceBusMessage
{
    [JsonPropertyName("sWrapper")]
    public SWrapper SWrapper { get; set; }

    [JsonPropertyName("classification")]
    public Classification Classification { get; set; }
}

public class SWrapper
{
    [JsonPropertyName("sid")]
    public string Sid { get; set; }

    [JsonPropertyName("identifiers")]
    public SWrapperIdentifier[] Identifiers { get; set; }
}

public class SWrapperIdentifier
{
    [JsonPropertyName("value")]
    public string[] Value { get; set; }
}

public class Classification
{
    [JsonPropertyName("identifier")]
    public string Identifier { get; set; }
}

此外,如果您的 Azure Function 是 2.0 或更高版本,您可以将函数签名更改为:

public void Run([ServiceBusTrigger("product-data-dev-01", Connection = "ServiceBusConnectionString")] ServiceBusMessage myQueueItem, ILogger log)

框架将为您处理反序列化(根据 these 文档)。

然后您可以将这个“请求”对象映射到任何您想要使用的结构。