【问题标题】:Deserialize JSON and assign to model反序列化 JSON 并分配给模型
【发布时间】:2020-02-25 14:43:05
【问题描述】:

作为我的 web api 的一部分,我得到了以下 JSON 返回。

["{\"InputType\":17,\"EngineSubType\":4,\"Filename\":\"targetFile.csv\",\"FileExtensionType\":\".csv\",\"IsLoadFile\":true,\"LoadContextId\":4121,\"ReportingDate\":\"2019-05-31T00:00:00\",\"IsSuccess\":false}"]

我想要做的是获取Filename 旁边的值并将其分配给我的模型Filename 参数。

在我的项目中,我创建了一个单元测试来尝试获取该值,但我所做的每次尝试都失败了。

在我的测试中,我有以下 DTO 模型:

public class HangfireTestDTO
{
    public string InputType { get; set; }
    public string Filename { get; set; }
}

那我的文字逻辑是这样的:

[Fact]
public void TestDTO()
{
    string data =
          "[\"{\\\"InputType\\\":12,\\\"EngineSubType\\\":2,\\\"Filename\\\":\\\"targetFile.csv\\\",\\\"FileExtensionType\\\":\\\".csv\\\",\\\"IsLoadFile\\\":true,\\\"LoadContextId\\\":4120,\\\"ReportingDate\\\":\\\"2019-05-31T00:00:00\\\",\\\"IsSuccess\\\":false}\"]";

     // fails here
     var arguments = System.Text.Json.JsonSerializer.Deserialize<HangfireTestDTO>(data);

     // This is wrong - ignore for now
     Assert.Equal("targetFile.csv", arguments.ToString());

}

当我在测试中调试上述内容时,它会告诉我以下信息:

无法将 JSON 值转换为 MyProject.HangfireTestDTO

然后我的想法导致我通过将反序列化行修改为以下内容再次尝试:

 var arguments = System.Text.Json.JsonSerializer.Deserialize<IEnumerable<HangfireTestDTO>>(data).FirstOrDefault();

但是当使用新行运行它时,我收到以下错误:

无法将 JSON 值转换为 System.Collections.Generic.List

我做错了什么?

【问题讨论】:

  • 看起来像 JSON 中的 JSON。尝试解析字符串列表,并单独解析这些字符串。
  • 无论生成什么 JSON,都应该尽快重组。嵌套的 JSON 基本上总是代码设计不佳的标志,并且总是在未来出现潜在的麻烦。
  • @FranzGleichmann 那是吊火。零控制
  • 您接受了一个不适用于您在问题中提出的 JSON 的答案 - 这是否意味着您的 JSON 实际上不是那样的?
  • @N0xus 然后告诉负责修复他们的代码的人,在他们修复之前不要停止告诉他们

标签: c# json deserialization json-deserialization


【解决方案1】:

您当前的 JSON 字符串是一个字符串数组。您需要首先将 JSON 反序列化为字符串列表,然后将每个字符串反序列化为 DTO。这是一个使用 JSON 的完整示例:

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

public class HangfireTestDTO
{
    public int InputType { get; set; }
    public int EngineSubType { get; set; }
    public string Filename { get; set; }
    public string FileExtensionType { get; set; }
}

class Program
{
    static void Main()
    {
        string data =
          "[\"{\\\"InputType\\\":12,\\\"EngineSubType\\\":2,\\\"Filename\\\":\\\"targetFile.csv\\\",\\\"FileExtensionType\\\":\\\".csv\\\",\\\"IsLoadFile\\\":true,\\\"LoadContextId\\\":4120,\\\"ReportingDate\\\":\\\"2019-05-31T00:00:00\\\",\\\"IsSuccess\\\":false}\"]";

        // First deserialize the single string to a list of strings
        List<string> jsonStrings = JsonSerializer.Deserialize<List<string>>(data);

        // Then deserialize each of the strings to a DTO.
        List<HangfireTestDTO> dtos = jsonStrings
            .Select(json => JsonSerializer.Deserialize<HangfireTestDTO>(json))
            .ToList();
        Console.WriteLine(dtos.Count);
        Console.WriteLine(dtos[0].Filename);
    }
}

