繁体   English   中英

反序列化 JSON,嵌套对象属性位于父对象中。 C#

[英]Deserializing JSON, nested object properties to be in parent object. C#

我有以下 JSON,我正在编写对象模型以反序列化:

{
  "company_webhooks": [
    {
      "company_webhook": {
        "id": 42,
        "url": "https://keeptruckin.com/callbacktest/842b02",
        "secret": "fe8b75de0a4e5898f0011faeb8c93654",
        "format": "json",
        "actions": [
          "vehicle_location_received",
          "vehicle_location_updated"
        ],
        "enabled": false
      }
    },
    {
      "company_webhook": {
        "id": 43,
        "url": "https://keeptruckin.com/callbacktest/a6a783",
        "secret": "66a7368063cb21887f546c7af91be59c",
        "format": "json",
        "actions": [
          "vehicle_location_received",
          "vehicle_location_updated"
        ],
        "enabled": false
      }
    },
    {
      "company_webhook": {
        "id": 44,
        "url": "https://keeptruckin.com/callbacktest/53a52c",
        "secret": "4451dc96513b3a67107466dd2c4d9589",
        "format": "json",
        "actions": [
          "vehicle_location_received",
          "vehicle_location_updated"
        ],
        "enabled": false
      }
    },
    {
      "company_webhook": {
        "id": 45,
        "url": "https://keeptruckin.com/callbacktest/6fb337",
        "secret": "4177fbd88c30faaee03a4362648bd663",
        "format": "json",
        "actions": [
          "vehicle_location_received",
          "vehicle_location_updated"
        ],
        "enabled": false
      }
    },
    {
      "company_webhook": {
        "id": 46,
        "url": "https://keeptruckin.com/callbacktest/8cd6da",
        "secret": "6e41817a048b009435e5102fca17db55",
        "format": "json",
        "actions": [
          "vehicle_location_received",
          "vehicle_location_updated"
        ],
        "enabled": false
      }
    }
  ],
  "pagination": {
    "per_page": 25,
    "page_no": 1,
    "total": 5
  }
}

这是我所拥有的:

[DataContract]
public class KeepTruckinResponse
{
    [DataMember(Name = "company_webhooks", EmitDefaultValue = false)]
    public KeepTruckinCompanyWebHook[] WebHooks { get; set; }

    [DataMember(Name = "pagination", EmitDefaultValue = false)]
    public KeepTruckinPagination Pagination { get; set; }

    public string RawJSON { get; set; }
}

[DataContract]
public class KeepTruckinPagination
{
    [DataMember(Name = "per_page", EmitDefaultValue = false)]
    public int PerPage { get; set; }

    [DataMember(Name = "page_no", EmitDefaultValue = false)]
    public int PageNumber { get; set; }

    [DataMember(Name = "total", EmitDefaultValue = false)]
    public int Total { get; set; }
}

[DataContract(Name = "company_webhook")]
public class KeepTruckinCompanyWebHook
{
    [DataMember(Name = "id", EmitDefaultValue = false)]
    public int Id { get; set; }

    [DataMember(Name = "url", EmitDefaultValue = false)]
    public string Url { get; set; }
}

显然,当我反序列化 JSON 时,我没有得到KeepTruckinCompanyWebHook属性,因为它们发送集合的方式是“嵌套的”。 我几乎必须在KeepTruckinCompanyWebHook创建另一个具有属性的对象。 但我想保持我的对象模型原样。 .NET 序列化程序可以吗?

我们像这样使用DataContractJsonSerializer

var ser = new DataContractJsonSerializer(typeof(KeepTruckinResponse));
response = ser.ReadObject(ms) as KeepTruckinResponse;

此时我们不想使用 NewtonSoft.Json

是的,这是可能的,但您需要一些自定义代码才能做到这一点。

有点难看,但是您可以创建一个自定义的IDataContractSurrogate类,将company_webhooks数组中的每个 JSON 对象反序列化为Dictionary<string, Dictionary<string, object>> ,然后将嵌套字典结构中的值复制到你的KeepTruckinCompanyWebHook类。 这是代理所需的代码:

