Azure table storage and complex types stored in Json

Azure table storage only supports some types. You can find the list here. Complex types are not supported (maybe later they will be, but today it's not the case).
I needed to store some data that is more complex than just a string. As I didn't need to search on the objects themselves it was ok to store them as Json.

To make our lives easier, Microsoft added a TableEntity class in their library. If you inherit your domain object from TableEntity, you'll be able to store your domain class in an azure table BUT only if it contains simple objects.

public class Person: TableEntity  
{
   public string Id { get; set; }
   public string FirstName { get; set; }
   public string LastName { get; set; }

   //The following property will NOT be stored in Azure
   public ContactData ContactData { get; set; }
}

To store an instance of the Person class you can do the following:

public async Task AddPerson()  
{
  var newPerson = new Person(){Id="1", FirstName="Bob", LastName=""};
  CloudStorageAccount storageAccount =   CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
  CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
  CloudTable table = tableClient.GetTableReference("Persons");
  TableOperation insertOperation = TableOperation.Insert(newPerson);
  await table.ExecuteAsync(insertOperation).ConfigureAwait(false);
}

There are 2 things to keep in mind:

  • The contactdata isn't stored
  • Treat Person as a domain object is strange because it isn't just a POCO. It has a reference to Microsoft.WindowsAzure.Storage and it inherits from TableEntity. It doesn't feel right to have that reference in each project that is linked to the domain.

Store your complex TableEntity property in Azure in Json

I wrote an attribute to decorate your property with to indicate that you want to serialize or deserialize that object to Json when stored or retrieved from Azure. The code and a demo can be downloaded from my Github.

Decorate your complex properties with the EntityPropertyConverterAttribute and override the ReadEntity en WriteEntity methods as follows:

using DevProtocol.Azure.EntityPropertyConverter;  
public class Person: TableEntity  
{
   public string Id { get; set; }
   public string FirstName { get; set; }
   public string LastName { get; set; }

   [EntityPropertyConverter]
   public ContactData ContactData { get; set; }

public override IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext)  
        {
            var results = base.WriteEntity(operationContext);
            EntityPropertyConvert.Serialize(this, results);
            return results;
        }

        public override void ReadEntity(IDictionary<string, EntityProperty> properties, OperationContext operationContext)
        {
            base.ReadEntity(properties, operationContext);
            EntityPropertyConvert.DeSerialize(this, properties);
        }
}

What if your TableEntity property is an interface?

If you work with an interface I added an overload to the EntityPropertyConverterAttribute so you can define the type of the class that implements the interface.

When using the following interfaces:

public interface IPerson  
{
     string Id { get; }
     string FirstName { get; }
     string LastName { get; } 
     IContactData ContactData { get; }
}

public interface IContactData  
{
    string Email { get; }
    string Phone { get; } 
}

Your Person class becomes:

public class Person: TableEntity, IPerson  
    {
        public string Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        [EntityPropertyConverter(typeof(ContactData))]
        public IContactData ContactData { get; set; }

        public override IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext)
        {
            var results = base.WriteEntity(operationContext);
            EntityPropertyConvert.Serialize(this, results);
            return results;
        }

        public override void ReadEntity(IDictionary<string, EntityProperty> properties, OperationContext operationContext)
        {
            base.ReadEntity(properties, operationContext);
            EntityPropertyConvert.DeSerialize(this, properties);
        }

With the attribute it becomes simple to store your complex types in azure table storage. Let me know how you're storing your complex types.

Download the code from my Github