【问题标题】:Deserializing JSON, nested object properties to be in parent object. C#反序列化 JSON,嵌套对象属性位于父对象中。 C#
【发布时间】:2017-10-03 21:30:36
【问题描述】:

我有以下 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

【问题讨论】:

  • 编辑您的问题以表明您正在序列化数据。通常避免使用DataContract,而是使用更多使用的NewtonSoft.Json 属性
  • “显然,当我反序列化 JSON 时,我没有得到 KeepTruckinCompanyWebHook 属性,因为它们发送集合的方式是嵌套的”不知道你的意思。作为使用 Newtonsoft 的人,我非常希望它能够被反序列化。

标签: c# .net json serialization datacontractjsonserializer


【解决方案1】:

是的,这是可能的,但您需要一些自定义代码来执行此操作。

有点难看,但是您可以创建一个自定义 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-08
    • 1970-01-01
    • 2011-12-21
    • 2019-07-22
    相关资源
    最近更新 更多