class MyDataContractSurrogate : IDataContractSurrogate
{
    public Type GetDataContractType(Type type)
    {
        if (type == typeof(KeepTruckinCompanyWebHook))
        {
            return typeof(Dictionary<string, Dictionary<string, object>>);
        }
        return type;
    }

    public object GetDeserializedObject(object obj, Type targetType)
    {
        if (obj.GetType() == typeof(Dictionary<string, Dictionary<string, object>>) &&
            targetType == typeof(KeepTruckinCompanyWebHook))
        {
            var webHook = new KeepTruckinCompanyWebHook();
            var outerDict = (Dictionary<string, Dictionary<string, object>>)obj;
            var innerDict = outerDict["company_webhook"];

            foreach (PropertyInfo prop in GetDataMemberProperties(typeof(KeepTruckinCompanyWebHook)))
            {
                DataMemberAttribute att = prop.GetCustomAttribute<DataMemberAttribute>();

                object value;
                if (innerDict.TryGetValue(att.Name, out value))
                {
                    prop.SetValue(webHook, value);
                }
            }

            return webHook;
        }
        return obj;
    }

    public object GetObjectToSerialize(object obj, Type targetType)
    {
        if (obj.GetType() == typeof(KeepTruckinCompanyWebHook) &&
            targetType == typeof(Dictionary<string, Dictionary<string, object>>))
        {
            var webHook = (KeepTruckinCompanyWebHook)obj;
            var outerDict = new Dictionary<string, Dictionary<string, object>>();
            var innerDict = new Dictionary<string, object>();
            outerDict.Add("company_webhook", innerDict);

            foreach (PropertyInfo prop in GetDataMemberProperties(typeof(KeepTruckinCompanyWebHook)))
            {
                DataMemberAttribute att = prop.GetCustomAttribute<DataMemberAttribute>();
                innerDict.Add(att.Name, prop.GetValue(webHook));
            }

            return outerDict;
        }
        return obj;
    }

    private IEnumerable<PropertyInfo> GetDataMemberProperties(Type type)
    {
        return type.GetProperties().Where(p => p.CanRead && p.CanWrite && p.GetCustomAttribute<DataMemberAttribute>() != null);
    }

    // ------- The rest of these methods do not need to be implemented -------
    public object GetCustomDataToExport(Type clrType, Type dataContractType)
    {
        throw new NotImplementedException();
    }

    public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType)
    {
        throw new NotImplementedException();
    }

    public void GetKnownCustomDataTypes(System.Collections.ObjectModel.Collection<Type> customDataTypes)
    {
        throw new NotImplementedException();
    }

    public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
    {
        throw new NotImplementedException();
    }

    public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
    {
        throw new NotImplementedException();
    }
}

要使用代理,您需要创建DataContractJsonSerializerSettings的实例并将其传递给DataContractJsonSerializer并设置以下属性。 请注意,由于我们需要UseSimpleDictionaryFormat设置,因此此解决方案仅适用于 .Net 4.5 或更高版本。

var settings = new DataContractJsonSerializerSettings();
settings.DataContractSurrogate = new MyDataContractSurrogate();
settings.KnownTypes = new List<Type> { typeof(Dictionary<string, Dictionary<string, object>>) };
settings.UseSimpleDictionaryFormat = true;

这是一个演示:

