HttpClient ObjectContent JSON: 在 json 对象中使用根 class 名称的格式?

HttpClient ObjectContent JSON: format with root class name in json object?

我使用 json2csharp.com 为 json 源生成一个 C# class。我的 json 是:

        {
  "email_verified": true,
  "user_id": "gg2323",
  "app_metadata": {
    "tc_app_user": {
      "user_guid": "c0fb150f6er344df98ea3a06114e1e4a",
      "cto_admin_a_user_id": "551294d4f6cfb46e65a5aq71",
      "lang": "EN",
      "country": "USA",
      "disabled": false
  }

我生成的 C# 是:

public class TcAppUser
{
    public string user_guid { get; set; }
    public string cto_admin_a_user_id { get; set; }
    public string lang { get; set; }
    public string country { get; set; }
    public bool disabled { get; set; }
}

public class AppMetadata
{
    public TcAppUser tc_app_user { get; set; }
    public int logins_count { get; set; }
}

public class RootObject
{
    public bool email_verified { get; set; }
    public string user_id { get; set; }
    public AppMetadata app_metadata { get; set; }
}

使用 .NET HttpClient GET,我可以很好地从 JSON API 读入此 C# 结构。走另一条路 (POST, PATCH) 会带来一个问题:当我使用如下常用方法时,我的 app_metadata 属性 名称在生成的 JSON 输出中被删除:

    //Would be nice: var contentIn = new ObjectContent<string>(RootObjectInstance.app_metadata, new JsonMediaTypeFormatter());  
string json = JsonConvert.SerializeObject(RootObjectInstance.app_metadata);         
HttpResponseMessage response = await hclient.PatchAsync("api/users/" + user_id, new StringContent(json, Encoding.UTF8, "application/json"));

结果 JSON 现在是:

    {
    "tc_app_user": {
      "lang": "en-en",
      "country": "GER",
      "disabled": false
    }
}

我的快速技巧是使用以下附加包装器动态重新打包 app_metadata 属性,使其输出格式与输入格式相同。其余部分与上面相同:

dynamic wireFormatFix = new ExpandoObject();
                wireFormatFix.app_metadata = usr.app_metadata;
                string json = JsonConvert.SerializeObject(wireFormatFix);

现在我的 JSON 输出对应于 JSON 输入。 我的问题:实现对称 json 输入和输出的最佳实践是什么,而无需讨厌的格式修复?

编辑:如果我尝试修补整个结构(RootObjectInstance 而不是 RootObjecInstance.app_metadata),我得到:

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Payload validation error: 'Additional properties not allowed: 'user_id'."
}

因此,我必须发送正确打包的 C# RootObject 的 app_metadata subset/property,或者我必须有选择地从 RootObject 中删除字段以满足 API 的要求.

谢谢!

正在从您的 JSON 中删除根 app_metadata 标记,因为您根本没有对其进行序列化。这个:

string json = JsonConvert.SerializeObject(RootObjectInstance.app_metadata);

将序列化里面的所有东西 app_metadata.

如果序列化整个对象图,则不需要修补任何内容:

string json = JsonConvert.SerializeObject(RootObjectInstance);

作为旁注,您应该遵循 C# naming conventions。您可以使用 JsonProperty 来帮助您。

编辑:

好的,在你的编辑之后我看到了实际的问题。您在查询字符串中通过 user_id 调用了 API,并且您的对象内部也有一个 user_id 属性。这似乎需要两个不同的对象来完成这项工作。

您有两种可能性:

  1. 创建对象层次结构:

    public class BaseObject
    {
        [JsonProperty(email_verified)]
        public bool EmailVerified { get; set; }
        [JsonProperty(app_metadata)]
        public AppMetadata AppMetadata { get; set; }
    }
    
    public class ExtendedObject : BaseObject
    {
       [JsonProperty(user_id)]
       public string UserId { get; set; }
    }
    

然后使用基本类型序列化数据:

var baseObj = new BaseObject(); // Fill the object properties.
var json = JsonConvert.SerializeObject(intermidiateObj);
HttpResponseMessage response = await hclient.PatchAsync("api/users/" + 
                                                        user_id, 
                                                        new StringContent(json,
                                                        Encoding.UTF8,
                                                        "application/json"));
  1. 使用仅包含您实际需要的属性的匿名对象:

    var intermidiateObj = new { app_metadata = usr.app_metadata };
    var json = JsonConvert.SerializeObject(intermidiateObj);
    HttpResponseMessage response = await hclient.PatchAsync("api/users/" + 
                                                        user_id, 
                                                        new StringContent(json,
                                                        Encoding.UTF8,
                                                        "application/json"));