There are ways to work around this limitation, however. The simplest alternative would be to split the DateTimeOffset property into two properties in the client side – one for the DateTime itself, and one for the offset from UTC. In this case, the class would have two properties equivalent to the DateTimeOffset property – and the type can even continue with the original property (properly marked with [JsonIgnore] to prevent it from being sent to the server and creating a new column – notice that this code is already using the version 0.3.x of the client SDK, the Portable Library-based SDK from the NuGet feed). The code below shows the before and after version of a type with a DateTimeOffset property.
That solution works fine, but it forces us to change the domain object on the client side to deal with a distributed problem. If other people are using this type, they will get affected by it (we can mitigate it by using something like decorating the UtcTime and UtcTimeOffsetMinutes with [EditorBrowsable(EditorBrowsableState.Never)], but that’s again just working around the problem. What we can do is to change the way we serialize the original Time field, so that only during the serialization (and deserialization) of the type we need to worry about deconstructing (and reconstructing) the value. I posted before about how we can do it with the original managed client SDK, and the idea with the new version of the SDK (based on JSON.NET) is similar, as I’ll show below.
First, we don’t need to split the parameter in multiple values – all we need to do is to decorate the property with the [JsonConverter] attribute to tell the client runtime that we want to use our own code to convert that value to and from JSON.
To write the object into JSON we could call the appropriate methods into the JsonWriter parameter, but the simplest way is to wrap them into a dictionary, and let the JSON.NET serializer deal with that for us. What we’re doing here is to write the DateTimeOffset value as a JSON object with two members, one for the UTC value date component, one for the offset component.
And since we write it, we need to read it back, so here’s the implementation of ReadJson:
At this point, the client is all set. However, if we try to insert any instance of the Event class into an Azure Mobile Service, we’ll have an error at the runtime – the runtime doesn’t know how to insert objects into the database, so we need to update the insert (and update and read) scripts to “tell” it what to do with those. The full explanation can be found in the post about supporting complex types in mobile services. The insert script would look similar to the one below – if the incoming item has a ‘Time’ property of type object, that (likely) means that our converter is the one supplying the values, so we know which fields to look for. And after the insertion is completed, we recreate the original object, which will then be read by the converter at the client.
The update handler is exactly the same – break the object before the operation, recreate it afterwards:
Finally, for reading we need, for all objects to be returned, to reassemble the object from the two columns in the database, which can be easily implemented by ‘forEach’-ing the results as shown below.
That’s it. We don’t need to update the delete script since it is based on the object id.
This post is almost an update to the post about supporting complex types in mobile services using the new client API (based on JSON.NET), and hopefully it has shown that although some times the “impedance mismatch” between the runtime and the various client SDKs can cause problems, the Azure Mobile Services platform is extensible enough that we can, without a huge amount of code, work around the issues caused by the framework differences.
And as usual, please raise any concerns and suggestions in our MSDN forums or in the comments for those blogs.