Menu Home

Azure Mobile Service .NET backend using Azure Table Storage

Maybe you attended the Build 2014 Conference or maybe you just watched some of the sessions/keynote and was impressed with the new .NET backend for Azure Mobile Services. I was very impressed by what I saw in Kirill Gavrylyuk and Yavor Georgiev session on Powerful Mobile Apps with Mobile Services and ASP.NET Web API.

I have posted an update to this article with additional information. This article is still very valid, just be sure to also read part two. If you want to skip the reading just grab my sample project from github

I never really liked first version of the Mobile Service built on node.js, not because I dislike node.js, I just felt like it wasn’t production ready, due to the small node.js snippets typed into the Azure Portal (I know that the deployment story have gotten better since I played with it the first time, but they lost be in the beginning). Now with the .NET backend in preview, I might be coming back, I really like the WebAPI, and the deployment story seems a lot more complete now.

Also the whole concept of DomainManagers that they have introduced, so it is somewhat transparent to the developer what backing storage that are used is really cool. If you watch the session you will see how easy it is to use both Azure SQL and MongoDB, they also claim that they have a DomainManager ready for Azure Table Storage. The last announcement made me really exited, I never understod why I should use an expensive Azure SQL database, when the whole premise for Mobile Service is to have a very simple CRUD API with few to none relationsship between objects, why wasn’t it Azure Table Storage that was the datastorage of choice, instead of Azure SQL without relationships. Well, enough with the whining, lets look at how easy it’s to use Azure Table Storage for you .NET power Mobile Service.

Creating a new Visual Studio Project

The first thing you need to do before anything, is to update your VS2013 with Update 2 RC or newer, otherwise you won’t have the project template.

When that is taken care of, you find the Windows Azure Mobile Service project template, under the cloud category.
azuremobileservice
There is not much (in fact nothing) you can configure for this type of project, so simply click okay twice.

If you instantly start to look for the new domain managers, you are in for a disappointment, because the project comes preconfigured with some old references of the WindowsAzure.MobileServices.Backend Nuget packages, so you wont have the MongoDB or Azure Table Storage domain manager.

  <package id="WindowsAzure.MobileServices.Backend" version="1.0.225-beta" targetFramework="net45" />
  <package id="WindowsAzure.MobileServices.Backend.Entity" version="1.0.225-beta" targetFramework="net45" />
  <package id="WindowsAzure.MobileServices.Backend.Tables" version="1.0.225-beta" targetFramework="net45" />

To update to the latest packages (prerelease still) run the following commands from the Package Manager Console.
Update-Package WindowsAzure.MobileServices.Backend -Prerelease
Update-Package WindowsAzure.MobileServices.Backend.Entity -Prerelease

This will not give you access to the MongoDB or Azure Table Storage domain managers, if you want to work with those in the project run the following two commands.
Update-Package WindowsAzure.MobileServices.Backend.Storage -Prerelease
Update-Package WindowsAzure.MobileServices.Backend.Mongo -Prerelease

Note that you might have to restart Visual Studio to enable EntityFramework.6.1.0-beta1 to be fully installed.

Use Azure Table Storage from Mobile Service .NET Backend

The project comes preloaded with a TodoItemController that is configured to work with Azure SQL as backing storage. If we want to change this to work with Azure Table Storage you have to do the following changes.
Note this might not be the recommended way to do things, but since no sample code has been release yet, it was how I was able to get it working.

Initializing the StorageDomainManager

Instead of the EntityDomainManager in the TodoItemController we have to use the StorageDomainManager, if we want to save our data in Azure Table Storage. My Initialize method looks like this

    public class TodoItemController : TableController<TodoItem>
    {
        protected override void Initialize(HttpControllerContext controllerContext)
        {
            base.Initialize(controllerContext);
            MobileService1Context context = new MobileService1Context(Services.Settings.Schema);
            DomainManager = new StorageDomainManager<TodoItem>("AzureTable", "Todo", Request, Services);
        }

The construtor of the StorageDomainManager takes a name of a connection string (Azure Table Storage Connection string) and the name of the table to use (if the table doesn’t exists it will be created).
Here’s my connection strings from the web.config.

  <connectionStrings>
    <add name="MS_TableConnectionString" connectionString="Data Source=(localdb)\v11.0;AttachDbFilename=|DataDirectory|\aspnet-MobileService1-20140412092445.mdf;Initial Catalog=aspnet-MobileService1-20140412092445;Integrated Security=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
    <add name="AzureTable" connectionString="DefaultEndpointsProtocol=https;AccountName=sjkp;AccountKey=ahAKkscE3xXpMyFndLPgAzEdRWzc6CkNR8EL3zyllpziXGn4FkMmSKyANrS7WouavQtRpgkITBVUfRNDTgCow==;"/>
  </connectionStrings>

Inheriting from StorageData

Next up is fixing the TodoItem class so it works with the StorageDomainManager. Basically your DTO classes have to inherit from Microsoft.WindowsAzure.Storage.Table.TableEntity (to go into Azure Tables) and Microsoft.WindowsAzure.Mobile.Service.Tables.ITableData to work with the domain manager framework. There is a abstract class in the Mobile Services framework called StorageData, that I guess was design for working as a base class, unfortunately this class in version 1.0.258 of the framework have some design issues that makes it unsuited for this purpose. So instead I implemented my own base StorageData class that looks like this (It follows the same principles as the one of the framework, so once the framework is fixed feel free to change back to their implementation).

using System;
using Microsoft.WindowsAzure.Mobile.Service;
using Microsoft.WindowsAzure.Mobile.Service.Tables;
using Microsoft.WindowsAzure.Storage.Table;
using System.Text;

namespace MobileService1.DataObjects
{
    public class StorageData : TableEntity, ITableData
    {
        [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)
                {
                    throw new ArgumentException();
                }
                else
                {
                    this.PartitionKey = compositeTableKey.Segments[0];
                    this.RowKey = compositeTableKey.Segments[1];
                }
            }
        }
        [IgnoreProperty]
        public System.DateTimeOffset? UpdatedAt
        {
            get
            {
                return new DateTimeOffset?(this.Timestamp);
            }
            set { this.Timestamp = value.HasValue ? value.Value : DateTimeOffset.UtcNow; }
        }

        [IgnoreProperty]
        public byte[] Version
        {
            get
            {
                if (this.ETag == null)
                    return (byte[])null;
                else
                    return Encoding.UTF8.GetBytes(this.ETag);
            }
            set
            {
                this.ETag = value != null ? Encoding.UTF8.GetString(value) : (string)null;
            }
        }

        public System.DateTimeOffset? CreatedAt { get; set; }

        public bool Deleted { get; set; }
    }

    public class TodoItem : StorageData
    {     
        public string Text { get; set; }

        public bool Complete { get; set; }
    }
}

