Optimizing your JSON Data Access
If you're a .NET developer, you're likely familiar with Newtonsoft's Json.Net framework. Using it makes working with JSON in .NET apps a breeze. Drop in the NuGet package, decorate your model classes, and if the models you're working with are of a reasonable size, you're good to go.
Often when we're working with these models you only need a few properties, yet we serialize the entire model because the performance hit isn't large enough to justify writing new model classes for each subset of properties, along with other work to map data between objects. When performance becomes an issue though, we have a few ways to optimize. Here I'll show how to make use of the LINQ to JSON and ContractResolver features of the framework so you can achieve high performance working with any model, get some code re-use, and keep your model classes tidy.
(You can download the sample app to follow along)
LINQ to JSON
This simple technique can go a long way in the first step of getting your data, as you query only the JSON you're interested in out of the JObject graph. Here we have a Company holding a list of Locations. Each Location has multiple lists of it's own, so deserializing the entire Company when we only want one Location is inefficient and redundant. The following is a simple query to get us the one Location as a JObject in a strongly typed fashion:
Now that we have the JObject we're interested in, we can continue to optimize working with this Location further.
Have a look at this mobile app used to manage our Location:
What we can do is deserialize the properties we need on-demand, as the user navigates between tabs. We do this by holding a reference to the Location JObject in each tab. The Location Details tab will be shown first by default, so we need to get those properties. This is where our DynamicContractResolver comes in:
You can use this class to work with a subset of a models properties in a strongly typed fashion. Let's use it in our Location Details tab:
In this snippet, we lazy load our DynamicContractResolver and pass it the list of properties we need. Next we use a helper extension method from the framework to deserialize the JObject into a .NET Location object with ToObject<T>. From here it's just rinse and repeat for the remaining Location tabs.
Stitching It Back Together
Let's continue working with our Location Details tab. So far, we've grabbed our Location JObject and deserialized 2 properties into a Location .NET entity that we can bind to the UI. Now the user has updated the Name and Address, and hits save. Even though we can use our DynamicContractResolver to serialize the Location back into a JObject, the resulting JObject would be missing values from the other tabs such as Employees and Products. To preserve the entire Location JObject, we need to manually map these values over:
Finally, since our Location ultimately came from a list of Locations on the Company JObject, we upsert it using LINQ to JSON:
Performance and Flexibility
These simple enhancements can give you a big performance boost, as well as provide you with greater flexibility in situations where you can't change the schema of JSON objects you're working with.