C# 如何使用 System.Text.Json 反序列化 Json 数据

C# How deserialize Json data using System.Text.Json

再次向好社区问好。这次我需要一些帮助来反序列化一些来自 Web API 的数据,使用 System.Text.Json。在到处搜索之后,我没有找到任何可以真正帮助我解决这个问题的东西

这是数据示例:

对于 UF 指标:

{
    "UFs": [
        {
            "Valor": "30.008,40",
            "Fecha": "2021-09-10"
        }
    ]
}

对于美元指标:

{
    "Dolares": [
        {
            "Valor": "791,28",
            "Fecha": "2021-09-10"
        }
    ]
}

对于 UTM 指标:

{
"UTMs": [
        {
            "Valor": "52.631",
            "Fecha": "2021-09-01"
        }
    ]
}

以及多组数据的美元样本:

{
"Dolares": [
    {
        "Valor": "767,10",
        "Fecha": "2021-09-02"
    },
    {
        "Valor": "768,36",
        "Fecha": "2021-09-03"
    },
    {
        "Valor": "766,53",
        "Fecha": "2021-09-06"
    },
    {
        "Valor": "770,33",
        "Fecha": "2021-09-07"
    },
    {
        "Valor": "777,94",
        "Fecha": "2021-09-08"
    },
    {
        "Valor": "787,51",
        "Fecha": "2021-09-09"
    },
    {
        "Valor": "791,28",
        "Fecha": "2021-09-10"
    }
]
}

这是 class 我需要反序列化为:

public class Indicador : IIndicador
{
    public string Valor { get; set; }
    public string Fecha { get; set; }
}

当我尝试使用此反序列化时,问题开始了:

var dataFromApi = await httpResponse.Content.ReadAsStringAsync();
var indicador = JsonSerializer.Deserialize<Indicador>(dataFromApi);

我也尝试过使用这个“解决方案”,但一点运气都没有:

var dataFromApi = await httpResponse.Content.ReadAsStringAsync();
var indicador = JsonSerializer.Deserialize<Dictionary<string,List<indicador>>>(dataFromApi);

到目前为止,唯一的解决方案是创建一个“容器”class,它可以帮助我处理那些奇怪的“UF”列表,因为这个 WebAPI 可以 return 除“UF”之外的多个其他经济指标可以更改为许多其他概念,有没有办法将来自 WebAPI 的内容映射到我的通用 Indicador class?,这个想法是当只有 1 个数据时使用简单对象,当有多个数据时使用 IEnumerable。我需要停止对每种可用指标的依赖。

提前致谢!

问题/改进领域

你的最后一段有点含糊,你没有更多的例子。因此,答案可能不像您正在寻找的那样具体。

multiple other economics indicators than "UFs"

如果能看到一些其他示例会很高兴。

map what ever comes from the WebAPI to my generic Indicador class

有可能,但其他数据的结构还有待观察。

最简单的例子

我认为你错过了反序列化过程的这一部分

List<Indicador> indicadors = dataDict["UFs"]; // <-- Will fail If "UFs" is not present

下面是顶级 C# 程序,用于将给定数据反序列化为 List<Indicador>

using System;
using System.Text.Json;
using System.Collections.Generic;

// test data
string dataFromApi = @"{
    ""UFs"": [
        {
            ""Valor"": ""30.008,40"",
            ""Fecha"": ""2021-09-10""
        },
        {
            ""Valor"": ""40.008,50"",
            ""Fecha"": ""2021-10-10""
        }
    ]
}";

var dataDict = JsonSerializer.Deserialize<Dictionary<string, List<Indicador>>>(dataFromApi);
List<Indicador> indicadors = dataDict["UFs"]; // <-- Will fail If "UFs" is not present 

// print out the indicadors
indicadors.ForEach(indicador => Console.WriteLine(indicador));

// Using records because they are brief and come with a good default ToString() method
// You can use regular class if you require
public abstract record IIndicador(string Valor, string Fecha);
public record Indicador(string Valor, string Fecha): IIndicador(Valor, Fecha);

上面顶级C#程序的输出

Indicador { Valor = 30.008,40, Fecha = 2021-09-10 }
Indicador { Valor = 40.008,50, Fecha = 2021-10-10 }

如果不能保证“UFs”键,那么您可以使用一种字典方法来确定该键是否存在。例如

if (dataDict.ContainsKey("UFs")) ...

推测

在这里试图解决你最后一段的某些方面。 (您需要澄清这是否解决了您的所有顾虑并适应您的需求)System.Text.Json 也有 JsonConverterFactoryJsonConverter<T> 用于更高级的转换要求,如果您需要的话。

using System;
using System.Linq;
using System.Text.Json;
using System.Collections.Generic;

// test data
string multiDataFromApi = @"{
    ""UFs"": [
        {
            ""Valor"": ""30.008,40"",
            ""Fecha"": ""2021-09-10""
        },
        {
            ""Valor"": ""40.008,50"",
            ""Fecha"": ""2021-10-10""
        }
    ],
    ""UFOs"": [
        {
            ""Valor"": ""30.008,40"",
            ""Fecha"": ""2021-09-10""
        }
    ]
}";

string singleDataFromApi = @"{
    ""UFs"": [
        {
            ""Valor"": ""30.008,40"",
            ""Fecha"": ""2021-09-10""
        },
        {
            ""Valor"": ""40.008,50"",
            ""Fecha"": ""2021-10-10""
        }
    ]
}";

processDataFromApi(multiDataFromApi);
processDataFromApi(singleDataFromApi);

void processDataFromApi(string json)
{
    var dataDict = JsonSerializer.Deserialize<Dictionary<string, List<Indicador>>>(json);

    if (dataDict.Count == 1)
    {
        Console.WriteLine("-- Single Key Processing --");
        List<Indicador> indicadors = dataDict.Values.First();
        indicadors.ForEach(indicador => Console.WriteLine("\t{0}", indicador));
    }
    else
    {
        Console.WriteLine("-- Multi Key Processing --");
        foreach (var keyValuePair in dataDict)
        {
            Console.WriteLine($"Processing Key: {keyValuePair.Key}");
            List<Indicador> indicadors = keyValuePair.Value;
            indicadors.ForEach(indicador => Console.WriteLine("\t{0}",indicador));
        }
    }
    Console.WriteLine("-----------------------------");
}

// Using records because they are brief and come with a good default ToString() method
// You can use regular class if you require
public abstract record IIndicador(string Valor, string Fecha);
public record Indicador(string Valor, string Fecha): IIndicador(Valor, Fecha);

这将产生以下输出

-- Multi Key Processing --
Processing Key: UFs
        Indicador { Valor = 30.008,40, Fecha = 2021-09-10 }
        Indicador { Valor = 40.008,50, Fecha = 2021-10-10 }
Processing Key: UFOs
        Indicador { Valor = 30.008,40, Fecha = 2021-09-10 }
-----------------------------
-- Single Key Processing --
        Indicador { Valor = 30.008,40, Fecha = 2021-09-10 }
        Indicador { Valor = 40.008,50, Fecha = 2021-10-10 }
-----------------------------