#.think.in
learn.create.enjoy

Import AntiGravity and I'll see you on Cloud Azure

February 21, 2009 00:03 by tarn

On the topic of setting up tables on Windows Azure Steve Marx writes

Probably the best solution is to have separate initialization code that creates your tables.  This is analogous to the pattern of having CREATE TABLE commands scripted in T-SQL which you run once to set up the database.

In another post Mark Seemann extends on this and demonstrates creating tables with a PowerShell script and writes

You could obviously write a little utility that references StorageClient and your custom TableStorageDataServiceContext.

Another, in my opinion, better option for such a one-off script is a PowerShell script

I agree but I think you can actually take this a lot further. In my experience working on enterprise applications it is also common to use one-off SQL scripts to add, update, maintain and manage data. The problem with this is you often have a very good ORM available which has logic to protect the state of the data and the business requirements. I feel that if you can also expose these business objects to a scripting environment, you potentially have a very powerful way of managing your enterprise information. This is probably even more relevant in the cloud data services where there is no equivalent of low level T-SQL you can optimize, you can have full control from scripting environment with the tools and armour of your enterprise objects.        

Anyway, enough rambling. In my previous post I demonstrated working with Azure table storage data in IronPython, and briefly glossed over creating the tables. In this post I'm going to walk through dynamically creating table in the cloud with IronPython and what currently needs to be done to get them working on the local development storage server. 

I'm going to create some of my own customs tables and some tables for the standard providers (Membership, Roles and Session) as I am building a simple MVC application for the cloud. I've got DataModels.dll with my custom models and the AspProviders.dll from the Azure SDK Samples with the standard provider models. All the models extend TableStorageEntity.

Both assemblies also extend TableStorageDataServiceContext classes which are similar to the DataContext class in Linq2Sql. They have IQueryable<T> fields templated to model classes, which represent tables. The base class has additional functionality for tracking, adding, deleting and saving model objects. We will be able to create tables by reflecting these TableStorageDataServiceContext classes.

 

Creating a database the local development storage server

Unfortunately a current restriction of the local development storage server is that you can't dynamically create tables. To create tables on the local development server the DevTableGen.exe tool is used.

DevTableGen /database:TarnsDevDB /forceCreate AspProviders.dll;DataModels.dll

Which should produce an output like below, indicating that the tables had been created. You can see the provider model tables and my custom tables have been created.

Windows(R) Azure(TM) Development Table database generation tool version 1.0.0.0
for Microsoft(R) .NET Framework 3.5
Copyright (c) Microsoft Corporation. All rights reserved.

DevTableGen : Generating database 'TarnsDevDB'
DevTableGen : Generating table 'Membership' for type 'Microsoft.Samples.ServiceHosting.AspProviders.MembershipRow'
DevTableGen : Generating table 'Roles' for type 'Microsoft.Samples.ServiceHosting.AspProviders.RoleRow'
DevTableGen : Generating table 'Sessions' for type 'Microsoft.Samples.ServiceHosting.AspProviders.SessionRow'
DevTableGen : Generating table 'PostTable' for type 'DataModels.PostDataModel'
DevTableGen : Generating table 'CommentTable' for type 'DataModels.PostDataModel 

UI for development storage server should be found in the task bar. As it only supports one concurrent database, you may have to select the database just created.

image

Dynamically managing a database in the cloud

I created a simple IronPython helper module to assist creating and managing the table schema in the cloud. Like in the previous post, it's built on the StorageClient library that ships with the Windows Azure SDK. You'll notice that its expecting the StorageClient assembly to be in one of its script paths.

There was some frustration writing it; All the TableStorageDataServiceContext classes are internal, this meant I had to write the LoadFromAssembly method and do some reflection to get the types.

import clr
clr.AddReference("StorageClient.dll")
from Microsoft.Samples.ServiceHosting.StorageClient import *
from System.Reflection import Assembly
from System import Uri

class Account():
   def __init__(self):
      self.endPointUri = Uri("http://127.0.0.1:10002/")
      self.accountName = 'devstoreaccount1'
      self.accountSharedKey = 'Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw=='

