【问题标题】:How can you deserialize JSON data in C# (using DataContractJsonSerializer) without knowing all property names?在不知道所有属性名称的情况下,如何在 C# 中反序列化 JSON 数据(使用 DataContractJsonSerializer)?
【发布时间】:2013-11-20 05:05:25
【问题描述】:

我一直在使用 DataContractJsonSerializer 将从 HubSpot API 返回的数据转换为强类型对象,但我在使用用户配置文件对象时遇到了一些问题。

在此示例中,我能够获取 Id 和 IsContact 属性,但无法弄清楚如何获取属性列表,因为我事先不知道它们是什么。我想让 Properties 成为 Dictionary 但我不知道该怎么做。我不关心每个属性的版本,只关心值。

这是 API 返回的数据的简化示例:

{
  "vid": 72361,
  "is-contact": true,
  "properties": {
    "city": {
      "value": "Burlington",
      "versions": [
        {
          "value": "Burlington",
          "source-type": "SALESFORCE",
          "source-id": "continuous",
          "source-label": null,
          "timestamp": 1384319976006,
          "selected": false
        }
      ]
    },
    "country": {
      "value": "US",
      "versions": [
        {
          "value": "US",
          "source-type": "SALESFORCE",
          "source-id": "continuous",
          "source-label": null,
          "timestamp": 1384319976006,
          "selected": false
        }
      ]
    },
    "company": {
      "value": "Bridgeline Digital",
      "versions": [
        {
          "value": "Bridgeline Digital",
          "source-type": "SALESFORCE",
          "source-id": "continuous",
          "source-label": null,
          "timestamp": 1384319976006,
          "selected": false
        }
      ]
    }
  }
}

这是我试图反序列化的对象:

[DataContract]
public class HubSpotUserProfile
{
    [DataMember(Name = "vid")]
    public int Id { get; set; }

    [DataMember(Name = "is-contact")]
    public bool IsContact { get; set; }

    [DataMember(Name = "redirect")]
    public string RedirectUrl { get; set; }

    [DataMember(Name = "properties")]
    public Dictionary<string, HubSpotUserProfileProperty> Properties { get; set; }
}

[DataContract]
public class HubSpotUserProfileProperty
{
    [DataMember(Name = "value")]
    public string Value { get; set; }
}

我调用这个方法来执行反序列化:

    public static T Post<T>(string url, string postData) where T : class
    {
        string json = Post(url, postData);

        if (!String.IsNullOrWhiteSpace(json))
        {
            using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(json)))
            {
                DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));

                return (T)serializer.ReadObject(stream);
            }
        }

        return null;
    }

当我这样做时,不会引发错误,但属性的计数始终为 0。关于如何实现此目标的任何想法?

【问题讨论】:

  • 你会如何处理额外的属性?由于您不知道它们是什么,因此可能很难编写代码来使用它们。

标签: c# asp.net json serialization


【解决方案1】:

为您的 Properties 属性使用 JsonObject 类型。在某些非常奇怪的情况下,DataContractJsonSerializer 在这种情况下不支持 Dictionary 类型

【讨论】:

  • 我可能应该提到我正在使用没有 JsonObject 的 .NET 4.0。你知道有什么替代品吗?
  • 您可以开始使用JSON.NET。这个库对字典没有任何问题
【解决方案2】:

如果 JSON.NET 是一个选项,那么 James 最近添加了 ExtensionData 支持。见http://james.newtonking.com/archive/2013/05/08/json-net-5-0-release-5-defaultsettings-and-extension-data

public class DirectoryAccount
{
  // normal deserialization
  public string DisplayName { get; set; }

  // these properties are set in OnDeserialized
  public string UserName { get; set; }
  public string Domain { get; set; }

  [JsonExtensionData]
  private IDictionary<string, JToken> _additionalData;

  [OnDeserialized]
  private void OnDeserialized(StreamingContext context)
  {
    // SAMAccountName is not deserialized to any property
    // and so it is added to the extension data dictionary
    string samAccountName = (string)_additionalData["SAMAccountName"];

    Domain = samAccountName.Split('\\')[0];
    UserName = samAccountName.Split('\\')[1];
  }
}

【讨论】:

  • 实际上,当您在同一对象的未知属性旁边有一些已知属性时,这是最有用的。在您的情况下,由于所有未知属性都在子属性上,因此声明一个名为 Properties 的 JObject(来自 Newtonsoft.Json.Linq)类型的属性可能是最简单的。
【解决方案3】:

根据您选择的反序列化对象包,您当前的模型将起作用。我们将JSon.Net 用于 HubSpot 的确切目的。

以下是我们使用的示例...

[DataContract]
public class ContactHubSpotModel {
// snip for brevity 
[DataMember(Name = "properties")]     
public Dictionary<string, ContactProperty> Properties { get; set; }
}

[DataContract]
public class ContactProperty
{
    [DataMember(Name = "value")]
    public string Value { get; set; }

    [DataMember(Name = "versions")]
    List<ContactPropertyVersion> Versions { get; set; }
}

[DataContract]
public class ContactPropertyVersion
{
    [DataMember(Name = "value")]
    public string Value { get; set; }

    [DataMember(Name = "source-type")]
    public string SourceType { get; set; }

    [DataMember(Name = "source-id")]
    public string SourceId { get; set; }

    [DataMember(Name = "source-label")]
    public string SourceLabel { get; set; }

    [DataMember(Name = "timestamp")]
    public long Timestamp { get; set; }

    [DataMember(Name = "selected")]
    public bool Selected { get; set; }
}

然后您可以将联系人输出的副本转储到文件中以进行验证,如下所示...

string contactJson = GetContactString(); // pulls sample data stored in a .txt
ContactHubSpotModel contactModel = JsonConvert.DeserializeObject<ContactHubSpotModel>(contactJson);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多