4

我有一个 API JSON 响应,它将数据内容包装在一个data属性中,如下所示:

{ 
   "data":{ 
      "email":"admin@example.com",
      "mobile":"+1555555123",
      "id":4,
      "first_name":"Merchant",
      "last_name":"Vendor",
      "role":"Merchant",
   }
}

因此,当使用类似的库请求用户对象时,用户RequestSharpresponse.Content内容包含在datajson 属性中,因为它来自 API。代码:

var request = RequestHelper.CreateTokenRequest(email, password); // Create the request from a helper
var client = new RestClient(BaseUrl); // create new RestSharp Client
IRestResponse response = client.Execute(request); // execute the request
var content = response.Content; // raw content as string

这很好,但是当我将 json 反序列化为 Object 时System.Text.Json,如下所示,将创建该User对象但不会分配任何属性,尽管这是意料之中的,因为序列化程序正在寻找带有first_nameand的属性last_name。 .. 不是['data']['first_name']

User account = JsonSerializer.Deserialize<User>(response.Content, options);

我怎样才能JsonSerializer.Deserialize忽略data包装器?在其他 API 调用中,它可能是 Object 的名称,例如transactionor user,无论哪种方式,它都会包装数据。

其他注意事项:

我的目标是最新的 .Net Core 3.1,并且正在从 Newtonsoft Json.Net 迁移


我的用户对象:

using System.ComponentModel;
using System.Text.Json.Serialization;

namespace MyApplication.Models
{
    public interface IUser
    {
        string FirstName { get; set; }
        string LastName { get; set; }
        string Email { get; set; }
        string Mobile { get; set; }
        string Id { get; set; }
        string Role { get; set; }
    }

    public class User : IUser
    {
        [JsonPropertyName("first_name")]
        public string FirstName { get; set; }

        [JsonPropertyName("last_name")]
        public string LastName { get; set; }

        [JsonPropertyName("email")]
        public string Email { get; set; }

        [JsonPropertyName("mobile")]
        public string Mobile { get; set; }

        [JsonPropertyName("id")]
        public string Id { get; set; }

        [JsonPropertyName("role")]
        public string Role { get; set; }

        [JsonIgnore]
        public string Token { get; set; }
    }
}


解决后更新:

我从下面的 u/Nikunj Kakadiya 中选择了答案,作为可行的方法,并且与我最终做的最相似。

我创建了一个基于通用模板的容器类来处理data这样的问题:

public class Container<T>
{
    [JsonPropertyName("data")]
    public T Data { get; set; }
}

然后我使用该容器类来包装从 API 调用返回的 json 内容,如下所示:

var options = new JsonSerializerOptions
{
    AllowTrailingCommas = true
};

Container<User> accountContainer = JsonSerializer.Deserialize<Container<User>>(response.Content, options);
User account = accountContainer.Data;

此外,正如 u/Pavel Anikhouski 所指出的,我对User类的序列化导致了一个错误,需要我为该id字段创建一个自定义转换器。APIid以整数形式返回,尽管它是User类中的字符串。这是我遇到的最初令人困惑的错误,但我很快就弄清楚了:ERROR: The JSON value could not be converted to System.String. Path: $.data.id | LineNumber: 0 | BytePositionInLine: 77.

这是自定义转换器IntToStringConverter

public class IntToStringConverter : JsonConverter<string>
{
    public override string Read(
        ref Utf8JsonReader reader,
        Type typeToConvert,
        JsonSerializerOptions options) => reader.GetInt32().ToString();

    public override void Write(
        Utf8JsonWriter writer,
        string value,
        JsonSerializerOptions options) =>
        writer.WriteStringValue(value);
}

然后更改User类以使用客户转换器:

...
    [JsonPropertyName("id")]
    [JsonConverter(typeof(IntToStringConverter))]
    public string Id { get; set; }
...
4

4 回答 4

5

你需要另开一堂课。下面给出

Public class UserData
{
    public User data { get; set; }; 
}

现在您可以使用名为 UserData 的新类反序列化数据,如下所示

UserData account = JsonSerializer.Deserialize<UserData>(response.Content, options);
于 2020-01-02T19:14:17.207 回答
1

可以User使用 API 获取对象,而无需从 JSON 示例System.Text.Json中指定属性名称data

{ 
   "data":{ 
      "email":"admin@example.com",
      "mobile":"+1555555123",
      "id":4,
      "first_name":"Merchant",
      "last_name":"Vendor",
      "role":"Merchant",
   }
}

通过以下代码

var document = JsonDocument.Parse(json, new JsonDocumentOptions { AllowTrailingCommas = true });
var enumerator = document.RootElement.EnumerateObject();
if (enumerator.MoveNext())
{
    var userJson = enumerator.Current.Value.GetRawText();
    var user = JsonSerializer.Deserialize<User>(userJson,
        new JsonSerializerOptions {AllowTrailingCommas = true});
}

在上面的示例中,JsonDocument已加载,RootElement然后枚举第一个嵌套对象作为文本以反序列化为User实例。

根据您的问题,按名称获取属性更容易document.RootElement.GetProperty("data");,但名称实际上可能不同。通过indexer访问, likedocument.RootElement[0]也是不可能的,因为它仅在ValueKind元素的情况下才有效Array,而不是Object, 在您的情况下

我也将 更改"id":4,"id":"4",,因为出现错误

无法将令牌类型“数字”的值作为字符串获取。

于 2020-01-02T19:41:23.980 回答
0

你可以像这样创建一个对象:

  public class Data
   {
    public string email { get; set; }
    public string mobile { get; set; }
    public int id { get; set; }
    public string first_name { get; set; }
    public string last_name { get; set; }
    public string role { get; set; }
    }

   public class RootObject
   {
    public Data data { get; set; }
   }

然后

var data = JsonSerializer.Deserialize<RootObject>(JsonData);

然后您可以访问如下数据:

RootObject.Data.email ;
RootObject.Data.first_name

此外,任何时候您需要将 JSON 字符串转换为 C# POCO 类,您都可以使用这样的工具:http: //json2csharp.com/

于 2020-01-02T19:14:21.083 回答
-1

要么摆脱数据对象,要么编写自定义 json 转换器。我建议更改发送的数据或直接使用它,因为您尝试做的不是最佳实践。

于 2020-01-02T19:19:01.277 回答