As you can see my TodoItem class simply inherits from my own StorageData.

Querying for Data

If you run the project locally now (and you have fixed your connection string to point to a working Azure Storage account) then you should be able to insert and update items in your Azure Table.

There’s a little quirk for making inserts, that is that your id should be of the format "'PartitionKey','RowKey'" where PartitionKey are exchanged with the PartitionKey you want and RowKey is exchanged by your rowkey that should be unique within the partition.
posttoazuremobileservice

However if you try to query for all items, you get the following exception
The 'StorageDomainManager' domain manager does not support 'IQueryable' for querying data. Please use the 'QueryAsync' method instead'
So what they are telling us, is that we cannot use the base method Query of the TableController. Instead we have to use QueryAsync, but when you try that, you will realise that the TableController doesn’t have that method, instead we need to use the QueryAsync directly of the StorageDomainManager. The reason why the Query method does not work is that Azure Table Storage only supports a limited subset of the OData query operators, so we are basically on our own.

It was a little hard for me to figure out how to use the QueryAsync on the StorageDomainManager, probably because I’m not an OData expert, but I found a solution that does work for now (It will probably fail once the number of rows of the table exceeds 1000 which is the maximum you can retrive from Azure Table storage without paging, but once I figure out how to solve that, or somebody else does, I will post an update here).

So my code for GetAllTodoItems() looks like this

 public Task<IEnumerable<TodoItem>> GetAllTodoItems()
        {
            var sm = DomainManager as StorageDomainManager<TodoItem>;
            ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
            modelBuilder.EntitySet<TodoItem>("TodoItems");
            var opts = new ODataQueryOptions(new ODataQueryContext(modelBuilder.GetEdmModel(), typeof(TodoItem)), Request);
            return DomainManager.QueryAsync(opts);
        }

The response of the GET request to /tables/TodoItem looks like this
mobileservicegetresponse

Conclusion

With these changes you should be able to use the Azure Mobile Service with a .NET backend and Azure Table Storage. Obviously this post proves that the Preview tag is well earned as some of these issues needs to get ironed out before it is ready to be used by developers that just wants a no-fuss backend for their mobile solutions, and prefer the .NET backend over the node.js backed.

Categories: Programming Software Windows Azure

Tagged as:

Simon J.K. Pedersen

12 replies

  1. Great article. As far as the 1000 row limit, I believe you will have to loop within your code if you want to return more than 1000.

  2. Thanks so much!
    I had to add a hack to the set property of Id to add a partition key if no comma exists in value. This was just to get around the sample help page.

    Also, I had to make this change in the controller:
    public Task<SingleResult> GetTodoItem(string id)
    {

    var result = DomainManager.LookupAsync(id);
    }
    and update references:
    Install-Package Microsoft.Data.Edm

    Update-Package Microsoft.Data.Edm -Prerelease

  3. You are right about the GetTodoItem(string id) – I didn’t test that in my original post. Thanks for letting me know.

  4. Hello, would you please post the solution for the id hack I could’nt make it to work with only partition key passed as id parameter.

    I got this error: “The key ’70’ is not valid. It must either be a single token representing a partition key or be a comma separated tuple representing a partition key and a row key.

    Thank you very much for this post, is the only source of using mobile services with azure storage, hope this changes 😉

  5. Hi Armando, I will post an update tomorrow. I heard that they are working on a new version, I’m not sure if it’s out yet. But it should fix the issues I mentioned in this post.

  6. Does your solution work when published to Windows Azure? I’ve it running with the local server but failing with a “TypeLoadException, ToDoItem on StorageDomainManager[TData] violates the constraint of type parameter ‘TData'” when the service is published to the cloud…

  7. Hi Simon,
    Thank you for the great write-up! A huge time-saver 🙂
    Seems like the casted Domain-Manager is never used in your GetAllTodoItems() method 🙂
    var sm = DomainManager as StorageDomainManager;

    I am currently testing as well and I am trying to implement all of the CRUD methods. During my test I discovered a interesting little class “CompositeTableKey” this should solve the problem passing an “ID” to some of the CRUD methods. It allows you to encapsulate the partition-key and the row-key and to use the ToString method to transform it into the right format. I assume that it can then be passed as the ID parameter.
    Cheers!

Leave a Reply

Your email address will not be published. Required fields are marked *