Friday, January 27, 2012

Taking a Fresh Look at the Windows Azure Development Experience

Windows Azure has grown up over the years since it first debuted in late 2008. In this article we're going to take an updated look at what the cloud developer experience is with Windows Azure today. Here's what we'll cover, which will include a walk-through of developing a cloud application:
  • Key Online Resources
  • What You Need for Cloud Development
  • The Cloud Development Lifecycle
  • Application Development Walk-through

Key Online Resources
Azure.com
You can't be an effective developer these days without knowing where your online lifelines are! In Windows Azure, that's been made easy by giving you one place to find just about everything: Azure.com. Here are some of the things you can do there:
  • Set up an account or a 90-day free trial account
  • Estimate your operation costs with a pricing calculator
  • See your current and past billing activity
  • Visit a developer center
  • Download an SDK
  • Find documentation
  • Go to community forums
  • Go to the Windows Azure Management Portal to manage your cloud solutions

Whether you work in C# in Visual Studio or Java or PHP in Eclipse, Microsoft wants developers of all stripes to be able to use the Windows Azure platform. The Developer Centeron Azure.com lets you select your preferrred language/platform and gives you information relevant to the way you want to work.

Windows Azure Management Portal
The Windows Azure Management Portal is where you provision cloud services, manage and deploy your solutions, and view status. You can get here by clicking the Manage link on Azure.com, or by navigating directly to windows.azure.com.


What You Need for Cloud Development
Let's review what you need in order to develop for Windows Azure. You will typically develop and testing your solution locally (using a simulator) before you deploy to a cloud data center.

To Develop Locally
You will need the following in order to develop locally:
  • A Windows PC (running Windows Vista or later, WIndows 7 recommended)
  • A development environment, such as Visual Studio or Eclipse
  • The Windows Azure SDK (download from Azure.com), which includes the Windows Azure Simulation Environment
  • SQL Server Express
To Deploy and Run in the Cloud
You will need the following in order to deploy to a Windows Azure data center:
  • A Windows Azure account (note there is a 90-trial available, and if you have an MSDN subscription that will also give you some free hours)
The Cloud Development Lifecycle
In Windows Azure, the pattern is to develop and test locally as much as you can before deploying to the cloud. Once you're ready to run in the cloud, it's typical with the Compute service to first deploy to a Staging slot, test the solution in the cloud, and finally promote from Staging to Production (a one-click operation). After that, you allow people use your application, monitor and manage activity, and scale scale as needed if demand changes.

Eventually you'll want to change something in your solution and then the process repeats. In an upgrade situation, promotion Staging to Production is actually swapping them. This allows you to leave the older deployment in Staging until you're sure Production is working as it should, then you can remove it.

Application Development Walk-through
To illustrate what development is like, let's walk through provisoning, developing, testing, and deploying a cloud solution.

What We'll Build: T-Shirt World
In this example we'll build a simple order entry and order processing application named T-Shirt World. This is a rather simple application--nothing to write home about!--but it's more than a mere Hello, Cloud: it has a front end and a back end, and will make use of multple cloud services.


Activity Flow
There's a 4-step sequence of activity in T-Shirt World:
  1. Submit an Order
  2. Queue the Order
  3. Dequeue the Order
  4. Store the Order in a Database
The first two steps happen on the front end, a web page (what we call a Web Role). The last two steps happen on the back end, in a worker process (what we call a Worker Role).


Cloud Services We'll be Using
Any cloud solution you create is likely to use multiple Windows Azure services. We're going to make use of four Windows Azure services in this sample application:
  • Windows Azure Compute - hosts the web role (site) and worker role (back end process)
  • Windows Azure Storage - image files for the web site
  • Service Bus - we'll use a queue to route orders from front end to back end
  • SQL Azure Database - order records

Walk-through Step 1: Service Provisioning
We'll provision the services we're going to use up-front. Stricly speaking, this isn't necessary to do until later since the Compute, Storage, or Database service are available to you locally in the Windows Azure Simulation Environment. However, there's no local simulation of one of the service we're going to be using, the Service Bus, so we'll provision everything here and now.

