Using Custom Contract Resolvers for JSON.NET

June 15, 2016
by
Brian Oliver

C2 Senior Advanced Developer Brian Oliver outlines how he used custom contract resolvers to make similar sets of data from a third-party web service function better within C#.

Development

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.