3 – Phase 1: Getting to the Cloud
December 6, 2011
This chapter walks you through the first steps of migrating an application to Windows® Azure™ technology platform. You'll see an example of how to take an existing business application, developed using ASP.NET, and move it to the cloud. This first stage is only concerned with getting the application to work in the cloud without losing any functionality. It does address some "big" issues, such as security and data storage that are relevant to almost any cloud-based application.
This first stage doesn't explore how to improve the application by exploiting the features available on the Windows Azure platform. In addition, the on-premises version of the application that you'll see is not complete; it contains just enough basic functionality to get started. The following chapters discuss how to improve the application by using some of the features available on the Windows Azure platform, and you'll see more features added to the application. For now, you'll see how to take your first steps into the cloud.
The Premise
The existing aExpense application is a business expense submission and reimbursement system used by Adatum employees. The application is built with ASP.NET 3.5, deployed in Adatum's data center, and is accessible from the Adatum intranet. The application relies on Microsoft Active Directory® to authenticate employees. It also uses Active Directory to access some of the user profile data that the application requires, for example, an employee's cost center and manager. Because aExpense uses Windows authentication, it recognizes the credentials used when employees log on to the corporate network and doesn't need to prompt them again for their user names and passwords.
Poe Says: | |
|---|---|
![]() | Integration with Active Directory really simplifies the task of managing this application. The aExpense application leverages Active Directory's access management facilities, and the cost center and manager information that Adatum store in Active Directory. |
The aExpense access control rules use application-specific roles such as "Employee" and "Manager." Access control is intermixed with the application's business logic.
The aExpense application uses a simple SQL Server® database for storing application data, and the application uses LINQ to SQL as its data access mechanism. The application is configured to connect to SQL Server by using integrated security, and the website uses a service account to log on to the database.
The aExpense application uses the Enterprise Library Logging Application Block and the Exception Handling Application Block for logging diagnostic information from the application.
Figure 1 shows a whiteboard diagram of the structure of the on-premises aExpense application.
Figure 1
Goals and Requirements
In this first phase, Adatum has a number of goals for the migration of the aExpense application to the cloud that the team summarizes as "Getting it to work in the cloud." Optimizing the application for the cloud and exploiting the features of Windows Azure will come later.
Your decision to move an application to the cloud should be based on clear goals and requirements.
Adatum identified some specific goals to focus on in this first phase. The aExpense application in the cloud must be able to access all the same data that the on-premises version of the application can access. This includes the business expense data that the application processes and the user profile data, such as a user's cost center and manager, that it needs to enforce the business rules in the application. However, Adatum would like to remove any dependency on Active Directory from aExpense and avoid having the application call back into Adatum from the cloud.
Bharath Says: | |
|---|---|
![]() | We want to avoid having to make any calls back into Adatum from the cloud application. This would add significantly to the complexity of the solution. |
A second goal is to make sure that operations staff have access to the same diagnostic information from the cloud-based version of aExpense as they have from the existing on-premises version of the application.
A significant concern that Adatum has about a cloud-based solution is security, so a third goal is to continue to control access to the aExpense application based on identities administered from within Adatum, and to enable users to access the application by using their existing credentials. Adatum does not want the overhead of managing additional security systems for its cloud-based applications.
Overall, the goals of this phase are to migrate aExpense to the cloud while preserving the user experience and the manageability of the application, and to make as few changes as possible to the existing application.
Overview of the Solution
The first step was to analyze the existing application to determine which pieces would need to change when it was migrated to the cloud. Remember that the goal at this stage is to make the application work in the cloud while making as few changes as possible to the application.
At this stage, Adatum wants to make as few changes as possible to the application.
The migration project team determined that they could replace SQL Server with SQL Azure to meet the application's data storage requirements. They could easily copy the existing database structure and contents to SQL Azure.
Note: |
|---|
| You can use the SQL Azure Migration Wizard at http://sqlazuremw.codeplex.com/ to help you to migrate your local SQL Server databases to SQL Azure. |
They also determined that the application could continue to use the Enterprise Library application blocks in Windows Azure, and that the cloud-based application could continue to generate the same diagnostic information as the on-premises version.
Markus Says: | |
|---|---|
![]() | It would be great if we could continue to use tried and tested code in the cloud version of the application. |
Note: |
|---|
| You can download a white paper that explains the capabilities and limitations of Enterprise Library 5.0 when it is used by .NET applications designed to run on the Windows Azure platform from http://wag.codeplex.com/. |
The on-premises aExpense application stores users' preferred reimbursement methods by using the ASP.NET profiles feature. The default ASP.NET profile provider uses SQL Server as its storage mechanism. Because SQL Azure is a relatively expensive storage mechanism (compared to Windows Azure table storage), and because the profile data is very simple, the team decided to use a profile provider implementation that used Windows Azure table storage. Switching to a different profile provider should have no impact on any existing code in the application.
The biggest changes to the application that the team identified were in the authentication and authorization functionality. The Adatum team decided to modify the application to use a claims-based system. Adatum will configure an on-premises Active Directory Federation Services (ADFS) claims issuer in their data center. When a user tries to access the aExpense application in the cloud, that user will be redirected to this claims issuer. If the user has not already logged on to the Adatum domain, the user will provide his or her Windows credentials, and the claims issuer will generate a token that contains a set of claims obtained from Active Directory. These claims will include the user's role membership, cost center, and manager. This will minimize the changes needed in the application and remove the direct dependency that the current version of the application has on Active Directory because the application will obtain the required user data from the claims issuer (the claims issuer still has to get the data from Active Directory on behalf of the aExpense application). The external claims issuer can integrate with Active Directory, so that application users will continue to have the same single sign-on experience.
Jana Says: | |
|---|---|
![]() | Using claims can simplify the application by delegating responsibilities to the claims issuer. |
Figure 2 shows the whiteboard drawing that the team used to explain the architecture of aExpense would look like after the migration to Windows Azure.
Figure 2
Inside the Implementation
Now is a good time to walk through the process of migrating aExpense into a cloud-based application in more detail. As you go through this section, you may want to download the Microsoft Visual Studio® development system solution from http://wag.codeplex.com/. This solution contains implementations of the aExpense application, before (in the BeforeAzure folder) and after the migration (in the Azure-SQLAzure folder). If you are not interested in the mechanics, you should skip to the next section.
Use the Visual Studio Cloud Service project template to get started with your cloud project.
Creating a Web Role
The developers at Adatum created the Visual Studio solution for the cloud-based version of aExpense by using the Windows Azure Cloud Service template. This template generates the required service configuration and service definition files, and the files for the web and worker roles that the application will need.
Note: |
|---|
| For more information about how to create a Windows Azure Cloud Service project in Visual Studio, see the list of resources in the section "Developing Windows Azure Applications" in Chapter 1, "Introduction to the Windows Azure Platform." |
This first cloud-based version of aExpense has a single web role that contains all the code from the original on-premises version of the application.
The service definition file defines the endpoint for the web role. The aExpense application only has a single HTTPS endpoint, which requires a certificate. In this case, it is known as "localhost." When you deploy the application to Windows Azure, you'll also have to upload the certificate.
<ServiceDefinition name="aExpense.Azure" xmlns="…">
<WebRole name="aExpense">
<Sites>
<Site name="Web">
<Bindings>
<Binding name="Endpoint1" endpointName="Endpoint1" />
</Bindings>
</Site>
</Sites>
<Endpoints>
<InputEndpoint name="Endpoint1" protocol="https" port="443"
certificate="localhost" />
</Endpoints>
<Certificates>
<Certificate name="localhost" storeLocation="LocalMachine"
storeName="My" />
</Certificates>
<ConfigurationSettings>
<Setting name="DataConnectionString" />
</ConfigurationSettings>
<Imports>
<Import moduleName="Diagnostics" />
</Imports>
<LocalResources>
<LocalStorage name="DiagnosticStore"
cleanOnRoleRecycle="false" sizeInMB="5120" />
</LocalResources>
</WebRole>
</ServiceDefinition>
Note: |
|---|
| The "localhost" certificate is only used for testing your application. When you deploy your application to Azure so that it uses HTTPS, you must use a certificate that matches the application URL. If you map the URL to a different one using a CNAME record in your DNS, the certificate must match the mapped name. |
The service configuration file defines the aExpense web role. It contains the connection strings that the role will use to access storage and details of the certificates used by the application. The application uses the DataConnectionString to connect to the Windows Azure storage holding the profile data, and uses the DiagnosticsConnectionString to connect to the Windows Azure storage for saving logging and performance data. The connection strings will need to change when you deploy the application to the cloud so that the application can use Windows Azure storage.
<ServiceConfiguration serviceName="aExpense.Azure" xmlns="…">
<Role name="aExpense">
<Instances count="1" />
<ConfigurationSettings>
<Setting name=
"Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString"
value="DefaultEndpointsProtocol=https;
AccountName={Azure storage account name};
AccountKey={Azure storage shared key}" />
<Setting name="DataConnectionString"
value="DefaultEndpointsProtocol=https;
AccountName={Azure storage account name};
AccountKey={Azure storage shared key}" />
</ConfigurationSettings>
<Certificates>
<Certificate name="localhost" thumbprint="…"
thumbprintAlgorithm="sha1" />
</Certificates>
</Role>
</ServiceConfiguration>
Note: |
|---|
| The values of "Azure storage account name" and "Azure storage shared key" are specific to your Windows Azure storage account. |
Markus Says: | |
|---|---|
![]() | In Chapter 5, you'll see how Adatum automated editing the configuration file and uploading the certificate as part of the automated deployment process. |
Securing aExpense
Before the migration, aExpense used Windows Authentication to authenticate users. This is configured in the Web.config file of the application.
After the migration, the aExpense application delegates the process of validating credentials to an external claims issuer instead of using Windows Authentication. You make this configuration change in the Web.config file.
Note: |
|---|
| To find out more about claims-based Identity, the FedUtil tool, and Windows Identity Foundation (WIF), take a look at the book, A Guide to Claims-Based Identity and Access Control. You can download a .pdf copy of this book from http://msdn.microsoft.com/en-us/library/ff423674.aspx. |
The first thing that you'll notice in the Web.config file is that the authentication mode is set to None, while the requirement for all users to be authenticated has been left in place.
<authorization> <deny users="?" /> </authorization> <authentication mode="None" />
The WSFederationAutheticationModule (FAM) and SessionAuthenticationModule (SAM) modules now handle the authentication process. You can see how these modules are loaded in the system.webServer section of the Web.config file.
Markus Says: | |
|---|---|
![]() | You can make these changes to the Web.config file by running the FedUtil tool. |
<system.webServer>
…
<add name="WSFederationAuthenticationModule"
type="Microsoft.IdentityModel.Web.
WSFederationAuthenticationModule, …" />
<add name="SessionAuthenticationModule"
type="Microsoft.IdentityModel.Web.
SessionAuthenticationModule, …" />
</system.webServer>
When the modules are loaded, they're inserted into the ASP.NET processing pipeline in order to redirect the unauthenticated requests to the claims issuer, handle the reply posted by the claims issuer, and transform the security token sent by the claims issuer into a ClaimsPrincipal object. The modules also set the value of the HttpContext.User property to the ClaimsPrincipal object so that the application has access to it.
More specifically, the WSFederationAuthenticationModule redirects the user to the issuer's logon page. It also parses and validates the security token that is posted back. This module also writes an encrypted cookie to avoid repeating the logon process. The SessionAuthenticationModule detects the logon cookie, decrypts it, and repopulates the ClaimsPrincipal object. After the claim issuer authenticates the user, the aExpense application can access the authenticated user's name.
The Web.config file contains a new section for the Microsoft.IdentityModel that initializes the Windows Identity Foundation (WIF) environment.
<microsoft.identityModel>
<service>
…
</service>
</microsoft.identityModel>
You can also use a standard control to handle the user logout process from the application. The following code example from the Site.Master file shows a part of the definition of the standard page header.
<div id="toolbar">
Logged in as:
<i>
<%= Microsoft.Security.Application.Encoder.HtmlEncode
(this.Context.User.Identity.Name) %>
</i> |
<idfx:FederatedPassiveSignInStatus
ID="FederatedPassiveSignInStatus1"
runat="server"
OnSignedOut="FederatedPassiveSignInStatus1SignedOut"
SignOutText="Logout" FederatedPassiveSignOut="true"
SignOutAction="FederatedPassiveSignOut" />
</div>
You'll also notice a small change in the way that aExpense handles authorization. Because the authentication mode is now set to None in the Web.config file, the authorization rules in the Web.config file now explicitly deny access to all users as well as allowing access for the designated role.
<location path="Approve.aspx">
<system.web>
<authorization>
<allow roles="Manager" />
<deny users="*"/>
</authorization>
</system.web>
</location>
The claim issuer now replaces the ASP.NET role management feature as the provider of role membership information to the application.
There is one further change to the application that potentially affects the authentication process. If you were to run the aExpense application on more than one web role instance in Windows Azure, the default cookie encryption mechanism (which uses DPAPI) is not appropriate because each instance has a different key. This would mean that a cookie created by one web role instance would not be readable by another web role instance. To solve this problem you should use a cookie encryption mechanism that uses a key shared by all the web role instances. The following code from the Global.asax file shows how to replace the default SessionSecurityHandler object and configure it to use the RsaEncryptionCookieTransform class.
Bharath Says: | |
|---|---|
![]() | Although the initial deployment of aExpense to Windows Azure will only use a single web role, we need to make sure that it will continue to work correctly when we scale up the application. That is why we use RSA with a certificate to encrypt the session cookie. |
private void OnServiceConfigurationCreated(object sender,
ServiceConfigurationCreatedEventArgs e)
{
// Use the <serviceCertificate> to protect the cookies that
// are sent to the client.
List<CookieTransform> sessionTransforms =
new List<CookieTransform>(
new CookieTransform[]
{
new DeflateCookieTransform(),
new RsaEncryptionCookieTransform(
e.ServiceConfiguration.ServiceCertificate),
new RsaSignatureCookieTransform(
e.ServiceConfiguration.ServiceCertificate)
});
SessionSecurityTokenHandler sessionHandler =
new
SessionSecurityTokenHandler(sessionTransforms.AsReadOnly());
e.ServiceConfiguration.SecurityTokenHandlers.AddOrReplace(
sessionHandler);
}
Managing User Data
Before the migration, aExpense used an LDAP query to retrieve Cost Center, Manager, and Display Name information from Active Directory. It used the ASP.NET Role provider to retrieve the role membership of the user, and the ASP.NET Profile Provider to retrieve the application specific data for the application—in this case, the preferred reimbursement method. The following table summarizes how aExpense accesses user data, and where the data is stored before the migration:
User Data | Access Mechanism | Storage |
|---|---|---|
Role Membership | ASP.NET Role Provider | SQL Server |
Cost Center | LDAP | Active Directory |
Manager | LDAP | Active Directory |
Display Name | LDAP | Active Directory |
User Name | ASP.NET Membership Provider | SQL Server |
Preferred Reimbursement Method | ASP.NET Profile Provider | SQL Server |
After the migration, aExpense continues to use the same user data, but it accesses the data differently. The following table summarizes how aExpense accesses user data, and where the data is stored after the migration:
User Data | Access Mechanism | Storage |
|---|---|---|
Role Membership | ADFS | Active Directory |
Cost Center | ADFS | Active Directory |
Manager | ADFS | Active Directory |
Display Name | ADFS | Active Directory |
User Name | ADFS | Active Directory |
Preferred Reimbursement Method | ASP.NET Profile Provider | Windows Azure Table Storage |
The external issuer delivers the claim data to the aExpense application after it authenticates the application user. The aExpense application uses the claim data for the duration of the session and does not need to store it.
The external issuer delivers the claim data to the aExpense application after it authenticates the application user.
The application can read the values of individual claims whenever it needs to access claim data. You can see how to do this if you look in the ClaimHelper class.
Profile Data
Before the migration, aExpense used the ASP.NET profile feature to store application-specific user settings. Adatum tries to avoid customizing the schema in Active Directory, so aExpense stores a user's preferred reimbursement method by using the profile feature. The default Profile Provider stores the profile properties in a SQL Server database.
Poe Says: | |
|---|---|
![]() | We don't like to customize the Active Directory schema if we can possibly avoid it. Schema changes have far-reaching implications and are difficult to undo. |
Using the profile feature makes it very easy for the application to store small amounts of user data. You enable the profile feature and specify the properties to store in the Web.config file.
<profile defaultProvider="SqlProvider">
<providers>
<clear />
<add name="SqlProvider"
type="System.Web.Profile.SqlProfileProvider"
connectionStringName="aExpense"
applicationName="aExpense" />
</providers>
<properties>
<add name="PreferredReimbursementMethod" />
</properties>
</profile>
Then you can access a profile property value in code like this.
var profile = ProfileBase.Create(userName);
string prm =
profile.GetProperty<string>("PreferredReimbursementMethod");
After migration, aExpense continues to use the profile system to store the preferred reimbursement method for each user. Although it is possible to use the SQL Server profile provider in Windows Azure by using the custom scripts at http://support.microsoft.com/kb/2006191/, the solution uses a sample provider that utilizes Windows Azure table storage to store profile information. You can download this provider from http://code.msdn.microsoft.com/windowsazuresamples. The only change required for the application to use a different profile provider is in the Web.config file.
Markus Says: | |
|---|---|
![]() | Using a profile provider to access profile data minimizes the code changes in the application. |
<profile defaultProvider="TableStorageProfileProvider">
<providers>
<clear />
<add name="TableStorageProfileProvider"
type="AExpense.Providers.TableStorageProfileProvider …"
applicationName="aExpense" />
</providers>
<properties>
<add name="PreferredReimbursementMethod" />
</properties>
</profile>
Using the TableStorageProfileProvider class does raise some issues for the application:
- The TableStorageProfileProvider is unsupported sample code.
- You must migrate your existing profile data from SQL Server to Windows Azure table storage.
- You need to consider whether, in the long run, Windows Azure table storage is suitable for storing profile data.
Even with these considerations to taken into account, using the table storage profile provider enabled Adatum to keep the changes in the application to a minimum; this means that the running costs of the application will be lower than they would be using SQL Azure.
Note: |
|---|
| Chapter 4, "How Much Will It Cost?", describes the relative costs of using Windows Azure storage and SQL Azure. Chapter 5, "Phase 2: Automating Deployment and Using Windows Azure Storage," provides more information about using Windows Azure table storage. |
Connecting to SQL Server
Before the migration, aExpense stores application data in a SQL Server database. In this first phase, the team moved the database to SQL Azure and the data access code in the application remained unchanged. The only thing that needs to change is the connection string in the Web.config file.
Connecting to SQL Azure instead of an on-premises SQL Server only requires a configuration change.
<add name="aExpense" connectionString=
"Data Source={Server Name};
Initial Catalog=aExpense;
UId={SQL Azure User Id};
Pwd={SQL Azure User Password};
Encrypt=True;
TrustServerCertificate=False;"
providerName="System.Data.SqlClient" />
Note: |
|---|
| The values of Server Name, SQL Azure User Id, and SQL Azure User Password are specific to your SQL Azure account. |
There are two things to notice about the connection string. First, notice that because SQL Azure does not support Windows Authentication; the credentials for your SQL Azure account are stored in plain text. You should consider encrypting this section of the Web.config file. This will add to the complexity of your application, but it will enhance the security of your data. If your application is likely to run on multiple role instances, you must use an encryption mechanism that uses keys shared by all the role instances.
Note: |
|---|
| To encrypt your SQL connection string in the Web.config file, you can use the Pkcs12 Protected Configuration Provider that you can download from http://archive.msdn.microsoft.com/pkcs12protectedconfg. For additional background information about using this provider, read the set of four blog posts on the SQL Azure Team Blog starting with this one: http://blogs.msdn.com/b/sqlazure/archive/2010/09/07/10058942.aspx. |
The second thing to notice about the connection string is that it specifies that all communications with SQL Azure are encrypted. Even though your application may reside on a computer in the same data center as SQL Azure, you have to treat that connection as if it was using the internet.
Any traffic within the data center is considered "internet," so it should be encrypted.
Bharath Says: | |
|---|---|
![]() | You can also add protection to your SQL Azure database by configuring the SQL Azure firewall in the SQL Azure portal. You can use the SQL Azure firewall to specify the IP addresses of the computers that are permitted to connect to your SQL Azure server. |
SQL Azure Connection Timeout
When you try to connect to SQL Azure, you can specify a connection timeout value. If the timeout expires before establishing a connection, an error occurs, which your application must handle. How your application handles a timeout error depends on the specific circumstances, but possible strategies include keep retrying the connection until it succeeds, report the error to the user, or log the error and move on to another task.
The default connection timeout value is 15 seconds, but because the SQL Azure Service Level Agreement (SLA) specifies that an SLA violation does not occur until 30 seconds have elapsed, you should set your connection timeout to 30 seconds.
Note: |
|---|
| To retry connections you can use the RetryPolicy delegate in the Microsoft.WindowsAzure.StorageClient namespace. The article at http://blogs.msdn.com/windowsazurestorage/archive/2010/04/22/savechangeswithretries-and-batch-option.aspx describes how to use this delegate to retry saving changes to Windows Azure table storage, but you could adapt this approach to work with a context object in LINQ to SQL or ADO.NET Entity Framework. |
Handling Dropped Connections
If a connection to SQL Azure drops while your application is using the connection, you should immediately try to re-establish the connection. If possible, you should then retry the operation that was in progress before the connection dropped, or in the case of a transaction, retry the transaction. It is possible for a connection to fail between sending a message to commit a transaction and receiving a message that reports the outcome of the transaction. In this circumstance, you must have some way of checking whether the transaction completed successfully in order to determine whether you must retry it.
Diagnostics
The aExpense application uses the Logging Application Block and the Exception Handling Application Block from the Enterprise Library. The cloud-based version of aExpense continues to use these application blocks to help support and operations staff at Adatum troubleshoot problems. Although there are minimal changes required in the application to use these blocks in the cloud version of aExpense, the procedure for accessing the log files is different.
Jana Says: | |
|---|---|
![]() | The Logging Application Block and the Exception Handling Application Block are part of the Enterprise Library. We use them in a number of applications within Adatum. |
For aExpense to write logging information to Windows Azure logs, Adatum made a change to the Web.config file to make the Logging Application Block use the Windows Azure trace listener.
Poe Says: | |
|---|---|
![]() | We want to have access to the same diagnostic data when we move to the cloud. |
<listeners> <add listenerDataType="Microsoft.Practices.EnterpriseLibrary. Logging.Configuration.SystemDiagnosticsTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" type="Microsoft.WindowsAzure.Diagnostics .DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" traceOutputOptions="Timestamp, ProcessId" name="System Diagnostics Trace Listener" /> </listeners>
If you create a new Windows Azure Cloud Service project in Visual Studio, the Web.config file will contain the configuration for the Azure trace listener. The following code example from the Web.config file shows the trace listener configuration you must add if you are migrating an existing ASP.NET web application.
<system.diagnostics>
<trace>
<listeners>
<add type="Microsoft.WindowsAzure.Diagnostics
.DiagnosticMonitorTraceListener,
Microsoft.WindowsAzure.Diagnostics, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=31bf3856ad364e35"
name="AzureDiagnostics">
<filter type="" />
</add>
</listeners>
</trace>
</system.diagnostics>
By default in Windows Azure, diagnostic data is not automatically persisted to storage; instead, it is held in a memory buffer. In order to access the diagnostic data, you must either add some code to your application that transfers the data to Windows Azure storage, or add a diagnostics configuration file to your project. You can either schedule Windows Azure to transfer log data to storage at timed intervals, or perform this task on-demand. Adatum decided to use a diagnostics configuration file to control how the log data is transferred to persistent storage; the advantage of using a configuration file is that it enables Adatum to collect trace data from the Application_Start method where the aExpense application performs its initialization routines. The following snippet shows the sample diagnostics.wadcfg file from the solution.
<?xml version="1.0" encoding="utf-8" ?>
<DiagnosticMonitorConfiguration xmlns="http://schemas.microsoft.com/ServiceHosting/2010/10/DiagnosticsConfiguration"
configurationChangePollInterval="PT1M"
overallQuotaInMB="5120">
<DiagnosticInfrastructureLogs bufferQuotaInMB="1024"
scheduledTransferLogLevelFilter="Verbose"
scheduledTransferPeriod="PT1M" />
<Logs bufferQuotaInMB="1024"
scheduledTransferLogLevelFilter="Verbose"
scheduledTransferPeriod="PT1M" />
<Directories bufferQuotaInMB="1024"
scheduledTransferPeriod="PT1M">
<!-- These three elements specify the special directories
that are set up for the log types -->
<CrashDumps container="wad-crash-dumps" directoryQuotaInMB="256" />
<FailedRequestLogs container="wad-frq" directoryQuotaInMB="256" />
<IISLogs container="wad-iis" directoryQuotaInMB="256" />
</Directories>
<PerformanceCounters bufferQuotaInMB="512" scheduledTransferPeriod="PT1M">
<!-- The counter specifier is in the same format as the
imperative diagnostics configuration API -->
<PerformanceCounterConfiguration
counterSpecifier="\Processor(_Total)\% Processor Time" sampleRate="PT5S" />
</PerformanceCounters>
<WindowsEventLog bufferQuotaInMB="512"
scheduledTransferLogLevelFilter="Verbose"
scheduledTransferPeriod="PT1M">
<!-- The event log name is in the same format as the
imperative diagnostics configuration API -->
<DataSource name="System!*" />
</WindowsEventLog>
</DiagnosticMonitorConfiguration>
The value of the overallQuotaInMB must be more than the sum of the bufferQuotaInMB values in the diagnostics.wadcfg file, and you must configure a local storage resource in the Web role named "DiagnosticsStore" that is at least the size of the overallQuotaInMB value in the diagnostics configuration file. In this example, the log files are transferred to storage every minute and you can then view them with any storage browsing tool such as the Server Explorer window in Visual Studio.
For more information about thediagnostics.wadcfg file, see. This blog post also contains some useful tips: |
|---|
| http://msdn.microsoft.com/en-us/library/gg604918.aspxhttp://blogs.msdn.com/b/davidhardin/archive/2011/03/29/configuring-wad-via-the-diagnostics-wadcfg-config-file.aspx. |
Bharath Says: | |
|---|---|
![]() | Because persisting diagnostic data to Windows Azure storage costs money, we will need to plan how long to keep the diagnostic data in Windows Azure and how we are going to download it for offline analysis. |
Setup and Physical Deployment
When you're developing an application for Windows Azure, it's best to do as much development and testing as possible by using the local Compute Emulator and Storage Emulator. When the application is ready, you can deploy it to Windows Azure for further testing. You shouldn't need to make any code changes before deploying to Windows Azure, but you will need to make sure that you upload any certificates that the application requires and update the configuration files for the Windows Azure environment.
Note: |
|---|
| You can upload SSL certificates to Windows Azure by using the Windows Azure Developer Portal at http://windows.azure.com/ or by using a script. For information about how to upload certificates by using a Windows PowerShell™ command line script, see Chapter 5, "Phase 2: Automating Deployment and Using Windows Azure Storage." |
Role Instances, Upgrade Domains, and Fault Domains
Deploying multiple instances of web roles and worker roles is an easy way to scale out your application to meet increased demand. It's also easy to add or remove role instances as and when you need them, either through the Windows Azure Developer Portal or by using scripts, so you only pay for the services you actually need. You can also use multiple role instances to enable fault tolerant behavior in your application, and to add the ability to perform "live" upgrades of your application.
Use multiple role instances to scale out your application, add fault tolerance, and enable in-place upgrades.
If you have two or more role instances, Windows Azure organizes them into virtual groupings known as upgrade domains. When you perform an in-place upgrade of your application, Windows Azure upgrades a single domain at a time; this ensures that the application remains available throughout the process. Windows Azure stops, upgrades, and restarts all the role instances in the upgrade domain before moving on to the next one.
Note: |
|---|
| There are some limitations to the types of upgrade that you can perform like this. In particular, you cannot modify the service configuration or add or remove roles from the application. You can also specify how many upgrade domains your application should have in the service configuration file. |
In Windows Azure, fault domains are a physical unit of failure. If you have two or more role instances, Windows Azure will allocate them to multiple fault domains, so that if one fault domain fails, there will still be running instances of your application. Windows Azure determines how many fault domains your application uses.
Windows Azure also ensures upgrade domains and fault domains are orthogonal, so that the role instances in an upgrade domain are spread across different fault domains.
Deployment Scripts
Manually modifying your application's configuration files before you deploy the application to Windows Azure is an error-prone exercise. The developers at Adatum have developed a set of deployment scripts that automatically update the configuration files, package the application files, and upload the application to Windows Azure. You'll see more of these scripts later.
Using a Mock Issuer
By default, the downloadable version of aExpense is set up to run on a standalone development workstation. This is similar to the way you might develop your own applications. It's generally easier to start with a single development computer.
Poe Says: | |
|---|---|
![]() | Using a simple, developer-created claims issuer is good practice during development and unit testing. |
To make this work, the developers of aExpense wrote a small stub implementation of an issuer. You can find this code in the downloadable Visual Studio solution. The project is in the Dependencies folder and is named Adatum.SimulatedIssuer.
When you first run the aExpense application, you'll find that it communicates with the stand-in issuer. The issuer issues predetermined claims.
It's not very difficult to write this type of component, and you can reuse the downloadable sample, or you can start with the template included in the Windows Identity Foundation (WIF) SDK.
Note: |
|---|
| You can download the WIF SDK from the Microsoft Download Center. The book, "A Guide to Claims-Based Identity and Access Control," describes several ways you can create a claims issuer. You can download a PDF copy of this book from http://msdn.microsoft.com/en-us/library/ff423674.aspx. |
Converting to a Production Issuer
When you are ready to deploy to a production environment, you'll need to migrate from the simulated issuer that runs on your development workstation to a component such as ADFS 2.0.
Making this change requires two steps. First, you need to modify the Web application's Web.config file using the FedUtil utility such that it points to the production issuer. Next, you need to configure the issuer so that it recognizes requests from your Web application and provides the appropriate claims.
Note: |
|---|
| To learn more about FedUtil and configuring applications to issue claims, take a look at the book, "A Guide to Claims-Based Identity and Access Control." You can download a PDF copy of this book from http://msdn.microsoft.com/en-us/library/ff423674.aspx. |
You can refer to documentation provided by your production issuer for instructions about how to add a relying party and how to add claims rules.
When you forward a request to a claim issuer, you must include a wreply parameter that tells the claim issuer to return the claims. If you are testing your application locally and in the cloud, you don't want to hard code this URL because it must reflect the real address of the application. The following code shows how the aExpense application generates the wreply value dynamically in the Global.asax.cs file.
Building the wreply parameter dynamically simplifies testing the application in different environments.
private void
WSFederationAuthenticationModule_RedirectingToIdentityProvider
(object sender, RedirectingToIdentityProviderEventArgs e)
{
// In the Windows Azure environment, build a wreply parameter
// for the SignIn request that reflects the real
// address of the application.
HttpRequest request = HttpContext.Current.Request;
Uri requestUrl = request.Url;
StringBuilder wreply = new StringBuilder();
wreply.Append(requestUrl.Scheme); // e.g. "http" or "https"
wreply.Append("://");
wreply.Append(request.Headers["Host"] ??
requestUrl.Authority);
wreply.Append(request.ApplicationPath);
if (!request.ApplicationPath.EndsWith("/"))
{
wreply.Append("/");
}
e.SignInRequestMessage.Reply = wreply.ToString();
}
Isolating Active Directory
The aExpense application uses Windows Authentication. Because developers do not control the identities in their company's enterprise directory, it is sometimes useful to swap out Active Directory with a stub during the development of your application.
The on-premises aExpense application (before the migration) shows an example of this. To use this technique, you need to make a small change to the Web.config file to swap Windows Authentication for Forms Authentication and then add a simulated LDAP profile store to the application. Swap Windows Authentication for Forms Authentication with the following change to the Web.config file.
<authentication mode="Forms">
<forms name=".ASPXAUTH"
loginUrl="~/SimulatedWindowsAuthentication.aspx"
defaultUrl="~/default.aspx" requireSSL="true">
</forms>
</authentication>
You need to add a logon page to the application that enables you to select the user that you want to use for testing. In aExpense, this page is known as SimulatedWindowsAuthentication.aspx.
You also need to add a class that simulates an LDAP lookup for the Active Directory attributes that your application needs. In this example, the GetAttributes method simulates the LDAP query "&(objectCategory=person)(objectClass=user);costCenter;manager;displayName".
public static class SimulatedLdapProfileStore
{
public static Dictionary<string, string> GetAttributesFor(
string userName, string[] attributes)
{
Dictionary<string, string> results;
switch (userName)
{
case "ADATUM\\johndoe":
results = new Dictionary<string, string>
{
{ "costCenter", "31023" },
{ "manager", "ADATUM\\mary" },
{ "displayName", "John Doe" }
};
break;
…
}
return results;
}
}
Note: |
|---|
| These code samples come from the BeforeAzure solution in the downloadable solutions. |
SQL Server
At this stage, the development team at Adatum is working with sample data, so the deployment script builds a sample database in SQL Azure. They will need to create a script that transfers data from the on-premises version of SQL Server to Windows Azure, when they come to migrate the live application. To migrate an existing database schema to SQL Azure, you can use SQL Server Management Studio to export the schema as a Transact-SQL script, and then run the script against SQL Azure. To move data to SQL Azure, you can use SQL Server Integration Service. However, the team is planning to investigate whether they need SQL Azure at all, or whether the application can utilize Windows Azure table storage. Therefore, they haven't spent any time yet developing a data migration strategy.
Note: |
|---|
| You can get an overview of the limitations of SQL Azure that are important to be aware of at http://msdn.microsoft.com/en-us/library/ff394102.aspx. |
Note: |
|---|
| You can get an overview of how to migrate a database to SQL Azure at http://msdn.microsoft.com/en-us/library/ee730904.aspx. You can also use the SQL Azure Migration Wizard at http://sqlazuremw.codeplex.com/ to help you to migrate your local SQL Server databases to SQL Azure |
Accessing Diagnostics Log Files
The on-premises version of aExpense uses the Logging Application Block and the Exception Handling Application Block to capture information from the application and write it to the Windows event log. The Windows Azure version of the application continues to use the same application blocks, and through a configuration change, it is able to write log data to the Windows Azure logging system. However, to access the log data in Windows Azure, you have to perform a few more steps. First, you need to save the log data to persistent storage. You can do this manually by using the Windows Azure Developer Portal, or you can add code or a diagnostics.wadcfg file to your application to dump the log data to storage at scheduled intervals. Second, you need to have some way of viewing the log data in Windows Azure storage.
Poe Says: | |
|---|---|
![]() | To access your log files in Windows Azure, you can find a utility that lets you access your Windows Azure storage remotely or develop some scripts that download them for you on a regular basis. |
For detailsabout some tools you can use to manage the log datasee the list oftools at: |
|---|
| http://www.microsoft.com/windowsazure/tools/. |
More Information
You can download the latest versions of Windows Azure Tools for Microsoft Visual Studio and the Windows Azure SDK from the Microsoft Download Center.
MSDN contains plenty of information about Windows Azure and SQL Azure. A good starting place is at http://msdn.microsoft.com/en-us/library/dd163896.aspx.
The Windows Azure Getting Started page (http://www.microsoft.com/windowsazure/getstarted) contains links to plenty of resources to help you learn about developing applications for Windows Azure.
Poe Says:




