2

I'm using Json.NET (http://james.newtonking.com/projects/json/help/) as a way to serialize and deserialize JSON from a server. Let's say I have the following JSON object:

{
    "user" : {
         "name" : "Bob",
         "age" : 35
    },
    "location" : "California"
}

The only way that I can find to deserialize this in to native types is to use a custom DTO as follows:

string jsonString = ""; // json string from above
Response result = JsonConvert.DeserializeObject<Response> (jsonString);

where the Response class looks something like:

public class Response
{
    [JsonProperty("user")]
    public UserResponse User { get; set; }

    [JsonProperty("location")]
    public string Location { get; set; }
}

public class UserResponse
{
    [JsonProperty("name")]
    public string Name { get; set; }

    [JsonProperty("age")]
    public int Age { get; set; }
}

I want to deserialize this in to native types but I'm in an environment where I don't always know what the JSON string will look like... so it's hard to use custom DTO's when I don't know exactly what I'm getting down the pipe. If I don't pass any class in to JsonConvert.DeserializeObject(), then I end up with Json.NET types instead of native types like strings, ints, etc. Any suggestions on how to get around this? Should I be using a different JSON library instead?

Thanks!

joelpoloney
  • 419
  • 4
  • 13
  • 3
    You won't get strongly-typed results, but see these articles: http://stackoverflow.com/questions/3142495/deserialize-json-into-c-sharp-dynamic-object and http://blog.petegoo.com/index.php/2009/10/26/using-json-net-to-eval-json-into-a-dynamic-variable-in/ You can deserialize to an anonymous/expando/dynamic object. – Eli Gassert Nov 09 '12 at 22:35
  • 4
    Your problem is not related with json libraries. `I don't always know what the JSON string will look like`; then you can not deserialize it to a type safe class – L.B Nov 09 '12 at 22:35

1 Answers1

1

This will not solve all of your problems (that's just not possible) but here is a solution that will allow you to parse json with limited information about what's coming back.

At the outer level you create an object call it Vehicle. This contains a Car, Boat, and Plane. You're requesting some Vehicle but you don't know whether it will be Car, Boat, or Plane (note this could easily be expanded to handle an array of Vehicles or many other more complex responses). In the schema you have some options like;

"id": "vehicle.schema.json",
"type": "object",
"required": true,
"additionalProperties": false,
"properties": {
    "Car": {
        "type": "object",
        "required": false
        //other properties
    },
              "Boat": {
        "type": "object",
        "required": false
        //other properties
    },
            "Plane": {
        "type": "object",
        "required": false
        //other properties
    }

Above is the schema file you would add to your project. If you want to have several of these just add more Tuples to the _schemaTypes array below.

   // code to set up your schema
  // Associate types to their JsonSchemas.  Order matters here.
  // After each parse, the schema is added to resolver, which is used in subsequent parses.
        _schemaTypes = new[]
        {
            Tuple.Create(typeof(Vehicle), "vehicle.schema.json"),
        }
        .ToDictionary(
            x => x.Item1,
            x => JsonSchema.Parse(
                File.ReadAllText(
                    Path.Combine(AppDomain.CurrentDomain.RelativeSearchPath ?? "",  @"Serialization\Schemas\") + x.Item2),
                    resolver));


 //method to return your deserialized object
 public T Deserialize<T>(IRestResponse response)
    {
        var schema = _schemaTypes[typeof(T)];

        T result = _serializer.Deserialize<T>(
                new JsonValidatingReader(
                    new JsonTextReader(
                        new StringReader(response.Content)))
                {
                    Schema = schema
                });
        return result;
    }

Now after you parse your response you will have a more general object and from there you can write some code to figure out what the more specific object returned was. I'm using this type of approach to parse json where it has several levels of nested objects and arrays of objects and it is rather effective.

evanmcdonnal
  • 46,131
  • 16
  • 104
  • 115
  • It seems that you create your own question and answer it. Another thing is that OP uses Json.Net, but what you are using is unknown. – L.B Nov 09 '12 at 23:29
  • 3
    @L.B This uses `Newtonsoft.Json` and `Newtonsoft.Json.Schema`. I didn't answer his question exactly because there is no answer to that question, I tried to provide some guidance for parsing json with limited information. As you said in your OP comment, there's no way to do exactly what he wants. – evanmcdonnal Nov 09 '12 at 23:34
  • @L.B Additionally I don't believe the line `I don't always know what the JSON string will look like`. I assume that's an overstatement and really means "there are many variations of json that can be returned by the same request depending on the current state of the server app." If that is the case then a good schema can handle all of those variations. – evanmcdonnal Nov 09 '12 at 23:44
  • +1 for a workable pattern despite not having all the needed info. – Heather Nov 10 '12 at 00:57
  • @Heather Thank you. What should I add to make it more complete? – evanmcdonnal Nov 10 '12 at 00:59
  • Shrug... depends on the "I don't always know" statement. If he truly can't know, I think I'd use the actual JSON data to create a prototype on the fly and see if it matches any known types. After all, it has the property names and the types can be inferred from the data. I think I'd find a way to know 'cos the alternative is pretty fugly. – Heather Nov 10 '12 at 01:07
  • I actually can't reliably determine what's coming over the wire. One of the parts of the JSON blob is a user defined section that could really have just about anything inside of it. There's no real way for me to match that to anything. – joelpoloney Nov 10 '12 at 02:46
  • @fffanatics This may be information you can't disclose, but, if the user can define anything what do you expect to get out of deserializing it? Why not just save the blob as is? – evanmcdonnal Nov 10 '12 at 02:58
  • Arrrrrrrr the schema part of json.net is a pay for module?! –  Apr 16 '15 at 11:13
  • @iwayneo really? Can you link to something? At the time I wrote this answer it was just part of the mainline distro. – evanmcdonnal Apr 16 '15 at 15:33