lightsaber
lightsaber

Reputation: 11

Datacontract object and string

I'm trying to parse some results from a web service in C# visual studio 2010 that are coming back in JSON but the field named data is sometime a string and sometimes an object. I'm not sure how to get the data contracts to handle that. When it runs through the deserialization it just returns a null result for the everything. If i try a web request that doesn't have any profile_results then works OK.

The JSON looks like this

{
"ListSingleOrganization": {
"id": 86270,
"short_name": "someshort name",
"long_name": "Long name",
"created_at": "2014-05-02T14:21:06Z",
"is_disabled": false,
"description": "Verbose description",
"renewed_at": "2014-05-02T14:21:07Z",
"alternate_id": null,
"website_url": "http://www.url.com",
"member_count": 50,
"pic_url": "https://www.somepicture.com/1.jpg",
"umbrella_id": 36016,
"keywords": "Fraternity, Leadership, Human Service, Scholarship",
"category": {
  "id": 53282,
  "name": "Fraternities"
},
"profile_responses": [
  {
    "element": {
      "id": 51350,
      "name": "Group Email Address",
      "type": "Email"
    },
    "data": "[email protected]"
  },
  {
    "element": {
      "id": 1239634,
      "name": "Please list your organization's Twitter handle so we may follow you with our office's account. (@something)",
      "type": "TextField"
    },
    "data": "@handle"
  },
  {
    "element": {
      "id": 1192652,
      "name": "Is this a new organization?",
      "type": "Radio"
    },
    "data": {
      "id": 2003570,
      "name": "No"
      }
    }
  ]
 }
}

the difference is based on the element type but i don't know how to account for that with them having the same name.

right now i have

[DataContract]
class ListSingleOrganization
{
 //other members

[DataMember(Name = "profile_responses")]
public List<profile_responses> profile_responses { get; set; }
}

[DataContract]
class profile_responses
{
    [DataMember(Name = "element")]
    public element element { get; set; }
    [DataMember(Name="data")]
    public data data {get; set; }

}

[DataContract]
class element
{
[DataMember(Name = "id")]
public int id { get; set; }

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

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


}
[DataContract]
class data
{
[DataMember(Order=1)]
public string raw { get; set; }
[DataMember(Name = "file_name")]
public string file_name { get; set; }
[DataMember(Name = "url")]
public string url { get; set; }
[DataMember(Name = "id")]
public int id { get; set; }
[DataMember(Name = "name")]
public string name { get; set; }

}

Upvotes: 1

Views: 1997

Answers (2)

lightsaber
lightsaber

Reputation: 11

Couldn't get the DataContract Serializes to work with these irregularities so I went the dynamic object route and that worked.

Deserialize JSON into C# dynamic object?

Upvotes: 0

John Iwasz
John Iwasz

Reputation: 151

You can create a custom formatter to read the property, check if it a string. If it's a string then create a new instance of your data class and set one of the properties to the string value. Otherwise, deserialize it to a your data object.

public class JsonDataConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(data));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        data returnVal = null;

         // You may need to debug this and see which token type is being returned
         // per data element and adjust, but the principle stands.
         if (reader.TokenType == JsonToken.String)
         {
             returnVal = new data();
             returnVal.raw = reader.ReadAsString();
         }
        else
        {
            returnVal = serializer.Deserialize<data>(reader);
        }

        return returnVal;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    { 
        // Assuming you only need to deserialize
        throw new NotImplementedException();
    }
}

Associate the JsonConverter with your property:

    [DataMember(Name = "data")]
    [JsonConverter(typeof(JsonDataConverter))]
    public data data { get; set; }

EDIT: (answering follow up question) Set this up in an isolated unit test and get it to work there first before trying to put this in a SSIS package. If you are using the DataContractSerializer then the JsonDataConverter class will not be invoked. You want to deserialize using Json.NET:

using Newtonsoft.Json;

. . .

var orgList JsonConvert.DeserializeObject<ListSingleOrganization>(webServiceResultString);

Upvotes: 1

Related Questions