My first article on Azure Mobile using Azure Table Storage, recieved a fair amount of feedback because not much other documentation can be found on how to use it.
Due to that I feel like it is due for a revisit, because afterall the first post was a little rushed to get it out before Microsoft would release any official documentation or release a newer version of the framework, which is on the way btw.
@simped @theyavor @kirillg_msft @AzureMobile Yes, [NotMapped] used to work but no longer 🙁 I've added [IgnoreProperty] for next drop. Thx!
— Henrik F. Nielsen (@frystyk) May 7, 2014
Russ one of the commentators on the first post complained that, he was getting exceptions on the documentation page. The fix to that is to change the code for the Id property to something like the following:
[csharp]
[IgnoreProperty]
public string Id
{
get
{
return ((object)new CompositeTableKey(new string[2] { this.PartitionKey, this.RowKey })).ToString();
}
set
{
CompositeTableKey compositeTableKey;
if (!CompositeTableKey.TryParse(value, out compositeTableKey) || compositeTableKey.Segments.Count != 2)
{
this.PartitionKey = value;
this.RowKey = value;
}
else
{
this.PartitionKey = compositeTableKey.Segments[0];
this.RowKey = compositeTableKey.Segments[1];
}
}
}
[/csharp]
The thing is the mobile framework for Azure table storage is based on having an Id that is of the format “[PartionKey],[RowKey]”. If you don’t have that the real implementation that I copied the code from and modified a bit in the first post, would throw an exception. Unfortunately that doesn’t really work with the custom documentation code that is also part of the mobile framework. So to fix that, I dropped the throwing of exception and just set both PartitionKey and Row key to the value of the Id (when it cannot be parsed as the format “[PartionKey],[RowKey]”).
Another annoying thing about using Azure table storage, I have noticed is that when you query for data it will return the public properties of the TableEntity
class, like PartitionKey, RowKey, ETag and Timestamp.
[js]
{
"text": "sample string 1",
"id": "’1′,’10’",
"partitionKey": "1",
"rowKey": "10",
"timestamp": "2014-05-09T19:09:02.364Z",
"eTag": "W/\"datetime’2014-05-09T19%3A09%3A02.364663Z’\""
}
[/js]
Whether or not you need these on your client is application dependent, but if you just want the properties you defined on your own data class, I have found a way to hide the rest.
The serialization from C# classes to JSON objects in the mobile service framework is done using JSON.Net. Luckily, JSON.net gives us a few options to control what becomes serialized to JSON.
One method is to put an attribute on your class, [JsonObject(MemberSerialization.OptOut)]
this way nothing will get serialize, except those properties that you want and mark with [JsonProperty]
.
I don’t like this approach, as it is one extra thing I have to remember to do right. Unfortunately, the alternative requires some extra code in the StorageData
class, as JSON.net apparently have no easy way of hiding properties from the base class when serializing.
Properties that are defined in the StorageData
class, can easily be excluded from the resulting JSON by adding the attribute [JsonIgnore]
. But for the base properties we have to go through the following loop hole, to hide e.g. the PartitionKey.
[csharp]
public new string PartitionKey
{
get { return base.PartitionKey; }
set { base.PartitionKey = value; }
}
public bool ShouldSerializePartitionKey()
{
return false;
}
[/csharp]
So what happens here? JSON.net have a feature to dynamically hiding properties. It works by implemention a public method called ShouldSerialize[PropertyName] that is called during the serialization process and the result of it defines if the property should be serialized or not. But it only works with properties in the same class, not in the base class, so to circumvent that I redefine the PartitionKey property in my StorageData
class, not a particularly nice solution, but a solution nevertheless.
Here’s how the result looks now
The complete source code for the sample project I have been playing around with can be found on github. It also contains a fix to the GetById method that Ross made me aware of in the first post.