Provisioning Hosted Service
In Windows Azure parlance, a Hosted Service is a project workspace in the Compute service that executes, such as a web site. We go to the Windows Azure Management Portal in our browser and navigate to the Hosted Services area, then click the New Hosted Service toolbar button. We fill in a dialog where we choose a name for the service, a unique DNS prefix, and select one of 6 data center locations. We'll use the name tshirtworld for our hosted service and select the South Central US data center.

After a minute or so the service is provisioned and appears in the portal. Here's how the service will look in the portal later on, once we have deployed our solution to its Production slot:


Provisioning a Storage Account
We want a place to keep web site images, so we will next provision a storage account for the Windows Azure Storage service which includes blob storage. Blobs are similar to files and can be accessed as Internet URIs. To provision a storage account, we navigate to the Storage Accounts area of the portal and click the New Storage Account button. In a dialog we specify a name for the account, a unique DNS prefix, and a data center locaton. We'll use the name tshirtworld for our storage account and again select the South Central US data center, as we want to keep all of our services in the same location for performance reasons.


After a minute or so the storage account is provisioned. Here's how it looks in the management portal:


Provisioning a Database Server
We want to store orders in a database, so we will provision a SQL Azure Database. To do that we first need to provision a virtual database server, and afterward we'll go on to provision a database for that server.

To create the "server" (there are actually 3 behind the scenes for redundancy), we click the Create Server toolbar button. As we walk through the multi-screen dialog we are choosing a data center location, specifying admin user credentials, and setting up firewall rules.We'll again select the South Central US data center.


Soon we have a database server. Unlike most of these other provisioning activities where we get to choose meaningful names, the database server is a cryptic, generated name ("lcuh7n0fna" in our case). Here's how the database server looks in the portal once we've provisioned it:


Provisioning a Database
We've just created a database server, now we need to create the database itself. Selecting the database server we just created, we click the New Database toolbar button and (you guessed it) fill in a dialog. We get to specify a name for the database--we'll use tshirtworld, of course--and a size (1-150GB).We'll choose the 1GB size.


Here's how our databaes appears in the management portal once it's been provisioned:


Provisioning a Service Bus Namespace
We'll be using the Service Bus for a durable queue that connects our front end and our back end to communicate newly submitted orders that are ready for processing. In the Service Bus area of the management portal, we click the New Service Bus Namespace toolbar button.


Once the namespace is provisioned, here's how it looks in the managment portal.


Credentials and Connection Strings
We now have our services provisioned. Many of them require us to specify credentials or a connection string in our code in order to use them. You retrieve this information from the management portal.


Walk-through Step 2: Create Solution
Now it's time to create our solution. We'll be using C#, the .NET Framework, and Visual Studio in this case but as previously mentioned you have the option of using many languages and development environments with Windows Azure.

Creating a Windows Azure Project
We'll create our solution by selecting File > New Project. Because we've previously installed the Windows Azure SDK and Tools for Visual Studio, we have a Cloud category and a Windows Azure Project template. We'll select that project template and name our solution Orders.


The project template puts us in a wizard to select projects for our roles. A role in Windows Azure Compute is a tier of your application. Here we want two roles, one for our front end and one for our back end. A Web Role is the appropriate container for our web site, it will give us a load-balanced HTTP endpoint and IIS. We want to use ASP.NET, so we select an "ASP.NET Web Role" in the wizard. For the back end, we can use a Worker Role which is similar to a .NET console program or a Windows Service. With our two roles identified, we click OK to generate a solution.

You might expect that the generated solution will have 2 projects, one for the web role and one for the worker role, but there are in fact 3 projects: a Windows Azure solution also includes a Windows Azure project that contains metadata. This metadata describes the shape of your application to the cloud data center (how many roles does it have? what kind of roles are they? what endpoints do you need?) as well as configuration information (what size VMs do you need, and how many?).






Using the Windows Azure Simulation Environment
Before we write any code, let's see what it's like to use the local Windows Azure Simulation Environment. This is integrated with Visual Studio, so all we have to do is press F5 and presto, we're running in the simulator. Let's do that now.