class TableHelper():
   def __init__(self, account):
      self.account = account
      self.storageInfo = StorageAccountInfo(account.endPointUri, None, account.accountName, account.accountSharedKey)
      self.tableStorage = TableStorage.Create(self.storageInfo)
   def AddTables(self, dataServiceContext):
      TableStorage.CreateTablesFromModel(dataServiceContext, self.storageInfo)
   def DeleteAllTables(self):
      for t in self.tableStorage.ListTables():
         self.tableStorage.DeleteTable(t)
   def PrintTables(self):
      for t in self.tableStorage.ListTables():         
         print t
   def LoadFromAssembly(self,assemblyName):
      # A bit of screwing round with reflection, because the types we want are internal
      assembly = Assembly.LoadFrom(assemblyName)
      baseType = TableStorageDataServiceContext
      contexts = filter(lambda t : t.BaseType == baseType, assembly.GetTypes())
      for context in contexts:
         print context
         self.AddTables(context)

Using this module we can easily create and manage tables from the IronPython interactive console, or with a script. Below is an example (with the credentials removed)

# load the helper module
from AzureTableHelper import *

# create an account and set creadentials
account = Account()
account.endPointUri = Uri('[Table Storage Url]')
account.accountSharedKey = '[Shared Key]'
account.accountName = '[Account Name]'

# create the helper with the account details
tableHelper = TableHelper(account)

# delete tables
tableHelper.DeleteAllTables()

# load tables from the AspProviders assembly 
tableHelper.LoadFromAssembly("AspProviders.dll")

# load tables from the DataModels assembly
tableHelper.LoadFromAssembly("DataModels.dll")

# print all the tables to the console
tableHelper.PrintTables()

There is a limitation of scripting tables this way as Mark Seemann notes,

Currently, the script has one limitation: Deleting a table using the StorageClient API only marks the table for deletion, so the operation returns much to soon. This means that if you are trying to recreate a table by the same name, a conflict will occur, and the table will not be created. You can work around this limitation by waiting a little while and then run the script again.

I think this part of the Azure framework is pretty exciting and I'm looking forward to checking out other parts.


Azure Table Storage in IronPython

February 20, 2009 14:14 by tarn

My goal was to write a bit of scaffolding to make using the storage service fun and easy from in IronPython. The Windows Azure SDK comes with a library in the samples which does the low level work interfacing with the API and provides some nice classes to work with. There are methods to generate table schemas by reflecting on model classes and another sample implements all the standard .NET providers.

I was hoping to write all the scaffolding and the model classes in IronPython but, in the first of a series of set backs, I found the development storage server behaves differently than the cloud. For some reason you need to create tables on the development storage server using a command line tool, passing your model assemblies as arguments. Apparently this will be fixed soon, but trying to stay focused I decided I'd have to write my models in C# for now.

Once I had an assembly with some models I could use the DevTableGen.exe command line tool that comes with the Azure SDK to create tables on my development storage server.

