1

So the company I've been working for has asked me to make a C# library for a client company who needs to access our API with .NET. So far I have a working library, but I keep having problems parsing optional properties. We use mongoDB on the backend, and mongoDB doesn't store properties that aren't provided even if they're defined in the schema.

For example, my schema may look like:

{
   name:String,
   id:Number,
   phone:String,
   email:String,
   experience:[]
}

Where as I make the document:

{
   name:"joe",
   id:5,
   phone:"222-222-2222",
}

The properties email and experience DO NOT exist in my document, so my JSON looks exactly as displayed above. These values are not required values however, but I still need to parse the rest of it. The problem is that when I parse the code above for all the possible values when I parse for email or experience the parser throws a Null Reference Exception, and with good reason because the value I'm trying to parse does not exist and the way I reference these values is like so:

JObject o=JObject.Parse(json); //parse json to JObject json object
string name=(string)o["name"];
int id=(int)o["id"];
string phone=(string)o["phone"];
string email=(string)o["emain"];
List<string> exp=o["experience"].Select(t => (string)t).ToList();

Now my code is a lot more objective, I using LINQ to create an object called Job and a object Jobs to store the JObject in a way where you can query certain values out of it using methods of the Jobs object thats initialized with the original JSON string.

Thing is the only way I can think of to handle optional properties in the JSON is to try/catch each and every value. This seems very sloppy and the JSON I have to parse is about 40-50 properties in total. This seems like it would be extremely slow and a huge mess of code. I'm wondering if I can implement this is a cleaner more efficient way.

22
  • 1
    Have you tried var job = JsonConvert.DeserializeObject<Job>(json); ? Commented Mar 10, 2014 at 21:52
  • I'm not sure I understand. MongoDB is schemaless, right? You shouldn't have to parse anything. You can just dump it as BSON document into Mongo Commented Mar 10, 2014 at 21:52
  • @mason it is Json.Net's class. Commented Mar 10, 2014 at 21:53
  • 1
    @tsturzl It seems you are missing something. goto first_comment; Commented Mar 10, 2014 at 22:04
  • 1
    @tsturzl Your problem lies in that you're trying to manually deserialize then this is something Json.NET does out of the box, as in the the first comment and evan's answer. Commented Mar 10, 2014 at 22:07

1 Answer 1

7

Unless there is some good reason you can't use the generic deserialize/serialize methods I would recommend changing your approach to use those. In general, I think the type of conditional, property specific parsing you're doing above is very poor practice. Here is an example;

public class Job
{
   public string name;
   public string id;
   public string phone;
   public string email;
   public string[] experience; // can also be a List<string> without any problems
}

Job j = JsonConvert.DeserializeObject<Job>(jsonString);

string output = JsonConvert.SerializeObject(j);
//will include "optional" parameters, meaning if there is no phone value it will be an empty string but the property name will still be there.

If you really want to confirm that say, some required parameters are included but some other optional ones are not I would recommend using json schemas in combination with json.NET. You can do something like the following;

//schema in flat text file I read with File.ReadAllText(path);
{
    "type":"object",
    "$schema": "http://json-schema.org/draft-03/schema",
    "required":true,
    "properties":{
        "name": { "type":"string", "required":true },
        "id": { "type":"string", "required":true },
                "phone": { "type":"string", "required":false },
                "email": { "type":"string", "required":false },
                "experience": { "type":"array", "required":true, "items": { "string" } }
    }
}

Then in code you have something like;

JObject obj = JObject.Parse(json);
JsonSchema jscheme = JsonSchema.Parse(File.ReadAllText(thatSchemaAbove));
IList<string> errors;
obj.IsValid(jscheme, out errors);
if (errors.Count() > 0)
{
     //json didn't match the schema, do something about it!
}

EDIT: Handling complex objects;

Pretend your json is instead an object with an array of Job objects called jobs. Use the following C# class definitions for that;

public class jobsWrapper
{
    public List<Job> jobs;
}

Any construct used in json has a C# equivalent, you just need to decompose it and determine what that is.

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you C# is definitely not my strong point. If I were to want to set experience to a List<string> instead of an array would that be a problem?
@tsturzl not at all. Just make it so in your class and everything will work just the same.
How would I be able to parse embedded objects? I have objects embedded in arrays, and objects inside other objects. This JSON is pretty complex.
@tsturzl so it's just about translating the data model in the json to classes in C#. I'll edit with another little snippet that might get you moving in the right direction. I would include more detail but it's very tedious and I can't copy/paste any of actual work for obvious reasons.

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.