1

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; }

}
2
  • You can receive it as an object at all times then you can map the object with a custom mapper. Commented Dec 19, 2014 at 22:21
  • I'm using the DataContractJsonSerializer Commented Dec 20, 2014 at 22:15

2 Answers 2

1

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);
Sign up to request clarification or add additional context in comments.

3 Comments

I think your solution would probably work. However I don't think I can use JSON.net. I'm trying to implement this solution in SSIS and I can get it to build in script editor but when the scripted component is built in the integration project it throws a missing file exception and can't find the 3rd party dll.
So I go JSON.net added to the GAC so it would work but when I ran the code it still didn't match and I only got a null result. could be because I'm using DataContractJsonSerializer.
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. using Newtonsoft.Json; . . . var orgList JsonConvert.DeserializeObject<ListSingleOrganization>(webServiceResultString);
0

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?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.