One hint that we're running in the simulator is the web address: 127.0.0.1:81. But we can see more, the simulation environment has a UI for its Compute Emulator. To bring that up, we find the blue Windows Azure system tray icon at the lower right of our desktop, right click, and select Show Compute Emulator UI. This give us an insightful view of our roles and VM instances. At the moment, we only have 1 web role VM instance and one worker role instance, but later we'll increase that.

Now that we've seen the simulator, let's stop the solution running in Visual Studio and proceed to implement our application. We could also use the simulator for storage and database, but since we've already provisioned those in the cloud we're just going to consume those services directly in this walk-through.

Walk-through Step 3: Using the Compute Service
Let's move forward in time and imagine that we've implemented an order entry form in HTML and CSS:


Before we launch this, let's up the number of web role instance from 1 to 2. We can do this by editing the ServiceConfiguration..cscfg file in the Windows Azure Project. There are two versions of this file, a local one and a cloud one. The local one applies to the simulator, the cloud one to an actual cloud deployment.


Now we can hit F5 to again launch the solution. Now we see our web form in the browser.


If we again launch the Compute Emulator UI, we see now that the web role has 2 instances because of the configuration change we made:

 

Let's stop the solution and proceed to look at storage next.

Walk-through Step 4: Using the Storage Service
Our web site has images of T-Shirts, and while we could just add those images to the ASP.NET project let's assume we'd like them to be dynamic and easily changeable. To accomplish that, we can use blob storage.

If you go back and look at the web solution, the images are not in the solution. Instead the HTML/CSS page references URIs like "tshirtworld.blob.core.windows.net/images/black-tshirt.png". This reflects that we're using blob storage. The URL format includes our storage account endpoint (tshirtworld.blob.core.windows.net), the path to our container (images), and the blob names (such as black-tshirt.png).


We put the images in storage using a storage tool--we'll use Azure Storage Explorer here, which is free. Cloud Storage Studio is also popular. We've created a blob container named images and we've uploaded our T-shirt image files to it. Because the images container was configured for public access, these image files can be accessed as Internet URIs. That allows us to referene them in our web page.



Walk-through Step 5: Using the Service Bus
Now we want to capture a submitted order and pass it to our back end for processing. We can use a queue for that. We have two kinds of queues available in Windows Azure: simple queues (part of the Storage service) or deluxe enterprise-class queues (part of the Service Bus service). We'll use a Service Bus Queue here.

In our web server code, when an order is submitted our handler will collect the order fields from the web form, construct an order message, and queue it. The code looks like this, and it uses credentials from the Service Bus namespace we set up when we provisioned our cloud services You might choose to put your order information in the body of the message (say in XML or JSON), or in message properties. We've actually done both below so you can compare them. Message properties are useful because you could filter on them for example to separate processing of air ship orders from ground ship orders.
protected void Submit_Click(object sender, EventArgs e)
{
    try
    {
        tP = TokenProvider.CreateSharedSecretTokenProvider(issuer, key);

        Uri uri = ServiceBusEnvironment.CreateServiceUri("sb", serviceBusNamespace, string.Empty);

        namespaceManager = new NamespaceManager(uri, tP);

        MessagingFactory factory = MessagingFactory.Create(uri, tP);
        MessageSender messageSender = factory.CreateMessageSender(queueName);

        string name = Request.Form["name"];
        string email = Request.Form["email"];
        string phone = Request.Form["phone"];
        string address = Request.Form["address"];
        string city = Request.Form["city"];
        string state = Request.Form["state"];
        string postalCode = Request.Form["postalcode"];
        string country = Request.Form["country"];
        string color = Request.Form["color"];
        string cardNumber = Request.Form["cardnumber"];
        string securityCode = Request.Form["secure"];
        string nameOnCard = Request.Form["namecard"];

        if (String.IsNullOrEmpty(name))
        {
            Status.Text = "Name is required";
            return;
        }

        if (String.IsNullOrEmpty(email))
        {
            Status.Text = "Email is required";
            return;
        }

        if (String.IsNullOrEmpty(phone))
        {
            Status.Text = "Phone is required";
            return;
        }

        BrokeredMessage message = new BrokeredMessage(
            String.Format("<Order><Name>{0}</Name><Email>{1}</Email><Phone>{2}</Phone><Address><Street>{3}</Street><City>{4}</City><State>{5}</State><PostalCode>{6}</PostalCode><Country>{7}</Country></Address><Color>{8}</Color><Card number=\"{9}\" securityCode=\"{10}\" nameOnCard=\"{11}\"/></Order>",
                name, email, phone, address, city, state, postalCode, country, color, cardNumber, securityCode, nameOnCard)
        );

        message.Properties["Name"] = name;
        message.Properties["Email"] = email;
        message.Properties["Phone"] = phone;
        message.Properties["Address"] = address;
        message.Properties["City"] = city;
        message.Properties["State"] = state;
        message.Properties["PostalCode"] = postalCode;
        message.Properties["Country"] = country;
        message.Properties["Color"] = color;
        message.Properties["CardNumber"] = cardNumber;
        message.Properties["SecurityCode"] = securityCode;
        message.Properties["NameOnCard"] = nameOnCard;

        // Send message to the queue
        messageSender.Send(message);

        Status.Text = "Thank you for your order!";
    }
    catch (Exception ex)
    {
        Status.Text = "ERROR";
    }
}