【讨论】:

  • 看来,OP 使用的是System.Text.Json,而不是Newtonsoft.Json
  • @PavelAnikhouski:啊,会解决的。不过,它可能是几乎相同的代码。
  • @PavelAnikhouski:完成:)
【解决方案2】:

首先你的 JSON 是错误的 我希望它看起来更像

string data = @"[{""InputType"":12,""EngineSubType"":2,""Filename"":""targetFile.csv"",""FileExtensionType"":"".csv"",""IsLoadFile"":true,""LoadContextId"":4120,""ReportingDate"":""2019-05-31T00:00:00"",""IsSuccess"":false}]"

string data = "[{\"InputType\":17,\"EngineSubType\":4,\"Filename\":\"targetFile.csv\",\"FileExtensionType\":\".csv\",\"IsLoadFile\":true,\"LoadContextId\":4121,\"ReportingDate\":\"2019-05-31T00:00:00\",\"IsSuccess\":false}]"

第二次你将 JSON 包装在 [] 中,这意味着一个文档列表,因此 Deserialize&lt;HangfireTestDTO&gt;(data); 将是 Deserialize&lt;List&lt;HangfireTestDTO&gt;&gt;(data); 或其他一些 IEnumerable

那么你有多个数据不匹配 12 是一个数字而不是一个字符串,所以 InputType 应该是一个 int 或 double,IsSuccess 是一个 bool,等等

最后,您的 JSON 中有很多字段不在您的对象上,您需要向 c# 解释如何处理它们,要么创建额外的属性,要么提供可以将它们放入的 KeyValue 存储 即

[JsonExtensionData]
public Dictionary<string, object> ExtensionData { get; set; }

根据您所做的评论进行编辑,如果这确实是数据从您的数据库中出来的方式,那么它是一个字符串数组,其中字符串是 JSON 编码的

在这种情况下,您需要读取字符串,然后解析它们

var jsonlist = JsonSerializer.Deserialize<List<string>>(data);
foreach(string json in jsonlist )
    var dto = JsonSerializer.Deserialize<HangfireTestDTO>(json);

【讨论】:

  • JSON 直接取自我的hangfire 数据库。当您将作业排入队列时,这就是它生成的内容。对此进行零控制。
  • 不,当您为测试创建数据变量时,您已经更改了它,一件事有很多额外的 \'s
【解决方案3】:

第一个错误是因为InputType。应该是int

public class HangfireTestDTO
{
    public int InputType { get; set; }
    public string Filename { get; set; }
}

第二个错误是因为JSON。在[{ 之间有一个附加引号。我已经尝试过JSON,它成功了。因为这个引用,它变成了List&lt;string&gt;而不是List&lt;HangfireTestDTO&gt;

[
    {
        "InputType": 12,
        "EngineSubType": 2,
        "Filename": "targetFile.csv",
        "FileExtensionType": ".csv",
        "IsLoadFile": true,
        "LoadContextId": 4120,
        "ReportingDate": "2019-05-31T00:00:00",
        "IsSuccess": false
    }
]

看看JSON应该是IEnumerable&lt;HangfireTestDTO&gt;

var arguments = JsonSerializer.Deserialize<IEnumerable<HangfireTestDTO>>(data);

【讨论】:

  • 谢谢你,但它会产生我上面提到的同样的错误The JSON value could not be converted to System.Collections.Generic.List1`
  • @N0xus,很遗憾您的 json 格式不正确。有一个额外的引用导致问题[\"{
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-06
  • 2017-04-13
  • 2020-10-23
  • 1970-01-01
  • 2020-06-29
相关资源
最近更新 更多