如何在不知道所有属性名称的情况下在C#中反序列化JSON数据(使用DataContractJsonSerializer)?

时间:2013-11-20 05:05:26

标签: c# asp.net json serialization

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

在这个例子中,我能够获得Id和IsContact属性,但无法弄清楚如何获取属性列表,因为我事先并不知道它们是什么。我想将属性设为字典,但我不知道如何做到这一点。我不关心每个属性的版本,只关心值。

这是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.我对如何实现这个目标有任何想法?

3 个答案:

答案 0 :(得分:0)

对Properties属性使用JsonObject类型。在一些非常奇怪的情况下,DataContractJsonSerializer不支持Dictionary&lt;&gt;在这种情况下键入

答案 1 :(得分:0)

如果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];
  }
}

答案 2 :(得分:0)

取决于您选择的用于反序列化对象的包,您当前的模型可以使用。为此,我们将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);