I don't think there are currently any good tools for visualizing and editing data, but I'm sure by the time its released it will integrate into Server Explorer and Query Analyzer (or perhaps it'll just be a Firefox plug-in). I've seen a presentation where HTTP requests are hand coded to retrieve data, but I wasn't up for that and tried importing the sample library into an IronPython console. I got enough working to convince me everything was going to work out, I just needed find out how to use extension methods in IronPython...

Much to my surprise and disappointment, consuming extension methods in IronPython is still difficult. There does appear to be a way to bind the extension methods, but I haven't seen an example binding all the Linq extension methods. This is a problem as it means Linq expression trees can't be easily built in IronPython. Passing expression trees as queries is ideal as the cloud can do the filtering, sorting and only return the data you want.   

I decided to put this problem on ice and write helpers in C# that returned a List<T> of all the rows. This won't work well with lots of data, but it will work find on small tables.

I wrapped the required credentials to connect to the service in an Account class, mainly so I could hard code the development credentials which are always the same.

public class Account
{
    public Uri EndPoint { get; set; }
    public String AccountName { get; set; }
    public String SharedKey { get; set; }

    public Account()
    {
        // development server defaults
        EndPoint = new Uri("http://127.0.0.1:10002/");
        AccountName = "devstoreaccount1";
        SharedKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
    }
}

I later I will try creating Models on the DLR, but for now I created them in a separate assembly using C#.

namespace DataModels
{
    public class PostDataModel : TableStorageEntity
    {
        public PostDataModel(string partitionKey, string rowKey)
            : base(partitionKey, rowKey)
        {
        }

        public PostDataModel()
            : base()
        {
            PartitionKey = Guid.NewGuid().ToString();
            RowKey = String.Empty;
        }


        public string Name
        {
            get;
            set;
        }

        public string Content
        {
            get;
            set;
        }

    }
}

A context is required that derives from TableStorageDataServiceContext, the field names in the context are used for table names and the type of the field describes the table row. The DataServiceContext works a bit like the LinqToSql data context keeping track of all the objects it returns.

namespace DataModels
{
    public class DataServiceContext : TableStorageDataServiceContext
    {
        public DataServiceContext(StorageAccountInfo accountInfo)
            : base(accountInfo)
        {
        }
        
        public IQueryable<PostDataModel> PostTable
        {
            get
            {
                return this.CreateQuery<PostDataModel>("PostTable");
            }
        }

        public IQueryable<PostDataModel> CommentTable
        {
            get
            {
                return this.CreateQuery<PostDataModel>("CommentTable");
            }
        }
    }
}

I wrote a generic model class to hide all the details and provide a simple wrapper to access create, read and select operations on a table. There's a couple of tests in the solution that demonstrate how this work, but basically you just need a custom context (V), a model (T) and table name. The generic model can then be used to insert, select and delete from the table.   

public class Model<T, V>
    where V : TableStorageDataServiceContext
{
    private V _context;
    public StorageAccountInfo AccountInfo { get; set; }
    public TableStorage TableStorage { get; set; }
    public string TableName { get; set; }

    public Model(Account account, string tableName)
    {
        TableName = tableName;
         AccountInfo = new StorageAccountInfo(account.EndPoint, null, account.AccountName, account.SharedKey);
         TableStorage = TableStorage.Create(AccountInfo);
         _context = Activator.CreateInstance(typeof(V), new object[] { AccountInfo } ) as V;  
    }

    public List<T> Select()
    {
        MethodInfo field = _context.GetType().GetMethods().Where(f => f.Name == "get_" + TableName).FirstOrDefault();
        if (field == null) return null; // field doesn't exist
        IQueryable<T> fieldValue = (field.Invoke(_context, null) as DataServiceQuery<T>);
        var results = from c in fieldValue select c;
        TableStorageDataServiceQuery<T> query = new TableStorageDataServiceQuery<T>(results as DataServiceQuery<T>);
        IEnumerable<T> queryResults = query.ExecuteAllWithRetries();
        return queryResults.ToList();
    }

    public void Insert(object item)
    {
        _context.AddObject(TableName, item);
        _context.SaveChanges();
    }

    public void Delete(object item)
    {
        // AttachTo is not required if the item was created by the context
        _context.DeleteObject(item);
        _context.SaveChanges();
    }
}

We've done all the C# code, now lets see how it can all be tied together in an IronPython console.

IronPython 2.0 (2.0.0.0) on .NET 2.0.50727.3053
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> # import everything we need
>>>
>>> import clr
>>> clr.AddReference("DataModels.dll")
>>> clr.AddReference("DataHelper.dll")
>>> clr.AddReference("StorageClient.dll")
>>> from DataModels import *
>>> from DataHelper import *
>>> from Microsoft.Samples.ServiceHosting.StorageClient import *
>>>
>>> # create a generic model, using the default account (development server)
>>>
>>> model = Model[PostDataModel, DataServiceContext](Account(), "PostTable")
>>>
>>> # now we can add some data rows
>>>
>>> for i in range(5):
...    post = PostDataModel()
...    post.Name = "Post Name " + str(i)
...    post.Content = "Some content for post" + str(i)
...    model.Insert(post)
...
>>>
>>> # we can now read them back
>>>
>>> for post in model.Select():
...    print "Name", post.Name
...
Name Post Name 3
Name Post Name 1
Name Post Name 2
Name Post Name 0
Name Post Name 4
>>>
>>> # delete them all
>>>
>>> for post in model.Select():
...    model.Delete(post)
...
>>>
>>> # and finally ensure they have all been removed
>>>
>>> for post in model.Select():
...    print "Name", post.Name
...
>>>
>>>

 

I'm pretty excited with how it all worked out, despite the setbacks. In future posts hopefully I'll have a go creating tables in the cloud with models and context created on the DLR. I will also try and resolve using Linq Extension Methods in IronPython which are essential to building complex queries to be executed in the cloud. I'm also writing a very simple Azure MVC weblog app which I'll hopefully finish soon.  

The project can be downloaded here and I've also uploaded just the compiled DataHelper assembly.

 

I found these links useful writing this post:

Windows Azure Essential Links

Walkthrough: Simple Table Storage

Creating Azure Tables From Script


Liberation Day - Power To Developers

November 13, 2008 22:40 by tarn

image I'm not in anyway formally associated Microsoft other than that I've been primarily using their tools to develop software for the over the last few years, so I was a little excited I was invited to Liberation Day in Sydney after placing 2nd in DevSta. I thought it would be great to see Steve Ballmer, infamous for this famous clip and this. He is, of course, also the Microsoft CEO and was going to announce Azure the new Microsoft cloud computing platform. He was sure to be entertaining anyway.

As I'd never been to Sydney I decided I could spend a couple of days on Bondi Beach with my girlfriend and drop into the conference and while I was there. I'm expecting to be looking for a new job from next year, probably not in Sydney, but I thought it would also be good to see who was there and meet a few people anyway. I was expecting there would be a couple of DevSta judges there too.

 

There were heaps of people at the event, I wouldn't be surprised if there actually was the 1000 developers the flyer claimed there would be. It was cool, I can't image an event with that many developers in Melbourne. It was streamed live and can be replayed on the Power To Developers site. I watched Steve get up and do his thing, and it was fun, not rock'n'roll, but fun. Unfortunately I wasn't feeling very well, almost feverish, and I had to duck out to find a chemist.

Gianpaolo Carraro's presentation attempted to demonstrate how easy developing cloud solutions for the Azure was with Visual Studios 2008. I thought it was pretty cool despite most of his demos failing in ways he couldn't have imagined. The Azure platform sounded pretty awesome, basically allowing custom .Net assemblies to be uploaded and invoked on Microsoft servers. He also managed to successfully demonstrate the cloud emulator for locally running and debugging cloud applications. I also really like the idea of being able to a write LINQ query joining two data tables from a SQL Server Service in the cloud.

Mike Culver presented the Amazon Web Services cloud solutions to the Vic.NET user group about a year ago and I think he sold their technology and the possibilities better. He showed the architecture of a video compression service that used a message queue service to queue requests and a controller application that can automatically rent, build and deploy servers capable of processing the requests. I thought it was pretty cool. I think Microsoft are a long way behind, but we'll see what the software giant is capable of. I'm certainly keen to get in and give it a go.

I still wasn't feeling well and missed most of Tim Sneath which was a shame, Brodie had seen him in London years ago but said he "knew his stuff". At the networking drinks I chatted with Michael Kordahi which was kind of fun, he'd judged my entry and he is a Silverlight guy. He introduced me to a couple of people, one of which was Jeremi Kelaher who does Strange Devices Podcasts. I also ran into Tatham Oddie on the way out who I'd seen present MVC stuff at REMIX and Vic.NET. I would have liked to have chatted with Andrew Coates who is a great presenter and was also a DevSta judge, but I didn't end up seeing him this time.


Tags:
Categories: Reviews
Comments (0)