Sunday, March 10, 2013

Azure Lessons Learned

I've been working to get my first real Azure web application working and I've got to the point where I want to record some of the lessons learned.  Most of this is documented elsewhere on the web, but the information is scattered and it took me awhile to find it and to work out what it really meant.

Lesson 1 - Web Application Projects work but Web Site Projects don't

If you have one of those old-fashioned web site projects (where the name of the project equals the name of the web URL), you'll need to convert it to a real web application.  The wizard that creates the Azure deployment project won't recognize the web site project.

Converting a web site project is kind of a pain.  The best approach seems to go like this:
  • Create a new web application project.
  • Copy the source files from the web site project to the web app project.
  • On each aspx page, right-click and use the "Convert to Web Application" option.
  • There are subtle differences in the global.asax file.  In web site projects, the application start, stop and other events are inline in a script block.  In a web application project, they are in code behind.
Lesson 2 - Web Apps that need to persistent local storage need custom code

If your web application reads and writes local files, it will need a little custom code.  The web app I was working on allowed users to upload files which were then edited and saved in local file storage.

In Azure web applications, local file storage is wiped clean every time the application is restarted or redeployed.  If you want the files added or changed by the web application to survive, you need to do something.

The good news is that there's a solution.  The bad news is it's a bit of a hassle and requires a deeper knowledge of how Azure works that I would have hoped.  Here's an outline of the solution:
  • You can mount a virtual hard disk (VHD) in Azure.  This VHD can be stored in a persistent blob store in a file type called a Page Blob.
  • Microsoft didn't provide a way to automatically provision VHDs in the role configuration (so far as I can tell). This means you have to write code.
  • The code to mount the VHD goes into either into:
    • A class derived from RoleEntryPoit
    • The application start in Global.asax (this seems to be Microsoft's recommendation)
  • The main reason code is necessary is that the Azure determines the drive letter at runtime an the letter may be different for each deployment.  Entries in web.config or role configuration settings won't work.
  • There are several decent code samples on the web for this. (link 1) (link 2) (link 3)
  • If the application uses virtual directories that are mapped outside the main application folder (presumably onto the mapped drives), you'll need to write more code. This code is tricker to write because it needs to run under elevetated privileges.
  • The VHD used by Azure is compatible with Windows 7 and Server 2008.  With a little care, you can bulk load your data locally and upload it to Azure. 
  • There are some Windows Explorer-like tools for uploading files to Azure storage.
Lesson 3 - Use Role config settings instead of web.config

In my case, I wanted the web application to continue to work in a "real" web application setting as well as Azure.  To do this, you'll probably want to write a bit of code to determine the running environment (Web or Azure).  If the code is running outside Azure, use the web.config file.  If the code is running in Azure, use the role settings instead.

Using role settings works better because it comes with local and Clould configuration settings. You'll want to use different settings when your running in the Azure Compute Emulator than when you're running in the real cloud.

This means you'll need three sets of app settings; one for regular web servers, one for the local Azure emulator and one for the production (Cloud) deployment.

Lesson 4 - The Azure SQL Database is a subset of a "real" SQL server.

The first thing I noticed is that every table must have a primary CLUSTERED key.  You can create tables without them, but you'll get an error the first time you try to insert a record.  This little gem means that you can't just port any old SQL database to Azure SQL.  It will probably need to be changed.

While you can connect to an Azure SQL Database with SQL Server Management Studio, much of the functionality you'd expect is missing.  Here's partial list of things that you can't do:
  • You can't create regular SQL server backups.  You can't restore a backup taken from a "real" SQL server to an Azure SQL either.
  • You can't design tables, views or stored procedures
  • You can't do "Edit first 200 rows"
  • You can't take the database offline
There is a SQL management tool in the Azure Management site, but it's, well, it's wierd and I still haven't figured it out.

Lesson 5 - Migrating an Existing SQL Database Takes Work

Here's the process I settled on:
  • Using a data modeling tool, reverse engineer the existing database and use the tool to build the SQL that generates the schema of the new database.  I did this because changes to the schema (to create missing PK clustered indexes) were necessasry.  The tool I use has a way to manage a somewhat more abstract data model and connect it with multiple physical implementations.  This allows me to maintain the "real" SQL server model and the Azure model in the same project.
  • Migrate the data using SSIS (or Export Data in SQL Server Management Studio).  Using SSIS makes it possible to handle items such tables with Text or Blob fields. 
There are other approaches (described here)