public class Program
{
    public static void Main(string[] args)
    {
        string json = @"
        {
          ""company_webhooks"": [
            {
              ""company_webhook"": {
                ""id"": 42,
                ""url"": ""https://keeptruckin.com/callbacktest/842b02"",
                ""secret"": ""fe8b75de0a4e5898f0011faeb8c93654"",
                ""format"": ""json"",
                ""actions"": [
                  ""vehicle_location_received"",
                  ""vehicle_location_updated""
                ],
                ""enabled"": false
              }
            },
            {
              ""company_webhook"": {
                ""id"": 43,
                ""url"": ""https://keeptruckin.com/callbacktest/a6a783"",
                ""secret"": ""66a7368063cb21887f546c7af91be59c"",
                ""format"": ""json"",
                ""actions"": [
                  ""vehicle_location_received"",
                  ""vehicle_location_updated""
                ],
                ""enabled"": false
              }
            },
            {
              ""company_webhook"": {
                ""id"": 44,
                ""url"": ""https://keeptruckin.com/callbacktest/53a52c"",
                ""secret"": ""4451dc96513b3a67107466dd2c4d9589"",
                ""format"": ""json"",
                ""actions"": [
                  ""vehicle_location_received"",
                  ""vehicle_location_updated""
                ],
                ""enabled"": false
              }
            },
            {
              ""company_webhook"": {
                ""id"": 45,
                ""url"": ""https://keeptruckin.com/callbacktest/6fb337"",
                ""secret"": ""4177fbd88c30faaee03a4362648bd663"",
                ""format"": ""json"",
                ""actions"": [
                  ""vehicle_location_received"",
                  ""vehicle_location_updated""
                ],
                ""enabled"": false
              }
            },
            {
              ""company_webhook"": {
                ""id"": 46,
                ""url"": ""https://keeptruckin.com/callbacktest/8cd6da"",
                ""secret"": ""6e41817a048b009435e5102fca17db55"",
                ""format"": ""json"",
                ""actions"": [
                  ""vehicle_location_received"",
                  ""vehicle_location_updated""
                ],
                ""enabled"": false
              }
            }
          ],
          ""pagination"": {
            ""per_page"": 25,
            ""page_no"": 1,
            ""total"": 5
          }
        }";

        var settings = new DataContractJsonSerializerSettings();
        settings.DataContractSurrogate = new MyDataContractSurrogate();
        settings.KnownTypes = new List<Type> { typeof(Dictionary<string, Dictionary<string, object>>) };
        settings.UseSimpleDictionaryFormat = true;

        KeepTruckinResponse response = Deserialize<KeepTruckinResponse>(json, settings);

        foreach (KeepTruckinCompanyWebHook wh in response.WebHooks)
        {
            Console.WriteLine("Id: " + wh.Id + ", Url: " + wh.Url);
        }
    }

    public static T Deserialize<T>(string json, DataContractJsonSerializerSettings settings)
    {
        using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json)))
        {
            var ser = new DataContractJsonSerializer(typeof(T), settings);
            return (T)ser.ReadObject(ms);
        }
    }

    public static string Serialize(object obj, DataContractJsonSerializerSettings settings)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            var ser = new DataContractJsonSerializer(obj.GetType(), settings);
            ser.WriteObject(ms, obj);
            return Encoding.UTF8.GetString(ms.ToArray());
        }
    }
}

[DataContract]
public class KeepTruckinResponse
{
    [DataMember(Name = "company_webhooks", EmitDefaultValue = false)]
    public KeepTruckinCompanyWebHook[] WebHooks { get; set; }

    [DataMember(Name = "pagination", EmitDefaultValue = false)]
    public KeepTruckinPagination Pagination { get; set; }

    public string RawJSON { get; set; }
}

[DataContract]
public class KeepTruckinPagination
{
    [DataMember(Name = "per_page", EmitDefaultValue = false)]
    public int PerPage { get; set; }

    [DataMember(Name = "page_no", EmitDefaultValue = false)]
    public int PageNumber { get; set; }

    [DataMember(Name = "total", EmitDefaultValue = false)]
    public int Total { get; set; }
}

[DataContract(Name = "company_webhook")]
public class KeepTruckinCompanyWebHook
{
    [DataMember(Name = "id", EmitDefaultValue = false)]
    public int Id { get; set; }

    [DataMember(Name = "url", EmitDefaultValue = false)]
    public string Url { get; set; }
}

输出:

Id: 42, Url: https://keeptruckin.com/callbacktest/842b02
Id: 43, Url: https://keeptruckin.com/callbacktest/a6a783
Id: 44, Url: https://keeptruckin.com/callbacktest/53a52c
Id: 45, Url: https://keeptruckin.com/callbacktest/6fb337
Id: 46, Url: https://keeptruckin.com/callbacktest/8cd6da

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM