Top 7 Concerns of Migrating an ASP.NET Application to Windows Azure
This post is part of a series called “Windows Azure for the ASP.NET Developer” written by Rachel Appel, Adam Hoffman, and Peter Laudati. You can see the complete list of posts in the series at the US DPE Azure Connection site.
In the previous post of this series, I covered how to prepare your development environment for building Windows Azure applications. I left you with some references to walkthroughs to build your first “Hello World” ASP.NET application for Windows Azure. Those walkthroughs are great tutorials for getting familiar with the tools and cloud environment.
However, as developers, it is rare that we get the opportunity to do a “File –> New Project” in our day to day work. More often than not, the next step after learning “Hello World”, is usually, “Okay, let’s see if I can get my app running in Azure.” That’s where the real fun usually begins and where your “Hello World” experience might not match the experiences you have migrating an existing ASP.NET application to the cloud.
In this post, I’ll describe the typical concerns encountered when migrating an existing ASP.NET application to Windows Azure. My goal is not to cover the details of how to handle each of these, but rather to provide a guide with the proper pointers that will help you on your way as you plan a migration. I’ve organized these concerns into a “Top 7” list, however, they are in no particular order.
Understanding the Windows Azure Compute Environment
Before you review the migration considerations, it is important to understand how the Windows Azure Compute environment works. In the second post of this series, Rachel Appel covered some of the differences between Windows Azure and Windows Server. I will expand upon those here, primarily with a focus on how deployment, recovery, and elasticity work. This will make the migration concerns more obvious and easier to understand.
Windows Azure Compute is a “Platform-as-a-Service” offering. This means that the operating system and application platform are provided for you. There is no need to create and manage the virtual machine(s) that your application will run in. The unit of deployment for your application is essentially your packaged application code and its associated configuration for how it should run in the cloud. This unit of deployment is referred to as a “Windows Azure service” or a “hosted service”.
Deployment in Windows Azure Compute
When you deploy your hosted service to Windows Azure, you upload the two files that make up your hosted service:
- <yourWindowsAzureProjectName>.cspkg – The service deployment package (zip-like) file containing the contents of your application.
- ServiceConfiguration.Cloud.cscfg – An XML configuration file containing the settings for how your hosted service will run in Windows Azure.
Windows Azure stores those files in a triple redundant storage location. These two files are considered the “base” or “snapshot” of your application’s deployment. Windows Azure then inspects the configuration file to determine how many roles (VM types) and instances of each will be needed for your application.
Windows Azure will then load as many ‘vanilla’ Windows Server virtual machine instances as required by the configuration. These ‘vanilla’ Windows Server VMs are “clean” machines with no software or data installed on them other than the necessary agents needed to communicate with the Windows Azure data center.
Once the Windows Server VMs are loaded, Windows Azure will perform any startup tasks specified in your application’s Service Configuration (.cscfg) file on each instance. This includes installing software dependencies, modifying registry settings, or modifying advanced configuration settings for IIS.
Finally, Windows Azure will unpack your application from the service deployment package (.cspkg file) and install it into each instance. Internet Information Server (IIS) will be started, where it will be connected to a load balancer handling traffic for the URL you configured for your service. Your service is then live.
Recovery in Windows Azure Compute
If at any point in time, one of your deployed instances fail, whether due to hardware or software failure, Windows Azure will detect this and immediately deploy a new instance to replace it. It does this by retrieving the service deployment package (.cspkg) and Service Configuration (.cscfg) file from storage and repeating the exact same process as described above for the initial deployment.
The key thing to remember here, is that Windows Azure will always start from scratch with a ‘vanilla’ Windows Server VM, and then deploy your application into it based on the contents of your service deployment package and service configuration file. Any changes made to the application, or by the application, on a running VM instance after the initial deployment are not persisted or available in new instances that are brought online for recovery purposes.
Elasticity in Windows Azure Compute
Elasticity is one of the key benefits of Windows Azure and cloud computing. If a deployed application requires more power to meet increased load, new instances can be added to an existing deployment to handle it. Upon receiving a command or configuration change to increase the instance count, Windows Azure will deploy extra instances following the same exact procedure as described earlier for the initial deployment.
Any changes made to the application, or by the application, on a running VM instance after the initial deployment will not be available in any new instances that are brought online to meet demand.
If the load on a deployed application with multiple instances decreases, instances can be taken offline to reduce resources and costs. When a request to reduce the instance count is received by Windows Azure, Windows Azure decides which instances to remove. This means, you have no way to control which instance(s) will be removed.
‘Stateless’ Virtual Machines
The net of takeaway of understanding deployment, recovery, and elasticity in the Windows Azure Compute environment is that the VM instances your application runs in are stateless by design. This is what enables elasticity, quick recovery, and scalability in the cloud.
Now that you understand how the compute environment of Windows Azure is based upon stateless VMs, that will lead to the list of ASP.NET application migration concerns compiled here below.
Top 7 List of Migration Concerns
1. Handling Storage
Given that the VM instances that run your application are stateless, handling storage is one of the primary migration considerations you must account for. Data can be stored locally in your application’s VM or external to the VM in storage services available within Windows Azure. Windows Azure provides both relational and non-relational storage services.
Windows Azure provides non-relational storage in the form of blobs, tables, and queues. These three storage mechanisms are collectively known as “Windows Azure Storage”. Relational storage is available via SQL Azure, which is SQL Server technology delivered as a service.
The key difference with storage in the cloud is that it is provided “as a service”. That is, you will not need to set up, install, or maintain an actual database server. These things are managed for you and provisioned via the Windows Azure Management Portal where you can then access them within your ASP.NET application via traditional methods.
Using Local Storage
In a Windows Azure Web or Worker Role VM, your application has access to read and write to the local storage. However, given the stateless nature of VM instances in Windows Azure, local storage is transient by design. Therefore, data that needs to be durable must be stored externally from the VM instance.
Data stored on the local drive of a VM instance will survive OS re-boots, but not hardware failures. Data on the local drive is not synced with the drives of other VM instances of your application. Likewise, new instances (added for capacity or restoration of failed VMs) will not have access to data persisted to local storage. Data on the local drive does not survive if an application deployment is deleted from Azure, and then later re-deployed again.
If your application does depend on the local drive for durable storage, you will need to plan for moving that data to either Windows Azure Storage or SQL Azure. Some examples of where an existing ASP.NET application may use local storage include writing dynamic data to an XML configuration file or storing images and other media content that may be uploaded to the application, like in a CMS system. These examples would be candidates for moving to Windows Azure blob storage.
Local storage can be used for temporary data that your application would have no issue re-generating or working without on a re-start.
For more information about Local Storage in Windows Azure WebRoles and WorkerRoles, see: How to Configure Local Storage Resources
Using SQL Azure
For ASP.NET applications that have been designed to scale over multiple servers in a web farm, the transient nature of local storage shouldn’t present a major challenge. In these types of applications, the data is typically stored externally from the application in a relational database such as SQL Server. In a typical web farm deployment, you may have multiple web servers running your application all sharing a common database server. This model works well in Windows Azure as your relational data should be able to migrate from SQL Server into SQL Azure.
When migrating an ASP.NET application into Windows Azure, one of the steps you must take early on is to configure a SQL Azure server instance and migrate your existing databases to it. This typically includes any custom databases you have, as well as the standard ASP.NET database for Membership and Profile data. Once these databases have been set up in SQL Azure, it is only the connection string that needs to be changed in your application’s configuration.
While developing your application locally, you will continue to use SQL Server Express as per usual. In this case, you will often find it helpful to keep different versions of your web.config file handy in your project for local development and production cloud deployment.
SQL Azure offers a subset of SQL Server’s features and functionality. Some elements of your application’s custom database may not be compatible. Using tools such as the SQL Azure Migration Wizard will help you discover any such incompatibilities so you can plan around them.
For more information using SQL Azure with ASP.NET, see Rachel Appel’s post: Get Started Building Data Driven Apps with Windows Azure and SQL Azure.
Also, see my post: Get Started with SQL Azure: Resoures
Using Windows Azure Storage
For easy migrations with little or no code changes, migrating your ASP.NET application’s data to SQL Azure is usually a great fit. If you’re like most ASP.NET developers, you may be asking, “Why should I care about these new storage mechanisms in Windows Azure Storage like blobs & tables?”. If your ASP.NET application is a typical CRUD-like application with lots of data driven forms, you might not need to deal with Windows Azure Storage when first migrating your application to Windows Azure.
If your ASP.NET application does make use of the local file system for durable data (such as dynamically editing XML configuration files) as described in the previous section, you will need to relocate that data to Windows Azure Storage. Blob storage is a great alternative to local storage for reading and writing files to.
As you optimize your application, it is a good idea to store static content such as script files, CSS style sheets, and images in Blob storage. These static files can be served directly by the web server in your application’s VM. However, by moving them to Blob storage, they are served to your users directly by the Windows Azure Storage service. This has the benefit of reducing the load on your web server(s) and also enabling you to later take advantage of Windows Azure’s Content Delivery Network (CDN).
For more details on using Windows Azure Storage with ASP.NET, see the next post in this series by Adam Hoffman: Windows Azure Storage for the ASP.NET Developer.
2. Mapping ASP.NET Applications to Windows Azure Roles
In my previous post in this series, I wrote that the Windows Azure Tools for Visual Studio include a Windows Azure Service project type to define a hosted service. This project is essentially a “meta” project that lets Visual Studio know how to package your application for deployment to the cloud and configure Windows Azure to run your application.
The tools also contain templates for WebRole and WorkerRole project types. The WebRole project type contains the actual ASP.NET application to be deployed as a hosted service in Windows Azure. The tools contain variants of the WebRole project type for each of the ASP.NET application types including WebForms, MVC 2, MVC 3, and MVC 4.
Creating a new WebRole project for any of the ASP.NET application types will essentially create a project with the structure as the existing ASP.NET project template types. When the WebRole project is created, the tools add the appropriate configuration settings to the Windows Azure Service project to link the two. You can add up to five WebRole projects to a single Windows Azure Service project.
In Visual Studio, you can also convert an existing ASP.NET Web Application project to a WebRole project by adding a “Windows Azure Deployment Package”. This will create a Windows Azure Service project, convert your ASP.NET application project to a WebRole project, and link the two. This is more likely the scenario most developers will use when migrating an existing application to Windows Azure.
For an example of how to converting an existing ASP.NET Web Application project to a WebRole project in Visual Studio, and how to create a new ASP.NET WebRole project see: Walkthrough: Hosting an ASP.NET MVC Application on Windows Azure.
Note: The Windows Azure Tools for Visual Studio do not support converting an ASP.NET Website to a WebRole project. It is possible to package an ASP.NET Website for deployment to Windows Azure, but the tooling experience is not great, essentially limited to command line calls and manual assembly of the required configuration files. For more information, see David Aiken’s post: How to Deploy an ASP.NET web site to Windows Azure! Or, see: Website Projects in Azure Web Role on Stackoverflow.com
Understanding WebRole Projects
Whether you create a new WebRole project from scratch, or convert your existing ASP.NET Web Application project to a WebRole project, there are three sets of things that will be added to your project:
- References to three Windows Azure assemblies: Diagnostics, Service Runtime, and Storage Client.
- A WebRole.cs or WebRole.vb file.
- A trace listener in the web.config file to enable Windows Azure logging and debugging.
The Windows Azure Diagnostic assembly contains the classes for logging and diagnostics. The Windows Azure Service Runtime assembly contains classes for accessing configuration settings and managing the lifecycle of the role (VM) that your application runs in. The Windows Azure Storage Client assembly contains the classes for accessing Windows Azure Storage services (Blobs, Tables, and Queues).
WebRole.cs (or .vb) Bootstrapping Code
The WebRole.cs (or .vb) file is a magical place where you can set up all sorts of advanced tasks and options. You will likely pay little attention to it when building your first “Hello World” ASP.NET application for Windows Azure, but over time, you may find yourself revisiting the classes in this file.
You can think of WebRole.cs as the “Global.asax” file for the cloud. Inside is a class called ‘WebRole’ which extends Windows Azure’s RoleEntryPoint class. This class contains methods that are called by Windows Azure to manage the lifecycle of your web role (starting, running, changing, stopping, etc). For details on the lifecycle events and their order with respect to the ASP.NET applications events handled in Global.asax, see Jim Nakashim’s post: Windows Azure RoleEntryPoint Method Call Order.
One of the most common tasks performed in the extended RoleEntryPoint class is to initialize Windows Azure diagnostics and logging at start up. Other things you can do include responding to configuration changes, such as the scaling up or scaling down of instances, and handle shut down tasks for the web role. We will have more coverage on those topics later in the series.
Troubleshooting Tip: If your role is recycling between the initializing, busy, and stopping states, this may be the result of something going wrong at startup time. A good place to poke around and troubleshoot is in the RoleEntryPoint class. If any of the methods in the RoleEntryPoint class raise an unhandled exception, the web role (VM) will be shut down. Windows Azure will then automatically attempt to re-start the role. For tips on how to break the cycle and troubleshoot, see: Troubleshooting Hosted Service Deployment States on MSDN.
For more information on WebRole.cs and the RoleEntryPoint class, see: Overview of Building an Application that Runs in a Hosted Service on MSDN.
For tips on how you can use the RoleEntryPoint, see Brent Stineman’s post: Leveraging the RoleEntryPoint.
3. Application Dependencies
A common hiccup that can occur when you are first migrating your ASP.NET application to Windows Azure is not including dependent assemblies. The Windows Azure compute environment includes the .NET Framework (3.5 and 4) as well as the Windows Azure SDK assemblies. However, it does NOT include other 3rd party or Microsoft frameworks such as those obtained via NuGet. For example, the Microsoft Enterprise Library, or out-of-band releases for the .NET Framework such as the ASP.NET MVC framework are not included in the Windows Azure compute environment.
Luckily, the WebRole project templates in the Windows Azure Tools for Visual Studio automatically include the ASP.NET MVC (versions 2, 3, or 4) framework assemblies in your application’s deployment service package (.cspkg file). However, if your application depends on other frameworks or components, you must add those assemblies to your application’s deployment service package. You can do this by:
- Setting the Copy Local property to True for each referenced assembly in your project that is not part of the Windows Azure SDK or the .NET Framework.
- Ensuring the web.config file does not reference any unused assemblies in the compilation element, and all references point to assemblies that are either part of the .NET Framework or the Windows Azure SDK, or that have their Copy Local property set to True in Visual Studio.
For more tips on verifying application dependencies in Windows Azure, see: Troubleshooting Hosted Deployment States on MSDN.
4. Session State
Many ASP.NET applications use ASP.NET’s Session State feature to track things such as the state of a user’s shopping cart or their profile information. Session state is a powerful feature of ASP.NET that brings the appearance of state to an environment that is stateless.
ASP.NET Session State Providers
The session state feature in ASP.NET uses a provider model that allows you to configure how session state is stored in your environment. There are three session state providers included with ASP.NET out of the box:
- In-process memory provider
- State server provider
- SQL Server provider
The most frequently used provider is the in-process memory provider, which stores the state in the memory of the web server it is running on. It relies on the load balancer configured for ‘sticky sessions’. Since the Windows Azure load-balancers are non-sticky, you can not use this provider.
The state server provider allows you to point your session state at a server that is dedicated to hosting state data in its own memory. In Windows Azure, this would require you to configure, run, manage, and pay for another WebRole specifically as a state server. That would not be economical as a state server would likely need a larger VM size to take advantage of extra memory.
The SQL Server provider does as you would expect, it stores state data in a SQL Server database. In this scenario, all the servers in web farm could point at the same database for session state, allowing user requests to be served across the farm. The SQL Server provider works just fine in Windows Azure if you point it to a SQL Azure database. However, storing session state in a database can add latency when retrieving state on each user request.
Windows Azure Session State Providers
The Windows Azure Cache provider is a great solution for managing ASP.NET Session state in Windows Azure. This provider was introduced recently in December 2011. It uses the Windows Azure Cache service to store session state. The Windows Azure Cache service is a distributed in-memory caching service. High performance is achieved by maintaining this cache in-memory across multiple cache servers.
The Windows Azure Cache provider requires ASP.NET 4, which means your projects must be compiled against the full version of the .NET 4 Framework. This may be a limitation for those who are on .NET 3.5 and earlier.
For more details on how to use the Windows Azure Cache provider, see: Using Windows Azure Caching for Session State
The Table Storage Session provider stores session state in Windows Azure Table storage. This provider is provided as sample code by the Windows Azure team. This provider appears to be more of a proof of concept vs. something you should use in production. The sample code does not clean up expired sessions, so the table size can continue to grow. However, it is a nice solution in concept as session state is stored in a high-scale storage service backed by triple redundancy.
5. Identity & Authentication In The Cloud
Handling identity and authentication is a common thing most ASP.NET applications do. One of ASP.NET’s best features is its provider-based Membership and Profile services. When combined with Forms Authentication, these two services make for a simple model to handle authentication and identity on your website. With the Membership and Profile services’ dynamic providers, user data can be stored in different locations. It is most common that this data be stored in SQL Server using the SQL Membership provider.
When migrating an ASP.NET application to Windows Azure, you can migrate the membership and profile data to SQL Azure. These standard ASP.NET databases should migrate just fine to the cloud. This means that Forms Authentication in Windows Azure “just works” using the existing SQL Membership provider. The exception to this would be if you created a custom membership and profile database that uses features not supported in SQL Azure.
For corporate and Intranet websites, it is common for ASP.NET applications to use Windows Integrated Authentication. In this scenario, if a user is logged into their desktop, their Windows identity is transferred to the web application. The user is essentially authenticated with the web application without knowing it.
Windows Authentication is not available “out of the box” in Windows Azure as it requires the web server to be part of the domain the users belong to. With your ASP.NET application running in a Windows Azure datacenter, the web server certainly won’t be part of your company’s corporate domain! Windows Azure provides a service called Access Control Service (ACS) which can help bridge the gap.
ACS is an authentication service in the cloud that enables you to set up a trust relationship between Windows Azure and a secure token server (STS) in your company. This concept is called Federated Identity. With ACS configured, users can log into your ASP.NET application seamlessly using their corporate domain credentials.
When migrating a corporate application that depends on Windows Authentication, you will need to configure Windows Azure’s Access Control Service with your company’s secure token server. Most companies use Windows Server Active Directory Federation Services V2 for their STS.
ACS also enables you to allow users to login with many popular identity providers such as Windows Live ID, Google, Yahoo, Facebook, and Open ID 2.0.
Sound confusing? If ACS, STS, and WSADFSV2 sound like crazy acronym soup to you, have no fear! We will be covering how to handle identity with Windows Azure’s Access Control Service in a forthcoming post in this series. (Which will eventually be linked from here.)
6. Handling Configuration
Most ASP.NET applications use the web.config file to store all of their run time configuration settings. Administrators of ASP.NET applications are used to having the ability to make configuration changes to this file while an application is running. Changes to the web.config file will trigger a restart of the application within IIS.
In Windows Azure, the web.config file is deployed as part of your application’s service deployment package. It lives within the VM instance that your application runs in. Due to the stateless nature of these instances, changes to the web.config file on a running instance is not allowed. This is because if changes were made:
- They wouldn’t be synchronized across all of the instances in the role.
- The changes would not be available to new instances spun up for elasticity or recovery.
Changes to the web.config file require a new deployment service package to be created, and a new deployment to be pushed to Windows Azure. If this is not an acceptable limitation, you can migrate your configuration settings to the hosted service’s ServiceConfiguration.Cloud.cscfg file in your Windows Azure Deployment Project.
Like web.config in a regular Windows Server environment, settings in this file can be edited at runtime too. Changes to ServiceConfiguration.Cloud.cscfg will also trigger a restart of your application within IIS, causing the new settings to be applied. This also has the benefit of applying the changes across all of the role instances that are running your application. Your configuration is now located in a central location relative to all of your role instances.
To move configuration settings to the ServiceConfiguration.Cloud.cscfg file, you will need to add a small bit of code to the RoleEntryPoint class in the WebRole.cs (or .vb) file to handle both the loading of these settings, and changes when the ServiceConfiguration.Cloud.cscfg file is updated.
For more details on how to store and retrieve custom configuration settings in the ServiceConfiguration.Cloud.cscfg file, see the following resources:
- How To: Configure the Roles for a Windows Azure Application with Visual Studio – (Jump to “Add custom settings to use in your Windows Azure application”)
- Reading Configuration Settings for the Storage Client Library and Handling Changed Settings
- 5 Ways to Use Microsoft Azure to Ease Cloud Migration – Brian Prince – (Jump to “3. Configuration”)
There are trade offs if you take the approach of putting your application’s settings in ServiceConfiguration.Cloud.cscfg. In exchange for having the ability to easily apply configuration changes across all of your instances while running, your application code now takes a dependency on Windows Azure. You will also need to write the code to retrieve settings from ServiceConfiguration.Cloud.cscfg.
In general, it is probably best to move only settings that you expect the administrators of your application to change frequently while in production. For settings that don’t change frequently, keep them in web.config and manage the changes via upgrade deployments.
7. IIS Configuration Differences
When your ASP.NET application runs in an Windows Azure WebRole, it is hosted using IIS 7.0. Being hosted in IIS 7.0 means your application has access to the full range of web server features available in an regular Windows Server installation. This includes useful things such as support for multiple sites or virtual applications and activation of WCF services over non-HTTP transports through Windows Activation Services. For more information on the IIS features available in Windows Azure, see: New Full IIS Capabilities: Differences from Hostable Web Core.
Advanced configuration of IIS components and features can be managed in the ServiceDefinition.csdef configuration file of your application’s Windows Azure Service project. Multiple websites can be configured directly in the ServiceDefinition configuration file. Other IIS settings can be configured by generating a CMD file script and running it as a startup task.
To learn how to generate a CMD file script to configure IIS, see: Using Configuration Editor: Generate Scripts.
To learn how to configure IIS components via start-up tasks, see: How to Configure IIS Components in Windows Azure.
Multiple ASP.NET Applications in a Single WebRole
The default way the Visual Studio tools work is to configure one ASP.NET application per WebRole. That is, each ASP.NET application will be configured to run in its own dedicated virtual machine in the cloud. By taking advantage of the sites, applications, and virtual directories features in Internet Information Services (IIS) 7.0, it is possible to host more than one ASP.NET application in a single WebRole. This is a more complex configuration that involves trade offs.
While you gain the economic convenience of hosting two sites in a single WebRole, you give up the ability to independently manage some aspects of those applications, such as whether or when to scale up or down to more role instances. Also, Windows Azure does not impose a security boundary between the sites and applications that are running within the role. This can have implications when you are considering the security of the individual sites.
On a regular server, multiple sites are managed by configuring host headers in the web.config file. In Windows Azure, you will essentially set this up by doing the same in the ServiceDefinition.csdef file.
For more information, see: How to Configure a Web Role for Multiple Web Sites on MSDN or Brian Hitney’s post: One Azure Role, Multiple Websites.
There you have it… a collection of top migration concerns when migrating an ASP.NET application to Windows Azure. This list is by no means comprehensive, but should provide you with enough information to move beyond “Hello World” and help you plan for getting your application deployed to the cloud.
Now that you understand the type of work needed to migrate an existing ASP.NET application to Windows Azure, it’s time to learn about the new storage mechanisms in Windows Azure (blobs, tables, and queues, oh my!). Read the next post in this series by Adam Hoffman: Windows Azure Storage for the ASP.NET Developer