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.