如何将 ReadAsAsync 与此数据架构一起使用

本文关键字:数据 一起 ReadAsAsync | 更新日期: 2023-09-27 18:33:08

我正在使用System.Net.Http.HttpClient,NuGet中当前可用的版本,以 JSON 格式从服务中检索数据。数据大致如下所示:

{
  "schema": "Listing",
  "data": {
    "key": "28ba648c-de24-45d4-a7d9-70f810cf5438",
    "children": [{
      "kind": "type1",
      "data": {
        "body": "Four score and seven years ago...",
        "parent_id": "2qh3l",
        "report_count": 0,
        "name": "c4j6yeh"
      }
    }, {
      "kind": "type3",
      "data": {
        "domain": "abc.def.com",
        "flagged": true,
        "category": "news",
        "saved": false,
        "id": "t3dz0",
        "created": 1335998011.0
        }
    }]
  }
}

我使用 HttpContentExtensions.ReadAsAsync<T> 将该 json 字符串反序列化为对象图。 类型定义大致如下所示:

public class Response
{
    public String schema { get;set; }
    public ListingData data { get;set; }
}
public class ListingData
{
    public string key { get;set; }
    public List<OneItem> children { get;set; }
}

问题是:我希望children中的项目类型根据kind属性而有所不同。 如果kind是"type1",那么我想反序列化一个对象...让我们称之为Type1. 如果kind是"type3",那么我想要一个类型为 Type3 的对象。

现在,我可以反序列化List<Type1>List<Type3>,但我不知道如何告诉反序列化逻辑来区分两者。

我可以将"type1"数据对象和"type3"数据对象的所有属性合并到单个 .NET 类型中。 但是属性的数量足够大,以至于这变得混乱。

如果 JSON 中的属性名称(在本例中为 data(不同,我可以使用它进行区分。 例如,如果数据如下所示:

    "children": [{
      "kind": "type1",
      "t1data": { ... }
    }, {
      "kind": "type3",
      "t3data": { ... }
    }]

。然后我可以在 .NET 中做这样的事情:

public class OneItem
{
    public string kind { get;set; }
    public Type1 t1data { get;set; }
    public Type3 t3data { get;set; }
}

但我的数据架构看起来不像那样。

是否可以根据数据内容选择反序列化的类型? 换句话说,查看一个属性的值(在本例中为 kind (,以确定如何反序列化另一个属性(在本例中为 data (的内容。

或者是否可以在 ReadAsAsync 尝试反序列化之前注入作用于 JSON 的筛选器或转换器?

如果是这样,如何?

如何将 ReadAsAsync<T> 与此数据架构一起使用

如果你对你的响应进行一些预处理并且你可以使用 Json.NET,你应该能够做你想做的事。

给定以下类:

public class Response
{
    public string schema
    {
        get;
        set;
    }
    public ListingData data
    {
        get;
        set;
    }
}
public class ListingData
{
    public string key
    {
        get;
        set;
    }
    public List<object> children
    {
        get;
        set;
    }
}
public class Type1
{
    public string body
    {
        get;
        set;
    }
    public string parent_id
    {
        get;
        set;
    }
    public int report_count
    {
        get;
        set;
    }
    public string name
    {
        get;
        set;
    }
}
public class Type3
{
    public string domain
    {
        get;
        set;
    }
    public bool flagged
    {
        get;
        set;
    }
    public string category
    {
        get;
        set;
    }
    public bool saved
    {
        get;
        set;
    }
    public string id
    {
        get;
        set;
    }
    public double created
    {
        get;
        set;
    }
}

此测试通过:

[Test]
public void RoundTrip()
{
    var response = new Response
                        {
                            schema = "Listing",
                            data = new ListingData
                                        {
                                            key = "28ba648c-de24-45d4-a7d9-70f810cf5438",
                                            children = new List<object>
                                                            {
                                                                new Type1
                                                                    {
                                                                        body = "Four score and seven years ago...",
                                                                        parent_id = "2qh3l",
                                                                        report_count = 0,
                                                                        name = "c4j6yeh"
                                                                    },
                                                                new Type3
                                                                    {
                                                                        domain = "abc.def.com",
                                                                        flagged = true,
                                                                        category = "news",
                                                                        saved = false,
                                                                        id = "t3dz0",
                                                                        created = 1335998011.0
                                                                    }
                                                            }
                                        }
                        };
    var jsonSerializerSettings = new JsonSerializerSettings
                                        {
                                            Formatting = Formatting.Indented,
                                            TypeNameHandling = TypeNameHandling.Objects
                                        };
    string serializedResponse = JsonConvert.SerializeObject(response, jsonSerializerSettings);
    Console.WriteLine(serializedResponse);
    var roundTrippedResponse = JsonConvert.DeserializeObject<Response>(serializedResponse, jsonSerializerSettings);
    Assert.That(roundTrippedResponse.data.children.First().GetType(), Is.EqualTo(typeof(Type1)));
    Assert.That(roundTrippedResponse.data.children.Last().GetType(), Is.EqualTo(typeof(Type3)));
}

写入控制台的输出为:

{
  "$type": "Test.Response, Test",
  "schema": "Listing",
  "data": {
    "$type": "Test.ListingData, Test",
    "key": "28ba648c-de24-45d4-a7d9-70f810cf5438",
    "children": [
      {
        "$type": "Test.Type1, Test",
        "body": "Four score and seven years ago...",
        "parent_id": "2qh3l",
        "report_count": 0,
        "name": "c4j6yeh"
      },
      {
        "$type": "Test.Type3, Test",
        "domain": "abc.def.com",
        "flagged": true,
        "category": "news",
        "saved": false,
        "id": "t3dz0",
        "created": 1335998011.0
      }
    ]
  }
}

因此,如果可以转换收到的响应以匹配 Json.NET 的预期格式,这将起作用。

要将所有这些拼凑在一起,您需要编写一个自定义的 MediaTypeFormatter 并将其传递给 ReadAsAsync<>(( 调用。