Cloud Zone is brought to you in partnership with:

Adam is an Evangelist for Windows Azure, working for Microsoft. By day, you can likely find him somewhere in the midwest, driving to yet another whiteboarding/deep-thinking session, ready to figure out how the cloud can save your family from certain doom, and make you rich and successful in the process. Before he started evangelizing, Adam was a Senior Developer Lead for Microsoft in Redmond, working on Office 365, BPOS, and Office Live. He misses Redmond, and the excitement of the mother ship, but the call of bitter cold and lots of snow in Chicago was too much for him, and he had to return. Lucky for you! When he's not evangelizing, he likes to spend time with his wife and kids, telling them how the cloud will benefit them as well. Adam is a DZone MVB and is not an employee of DZone and has posted 9 posts at DZone. You can read more from them at their website. View Full User Profile

Handling enum values with type converters in Windows Azure Mobile Services

01.09.2013
| 2859 views |
  • submit to reddit

I’ve been doing a lot of work with Windows Azure Mobile Services (WAMS).  It’s a brilliant technology that allows you to stand up powerful OData compliant services to support your Windows 8 Store Apps, Windows Phone 8 Apps, and even iOS apps in just a few minutes.  It’s hard to oversell the sheer awesomeness of this stuff.

I’m currently working on a bunch of code that will shortly become a sample project highlighting both WAMS and Windows 8 Apps (look for a project called “FamilyPig” coming soon).  In the process of building that, I ran into a couple of questions – one of which I’ll cover here, and give some guidance to people who might be running into a similar question.

One of the cool features that makes WAMS super easy to work with is the concept of “dynamic schema”.  In a nutshell, that means that if you have an existing table, and you throw a Plain Old CLR Object (POCO) at it using the InsertAsync method (of the IMobileServiceTable interface), WAMS is smart enough to look at the object coming in, and make sure that it has all the columns that it needs in the underlying Windows Azure SQL Database table to store the record (assuming that “dynamic schema” is enabled on the mobile service).  If the column does exist, it gets created on the fly.  Very, very cool.  Note, what’s actually happening under the covers is that your POCO object is being converted to a JSON object for transmission over the wire, and WAMS is pulling apart that JSON object to look at the columns.

Now, in order to do this, it makes some assumptions.  It looks at the JSON object, and if it sees a certain type of data, it creates a certain type of column to support the data.  The easiest thing that it could have done would be to just create text columns in the underlying SQL database, since any type of data can be stored as a string.  Instead, it does something quite a bit smarter, and creates data types that are quite a bit more “appropriate”.  Here’s the strategy that it uses:

JSON / CLR Data Type T-SQL Type in underlying SQL Azure database table
Numeric values (integer, decimal, floating point) float(53) – this is the maximum precision float.
Boolean bit
DateTime DateTimeOffset(3)
String nvarchar(max)

OK, so this is great.  Dynamic schema is pretty cool.  However…

When I work on a database schema, I often run into a case where I want to create a “code/decode” style table.  In my world, a “code/decode” table is typically a two column table, where the primary key is the “code” and the other column is a textual description.  The canonical example is a “States” table (in the US).  Like this:

Code Decode
AL Alabama
AK Alaska
AZ Arizona
IL Illinois
WY Wyoming

Then, with this table defined, I’ll just use it anywhere I need a State… like this:

Column DataType Notes
FirstName nvarchar(50)  
LastName nvarchar(50)  
Address1 nvarchar(100)  
Address2 nvarchar(100)  
City nvarchar(100)  
State char(2) Foreign Key to State Code
ZIPCode char(5)  

Now, in my current project, it wasn’t a state code that I needed, it was a “CurrencyType”.  And moreover, I wanted to be able to have an “enum” value of CurrencyTypes to be able to work with in my application.  This led me to wonder how WAMS could handle storing and retrieving an “enum” in the database.  It’s not immediately clear that it would know what to do with it as a JSON type.  The JavaScriptSerializer seems to turn enum values into an integer value, which would probably work, but I really wanted my underlying SQL table to store “IL” for Illinois, and not the number 14 as a 53 bits of precision float.  So, how can I turn my enum values into the underlying state codes as a 2 character string on the way in, and reconvert them back to my enum values on the way out?

To start with, here’s the (truncated) version of my enum for my CurrencyType.

public enum CurrencyType
{
	UnitedArabEmiratesDirham,
	AfghanistanAfghani,
	AlbaniaLek,
	//...
	UnitedStatesDollar,	
	//... 
	Unknown
}

Next, the secret sauce turns out to be an IDataMemberJsonConverter .  This interface exists within the Microsoft.WindowsAzure.MobileServices assembly, and has 2 methods that you need to implement – ConvertFromJson and ConvertToJson.  Here’s the type converter that I created to massage my enum into a string going in, and from a string back to the enum on the way back out…

First, the ConvertToJson method:

public IJsonValue ConvertToJson(object instance)
{
	if (instance is Types.CurrencyType)
	{
		switch ((Types.CurrencyType)instance)
		{	
			case Types.CurrencyType.UnitedArabEmiratesDirham:
				return JsonValue.CreateStringValue("AED");
			case Types.CurrencyType.AfghanistanAfghani:
				return JsonValue.CreateStringValue("AFN");
			case Types.CurrencyType.AlbaniaLek:
				return JsonValue.CreateStringValue("ALL");
// SNIP
			case Types.CurrencyType.UnitedStatesDollar:
				return JsonValue.CreateStringValue("USD");
// SNIP
			default:
				return JsonValue.CreateStringValue("XXX");
		}
	}
	else
		return JsonValue.Parse("null");
}

Next, the ConvertFromJson method:

public object ConvertFromJson(IJsonValue value)
{ 
	CurrencyType result = Types.CurrencyType.Unknown; 
	if (value != null && value.ValueType == JsonValueType.String) 
	{ 
		switch (value.GetString()) 
		{ 
			case "AED": 
				return Types.CurrencyType.UnitedArabEmiratesDirham; 
			case "AFN": 
				return Types.CurrencyType.AfghanistanAfghani; 
			case "ALL": 
				return Types.CurrencyType.AlbaniaLek;
// SNIP 
			case "USD": 
				return Types.CurrencyType.UnitedStatesDollar;
// SNIP 
			case "ZWD": 
				return Types.CurrencyType.ZimbabweDollar; 
			case "XXX": 
				return Types.CurrencyType.Unknown; 
			default: 
				return Types.CurrencyType.Unknown; 
		} 
	}
	return result;
}

Now, the only thing remaining is to decorate the CLR class that we’re using to hold our object with enough information to get the serializer to use our type converter as necessary.  In my case, the column for CurrencyType is contained in a class called FamilyGroup.  Here’s that implementation:

public class FamilyGroup
{
	public long Id { get; set; } 
	public string Name { get; set; }

 	[DataMemberJsonConverter(ConverterType = typeof(CurrencyTypeConverter))] 
	public CurrencyType CurrencyType { get; set; }
}

And that’s it.  We have our enum to work with in our code, we’re able to store and retrieve our values to WAMS and the data in the tables is readable to boot.

Happy coding.

Published at DZone with permission of Adam Hoffman, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)