Demonstrating ASP.NET+SQL App Migration to Windows Azure

Quite a number of times, I have been asked how hard it actually is to move an existing ASP.NET+SQL Server application over to Windows Azure. My response to this is generally the a classic "it depends" - provided there are no major pitfalls in the application architecture, it is a straight-forward exercise to perform this transition.

So much for the talk, but what is actually involved in doing this? I knew the theory, had it all mapped out in my head, but it was time to really go for it and demonstrate it. The only requirement was that this needed to be done within a couple of minutes, so don’t be expecting anything fancy or even remotely useful.

Part 1 – Start with a simple data-driven web application

So, the first thing to do was to create a sample application that includes some interaction with an “on-premise” database. The database, I got from here: msftdbprodsamples.codeplex.com/releases/view/55926 – just your stock-standard AdventureWorks database.

Now for the application itself. I decided to go for a simple data-grid showing the customer data from above database. So I went to Visual Studio and created a new ASP.NET web project:

image

Then, I added a GridView control to the Default.aspx page, specifying the Customers table and selecting some data from there.

Code-wise, this ends up like this in the ASPX page:

    1: <asp:GridView ID="GridView1" runat="server" CellPadding="4" 
    2:     DataSourceID="AdvWorks" ForeColor="#333333" GridLines="None" 
    3:     AutoGenerateColumns="False" DataKeyNames="CustomerID">
    4:     <AlternatingRowStyle BackColor="White" ForeColor="#284775" />
    5:     <Columns>
    6:         <asp:BoundField DataField="CustomerID" HeaderText="CustomerID" 
    7:             InsertVisible="False" ReadOnly="True" SortExpression="CustomerID" />
    8:         <asp:BoundField DataField="CompanyName" HeaderText="CompanyName" 
    9:             SortExpression="CompanyName" />
   10:         <asp:BoundField DataField="Title" HeaderText="Title" SortExpression="Title" />
   11:         <asp:BoundField DataField="FirstName" HeaderText="FirstName" 
   12:             SortExpression="FirstName" />
   13:         <asp:BoundField DataField="MiddleName" HeaderText="MiddleName" 
   14:             SortExpression="MiddleName" />
   15:         <asp:BoundField DataField="LastName" HeaderText="LastName" 
   16:             SortExpression="LastName" />
   17:         <asp:BoundField DataField="EmailAddress" HeaderText="EmailAddress" 
   18:             SortExpression="EmailAddress" />
   19:     </Columns>
   20:     <EditRowStyle BackColor="#999999" />
   21:     <FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
   22:     <HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
   23:     <PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" />
   24:     <RowStyle BackColor="#F7F6F3" ForeColor="#333333" />
   25:     <SelectedRowStyle BackColor="#E2DED6" Font-Bold="True" ForeColor="#333333" />
   26:     <SortedAscendingCellStyle BackColor="#E9E7E2" />
   27:     <SortedAscendingHeaderStyle BackColor="#506C8C" />
   28:     <SortedDescendingCellStyle BackColor="#FFFDF8" />
   29:     <SortedDescendingHeaderStyle BackColor="#6F8DAE" />
   30: </asp:GridView>
   31: <asp:SqlDataSource ID="AdvWorks" runat="server" 
   32:     ConnectionString="<%$ ConnectionStrings:AdvWorksConnectionString %>" 
   33:     SelectCommand="SELECT [CustomerID], [CompanyName], [Title], [FirstName], [MiddleName], [LastName], [EmailAddress] FROM [SalesLT].[Customer]">
   34: </asp:SqlDataSource>
   35: <asp:SqlDataSource ID="SqlDataSource1" runat="server"></asp:SqlDataSource>

  

In web.config, you will then find the Data Source defined:

 

    1: <connectionStrings>
    2:   <add name="ApplicationServices" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnetdb.mdf;User Instance=true"
    3:     providerName="System.Data.SqlClient" />
    4:   <add name="AdvWorksConnectionString" 
    5:        connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=AdventureWorksLT2008R2;Integrated Security=True"
    6:     providerName="System.Data.SqlClient" />
    7: </connectionStrings>

 

Note that I will not be needing the “ApplicationServices” connection string in this sample – this will continue to sit as-is.

Hitting <F5> verifies that this actually works as expected.

image

Part 2 – The Journey to Azure

When moving a data-driven application to Windows Azure, I generally recommend doing this in two steps – one for the Database and the other for the application itself. That way, you can more easily identify where a potential problem lies. If you move it all up in one go, it will be hard to discern between application-related and data-related issues.

While it is theoretically possible to move the application first, it is a lot easier to begin with the database, as it is very easy to access SQL Azure from an on-premise IIS, but accessing an on-premise SQL Server from a Windows Azure application involves some extra plumbing.

Step 2.1 – Migrating the database and testing the connection

For the database migration, I use the SQL Azure Migration Wizard from codeplex (<sqlazuremw.codeplex.com/>). This will adjust the schema to a SQL Azure-friendly form and alert me to any issues that may occur in the process.

The Wizard actually did come up with a few errors and warnings, like:

 XML Schema Collections are currently not supported in SQL Azure
The following XML Schema Collections were found:

[SalesLT].[ProductDescriptionSchemaCollection]

None of the errors or warnings are critical to my project, so I went ahead and allowed the Wizard to create me a new database called “AdvWorks” in my SQL Azure subscription.

In a real-life scenario, of course, the impact of the errors and warnings would need to be properly evaluated and might involve some code change in the application to circumvent.

In order to demonstrate that switching the database actually does anything, I then pulled up SQL Server Management Studio to slightly modify the data on the SQL Azure side:

    1:  UPDATE [AdvWorks].[SalesLT].[Customer]
    2:     SET [MiddleName] = 'AZURE'
    3:  GO

Every Customer on the Azure side will now show up with a Middle Name of “AZURE”.

So the only thing that remained to be done is to change the connection string in my web.config:

    1: <add name="AdvWorksConnectionString" 
    2:      connectionString="Server=tcp:[SERVER].database.windows.net,1433;Database=AdvWorks;User ID=[USER]@[SERVER];Password=[PASSWORD];Trusted_Connection=False;Encrypt=True;"
    3:   providerName="System.Data.SqlClient" />

(change [SERVER], [USER] and [PASSWORD] to whatever is applicable on your SQL Azure server)

Running this showed exactly what I would have hoped for – everyone now goes for a fancy new middle name:

image

Step 2.2 – Migrating the Web Application

For this, I simply added a new Windows Azure Cloud project to my solution:

image

in the next screen, I simply pressed “Next” as I didn’t need any additional Azure roles.

The Azure project automatically became the new StartUp project and I could right-click the “Roles” node in that project and select “Web Role Project in Solution…”, which brought up this dialog:

image

Adding this created the required wiring for a standard HTTP port and needed no additional tweaking. Hitting <F5> again ran the same project, but now inside the Windows Azure Compute Emulator on my machine:

image

Apart from the URL, no difference to the previous step and that’s exactly what we want.

Now, all that was needed was to deploy this to Windows Azure. This yielded exactly the same result, just delivered directly from our Cloud Servers.

Part 3 – Additional optional steps

What remains to be done are things like:

  • Add AppFabric Caching as ASP.NET Session State provider for scalability
  • Clean up any additional things (file management to blob storage; consider table storage; etc.)

Yes, I know – oversimplification on that last item, but the point is made – the core part of moving a data-driven ASP.NET application to Windows Azure is no real issue in itself and can happen quite rapidly. The devil may be in the detail, but there is no rocket science involved in the groundwork.