That's order submission on the front end, but we also need order processing on the back end. Let's tale a look at our worker role code, which has a Run() loop. We use the Windows Azure API to loop on queue messages and process them. Our processing consists of adding an order record to the database (we've left that part of the code for now because we'll look at it separately in the next section). Our code outputs trace messages, which we'll be able to view on the console window in the Compute Emulator UI.

public override void Run()
{
    // This is a sample worker implementation. Replace with your logic.
    Trace.WriteLine("$projectname$ entry point called", "Information");

    dbConnection = new SqlConnection(connectionString);

    tP = TokenProvider.CreateSharedSecretTokenProvider(issuer, key);

    Uri uri = ServiceBusEnvironment.CreateServiceUri("sb", serviceBusNamespace, string.Empty);

    MessagingFactory factory = MessagingFactory.Create(uri, tP);
    MessageReceiver orders = factory.CreateMessageReceiver("orders", ReceiveMode.PeekLock);

    while (true)
    {
        BrokeredMessage message = orders.Receive();

        if (message != null)
        {
            try
            {
                // Acknowledge receipt of order.

                Trace.WriteLine("-------------------- Order Received ------------------", "Information");
                Trace.WriteLine(message.GetBody<string>(), "Information");

                // Insert a record in database Order table.
                ...removed for brevity...

                // Remove message from queue
                message.Complete();
            }
            catch (Exception)
            {
                // Indicate a problem, unlock message in queue
                message.Abandon();
            }
        }

        Thread.Sleep(10000);
    }
}

Let's try this out. We again launch our solution with F5. We'll be sure to open the Compute Emulator UI and be viewing the worker role's console window before we submit any orders because we want to see the activity.

On the order form in the browser, we enter an order and click the Buy It button. After the message is submitted to the Service Bus Queue we'll see a confirmation message on the web page:


Now back to the worker role console window in the Compute Emulator UI. We soon see ---- Order Received --- and the order details displayed. We thus see the Service Bus Queue doing its job of coordinating our front end and back end.



Walk-through Step 6: Using SQL Azure Database
In the last step we showed how the Worker Role processes order messages from a queue, but we glossed over what the processing is, which is to add order records to our database. Let's see now how that is done.

You'll recall that earlier we created a database server and a database in the SQL Azure Database service. That service uses the same programming model and protocol as good old SQL Server, so using it is a very familiar experience. Here's the code within our Worker Role Run loop that inserts database records. We're using ADO.NET objects from the System.Data.SqlClient namespace like SqlConnection and SqlCommand.

// Insert a record in database Order table.

