Using Custom Contract Resolvers for JSON.NET

Brian Oliver
Senior Advanced Developer

So, a funny thing happened the other day.  I don’t mean “funny” as in “orange you glad I didn’t say banana,” and I definitely don’t mean funny as in a moose wearing a bikini.

I was writing an application that needed to consume a third-party web service to get seven-day weather forecast data.  The web service returned a JSON-formatted array of objects, so I created a .NET object and used the Newtonsoft JSON.Net library to deserialize the array.  The web service used one-letter property names, and I wanted to have something a little more descriptive in my code, so I used the JSONProperty attribute:

<p> CODE: https://gist.github.com/thec2group-blog/1510acde914fded289732830a9839b02.js</p>

The web service returned an array of these extended forecast objects – one for each of the next seven days, so I used this code to deserialize the result:

<p> CODE: https://gist.github.com/thec2group-blog/b83eba34c46ab929509d15de824c22bc.js</p>

This all worked swimmingly.  Life was good…but then the funny thing happened. I also needed to consume a web service to get a 36-hour forecast, but this was a web service that did not yet exist (ok, so when I said this was a funny thing, I actually meant it was funny in the sense that it made me want to bang my head against a wall).  When this web service became available, I discovered that it was returning the same exact data but with different property names. I would need the following class to deserialize the data from this new web service:

<p> CODE: https://gist.github.com/thec2group-blog/0be987fe22a0b8ccde6cbed3ac67bed7.js</p>

The problem was that I already had this class. Could I name it something else… ExtendedForecast2, perhaps? That just didn’t sit right with me.  It’s the same type of data, so I should be able to use the same class for each of the web services, shouldn’t I?

The solution?  Custom contract resolvers.  JSON.Net has a class called DefaultContractResolver that I can inherit and use in my JSONSerializationSettings.  This class defines a method named ResolvePropertyName, which is what JSON.Net will call for each JSON property to determine to which property name on my C# class it corresponds.  I’m going to use this contract resolver concept to replace the JSONProperty attributes.

I’m going to need two contract resolvers, one for each web service, and I want a way to use LINQ expressions to specify which property I’m mapping.  I want to be able to do this in the constructor of each contract resolver:

<p> CODE: https://gist.github.com/thec2group-blog/0b20a16f8ffaa9dec774abc3266ce91a.js</p>

In this example, the first five properties map to JSON properties with identical names.  The sixth property maps to a different name in the JSON.  To start with, I need a base class with three basic components: first, a dictionary for storing the C# property name (key) and JSON property name (value) for each property; second, an AddMap method that will take an LINQ expression, turn it into a C# property name, and add it to the dictionary; and third, an override of the ResolvePropertyName method that will take the property name passed in and look it up in the dictionary.

Step One, the dictionary.  That’s easy:

<p> CODE: https://gist.github.com/thec2group-blog/315bd8007cac5451c7dd301b96193d48.js</p>

Step Two, the real magic, the AddMap method.  I’m going to need two versions of this method.  One will take just the expression (for when the C# name and JSON name are identical), and the other will take the expression and the JSON property name:

<p> CODE: https://gist.github.com/thec2group-blog/be77bdb7255d644cdadf01cb7c423fc9.js</p>

Step Three, the override method:

<p> CODE: https://gist.github.com/thec2group-blog/32321639d1f05f8f246e0515639ab176.js</p>

Notice that the AddMap is only generic on U.  The other generic type (T) will be defined on the class.  The final base class is shown here:

<p> CODE: https://gist.github.com/thec2group-blog/4ec3cea333a040e04866bbbf4400f11b.js</p>

Now using these contract resolvers is super easy:

<p> CODE: https://gist.github.com/thec2group-blog/161a41ba9eef84917a254ff3c82ebe3d.js</p>

We could be done, except I suppose that instead of instantiating the contract resolvers each time we need them, we should have a static instance for each resolver and reuse them, thus saving the time of calling the constructor.  With this, the contract resolver would look like this:

<p> CODE: https://gist.github.com/thec2group-blog/505819c750177cab21c49bf310a8c43d.js</p>

And we would use it like so:

<p> CODE: https://gist.github.com/thec2group-blog/1b07cf7b8723a3a1bd707853602ead30.js</p>

The other contract resolver would follow the same pattern.

One last note:  it is important to remove all of the JSONProperty attributes from your class when using this method.  If you don’t, the name from that attribute (NOT the name of your C# property) will be passed in to the ResolvePropertyName method.

Insights, Right to Your Inbox.