Logo

Maarten Balliauw {blog}

ASP.NET, ASP.NET MVC, Azure, PHP, OpenXML, VSTS, ...

About the author

Maarten Balliauw is currently employed as .NET Technical Consultant at RealDolmen. His interests are mainly web applications developed in ASP.NET (C#) or PHP and the Windows Azure cloud platform.
More about me More about me
Send mail E-mail me


ASP.NET MVC Quickly Subscribe to my RSS feed Follow me on Twitter! View Maarten Balliauw's profile on LinkedIn
View Maarten Balliauw's MVP profile

Search

Latest Twitter

    Follow me on Twitter...

    My projects

    Disclaimer

    The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

    © Copyright Maarten Balliauw 2010

    CarTrackr on Windows Azure - Part 3 - Data storage

    This post is part 3 of my series on Windows Azure, in which I'll try to convert my ASP.NET MVC application into a cloud application. The current post is all about implementing cloud storage in CarTrackr.

    Other parts:

    Types of Azure storage

    Windows Azure offers 3 types of cloud storage: blobs, tables and queues. Blob Storage stores sets of binary data, organized in containers of your storage account. Table Storage offers structured storage in the form of tables. The Queue service stores an unlimited number of messages, each of which can be up to 8 KB in size.

    Windows Azure Storage Account

    CarTrackr will use table storage to store cars and refuellings. Table Storage is one of the simplest way to store data in Azure. All tables are accessed using a Uri in the form of http://<applicationname>.tables.core.windows.net. You need to have a storage cccount if you want to use the table storage. Waiting for an invitation? The Azure SDK contains a development storage tool which simulates all cloud table storage features on your local host: http://127.0.0.1:10002

    Each storage account has a Table containg an Entity. An Entity contains Columns. Entity can be considered to be the row and Columns as values. Each Entity always contains these properties: PartitionKey, RowKey and Timestamp . The PartitionKey and RowKey identify a row or an Entity. (source)

    Implementing Azure TableStorage in CarTrackr

    Configuring TableStorage

    First of all, we have to specify we are going to use storage in the CarTrackr application. This can be achieved by adding some configuration to the CarTrackr_Azure's ServiceConfiguration.cscfg:

    <?xml version="1.0"?>
    <ServiceConfiguration serviceName="CarTrackr_Azure" xmlns=""http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration"">http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration">
      <Role name="Web">
        <Instances count="1" />
        <ConfigurationSettings>
          <Setting name="AccountName" value="devstoreaccount1"/>
          <Setting name="AccountSharedKey" value="Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw=="/>
          <Setting name="TableStorageEndpoint" value=""http://127.0.0.1:10002"/">http://127.0.0.1:10002"/>
        </ConfigurationSettings>
      </Role>
    </ServiceConfiguration>

    When deploying, we should of course change the TableStorageEndpoint to the Azure TableStorage endpoint. Account name and key should also be modified at that moment.

    Development storage

    Making sure all tables exist in TableStorage

    To make sure all tables exist in TableStorage, a TableStorageDataServiceContext should be defined. This TableStorageDataServiceContext should contain some TableStorageEntity items. We can easily make all domain objects in CarTrackr of type TableStorageEntity. Make sure to build the samples in the Azure SDK folder and add a reference to the StorageClient.dll in that folder.

    Creating a class that is TableStorage aware is easy now: inherit the Microsoft.Samples.ServiceHosting.StorageClient.Microsoft.Samples.ServiceHosting.StorageClient class, modify the constructor and you're done. I've also modified the domain classes, making RowKey the identifier for the current object.

    namespace CarTrackr.Domain
    {
        public partial class Car : TableStorageEntity, IRuleEntity
        {
            public Car()
                : base()
            {
                PartitionKey = Guid.NewGuid().ToString();
                RowKey = Guid.NewGuid().ToString();
            }

            // ... other code ...
        }
    }

    Also add the CarTrackrCloudContext class to the CarTrackr.Data namespace. This CarTrackrCloudContext class will implement a TableStorageDataServiceContext, defining which tables are in the TableStorage.

    using System.Data.Services.Client;
    using CarTrackr.Domain;
    using Microsoft.Samples.ServiceHosting.StorageClient;

    namespace CarTrackr.Data
    {
        public class CarTrackrCloudContext : TableStorageDataServiceContext
        {
            public DataServiceQuery<Car> Cars
            {
                get
                {
                    return CreateQuery<Car>("Cars");
                }
            }

            public DataServiceQuery<Refuelling> Refuellings
            {
                get
                {
                    return CreateQuery<Refuelling>("Refuellings");
                }
            }

            public DataServiceQuery<User> Users
            {
                get
                {
                    return CreateQuery<User>("Users");
                }
            }
        }
    }

    This CarTrackrCloudContext tells the application there are 3 types of tables, represented by 3 domain class types. Note that the class has been inherited from TableStorageDataServiceContext, which automatically connects to the TableStorage endpoint with the account information we stored previously in the Service Configuration file.

    To make sure tables exist and are up to date when the application is started, add the following to CarTrackr's Global.asax:

    protected static bool tablesRegistered = false;
    protected static object syncLock = "";

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        if (!tablesRegistered)
        {
            lock (syncLock)
            {
                if (!tablesRegistered)
                {
                    try {
                        StorageAccountInfo account = StorageAccountInfo.GetDefaultTableStorageAccountFromConfiguration();
                        TableStorage.CreateTablesFromModel(typeof(CarTrackr.Data.CarTrackrCloudContext), account);
                        tablesRegistered = true;
                    }
                    catch { }
                }
            }
        }
    }

    The TableStorage client will create all requried tables based on the CarTrackrCloudContext class's IQueryable properties. Note that I'm using double-check locking here to make sure tables are only created once (performance). 

    Querying data

    Luckily, my repository code is not subject to much changes. Linq queries just keep working on the Azure TableStorage. Only Insert, Update and Delete are a little bit different. The CarTrackrCloudContext class represents the runtime context of ADO.NET Data Services and enables to use AddObject(), DeleteObject(), UpdateObject(), followed by SaveChanges().

    Here's an example on adding a Car (CarRepository):

    public void Add(Car car)
    {
        if (car.OwnerId == Guid.Empty)
            car.OwnerId = User.UserId;

        car.EnsureValid();

        DataSource.DataContext.AddObject("Cars", car);
        DataSource.DataContext.SaveChanges();
    }

    Storage conclusions

    I have actually modified my Linq to SQL classes and repository code as TableStorage currently only supports Binary, Bool, DateTime, Double, Guid, Int, Long and String. No decimals and custom types anymore... There's also some other missing features regarding ordering of data and joins which required me to change a lot of repository code. But hey, it's still only the repository code I needed to change!

    Next post will be about membership and authentication. Stay tuned!

    kick it on DotNetKicks.com


    Categories: ASP.NET | Azure | C# | General | MVC

    Comments

    alvinashcraft.com | Reply

    Wednesday, December 17, 2008 4:22 PM

    pingback

    Pingback from alvinashcraft.com

    Dew Drop – December 17, 2008 | Alvin Ashcraft's Morning Dew

    code-inside.de | Reply

    Thursday, January 15, 2009 1:37 AM

    pingback

    Pingback from code-inside.de

    HowTo: Einstieg in "Cloud-Computing" | Code-Inside Blog

    Add comment




      Country flag

    biuquote
    • Comment
    • Preview
    Loading