try
{
    dbConnection.Open();

    dbCmd = new SqlCommand(
        String.Format("INSERT INTO [Order] (Name, Email, Phone, Address, City, State, PostalCode, Country, Color, CardNumber, SecurityCode, NameOnCard) VALUES ('{0}', '{1}', '{2}', '{3}', '{4}', '{5}', '{6}', '{7}', '{8}', '{9}', '{10}', '{11}')",
            message.Properties["Name"],
            message.Properties["Email"],
            message.Properties["Phone"],
            message.Properties["Address"],
            message.Properties["City"],
            message.Properties["State"],
            message.Properties["PostalCode"],
            message.Properties["Country"],
            message.Properties["Color"],
            Convert.ToString(message.Properties["CardNumber"]).Substring(0, 4) + "XXXXXXXXXXXXXXXXXXXX",
            message.Properties["SecurityCode"],
            message.Properties["NameOnCard"]
        )
    , dbConnection);

    dbCmd.ExecuteNonQuery();

    dbConnection.Close();

    Trace.WriteLine("Order stored in database", "Information");
}
catch (Exception ex)
{
    Trace.WriteLine("Error inserting order in database - " + ex.Message, "Error");
}

Let's view our data. We can use SQL Server Management Studio (2008 R2 edition) or the Windows Azure Management Portal to query. We'll use SSMS here. Here's the conection dialog:


Now we can open a query window and perform a SELECT * FROM [Order} to see the orders we've been submitting. As you can see, this is a very familiar experience using tools you already know, but with some new aspects like the formats of the server address and username.


Walk-through Step 7: Deploy to the Cloud
At this point, we've seen the application do everything it's supposed to: web order entry form, order queueing, order dequeing, and database storage. We've been using using real cloud services already for storage, database, and the service bus--but we've been executing locally in the simulation environment. Our solution is not yet running in the cloud and no one else can use it. So it's time to deploy our solution to Windows Azure Compute as a hosted service.

There are a few different ways we can deploy to the cloud:
  • Package the solution and upload through the management portal
  • Package and publish the solution all from within Visual Studio
  • Command line / scripting
  • In code, using a Service Management API
We're going to use the first method. Specifically, we'll ask Visual Studio to package the solution and then we'll manually upload it to the Management Portal.

To package our application, we go to Visual Studio's Solution Explorer, right-click our Windows Azure Project, and select the Package action. This will create a package file named Orders.cspkg ("cloud service package"), which is a zip file of the solution's runtime code and content, encrypted.


When the process completes, a Publish folder will open in Windows Explorer showing two files: the package file, and your cloud service configuration file. We'll need to upload both files. The reason the configuration file is kept outside the package is so we can make changes after deployment, such as increasing the number of VM instances in a role.


Now we can return to the Windows Azure Management Portal to upload our package. We navigate to the Hosted Services area and find the tshirtworld hosted service project we provisioned earlier. We click New Staging Deployment or New Production Deployment, depending which slot we want to deploy to, and fill in a dialog. The dialog prompts us for a label for the deployment (I usually put the date and time here), and is where we upload the two files that the Package action generated for us: a .cspkg and a .cscfg file.


It will take 15 minutes or so for the deployment to complete. When it's done, you can access your solution in the cloud. The access URL will be name.cloudapp.net, where 'name'  is the unique production name you chose (for a Production slot) or is a generated cryptic name (for a Staging slot). You can see and these URLs in the managment portal.



To promote from Staging to Production (or to swap them, if both slots are occupied), use the Swap VIP toolbar button. This will exchange the virtual IPs, and only takes 20-30 seconds typically. I like to leave the older deployment up in Staging until I've verified what's in Production is working, then remove the Staging deployment. You do want to make sure you undeploy anything no longer needed, else you'll be spending money needlessly.

Well, there you have it. The Windows Azure development experience has come a long way since its debut a few years back and it is constantly being improved. I encourage you to get the 90-day Windows Azure Free Trial and take it for a spin!

2 comments:

ahriman said...

Hello.
Can i translate your posts into russian language and post it on my blog http://hpcru.wordpress.com? Sure, i will place all needed links.

David Pallmann said...

ahriman: sure, translate away.