Just Coding

.NET developer spanish bits

Advanced Configuration for Windows Azure NET Applications

Advanced (and flexible) Configuration for Windows Azure .NET Applications

Summary

We have created a tool that allows you to configure .Net applications running in Windows Azure in the same way you do with traditional On-Premise applications. In this article we are going to explain the motivations, current alternatives and the final solution that we have found to write this tool.

Authors

@ridomin & @ralarcones .Madrid, February 2012.

Widows Azure Configuration Basics

One of the main differences of Windows Azure applications versus standard On Premise applications, are the way you manage the configuration of your application. Because you have no physical control of the machines involved in your solution, you cannot use the same tools to manage the application.

Before continuing reading you should be familiar with the configuration basics of .NET and Azure platforms, so consider reading

Configuring a Windows Azure Application

 .NET Configuration Files

In this article we will refer to application configuration as .config, and service configuration as .cscfg

 

In first place, the setup mechanism based on .cspkg/.cscfg files imposes you some rules you have to follow in order to be “true Azure complaint”:

1)      You should assume the contents of  the .cspkg will be the same to all the roles you deploy in a single Hosted Service

2)      If you change any file of your application, this change will not be propagated to the rest of instances of your deployment, and in case of re-imaging, your changes will be lost.

3)      The only way to change the configuration of the application is using .cscfg files

The old .net configuration system

In the other hand, we have the well-known .net configuration approach, where the configuration files (web.config or app.config) are an essential part of any .net application, not only to store custom configuration parameters, but also to use some framework features as: diagnostics, asp.net behaviors and also runtime internals details.

However the configuration file is included in the .cspkg package, and there is no relation with the default Azure configuration: the .cscfg files. So if you want to change the configuration files you will have prepare a different package.

The Release Management Requirements

In professional development (in general) you will find also some basic rules that you must follow in order to adopt any process or methodology, like:

1)      The application should be able to be deployed to different environments (Development, Integration, Testing or Production), in order to have a formal testing based on versioning releases

2)      The different versions should be promoted to different environments based on its quality.

3)      The operations team need to be able to change configuration settings without affecting service availability

So the basic artifacts generated at build time, are just enough for deploy to just one environment, as you can see in the next diagram:


As you can see there are no easy relationship between these two worlds, in one side you have the .NET runtime to be highly dependent on the default configuration mechanisms, in the other you have the Azure configuration limitations, and there is no easy approach to satisfy both worlds’ requirements.

Out –Of-The- Box Configuration

At first glance, the Windows Azure SDKs, allows you to add configuration parameters to the .cscfg file that you can read from your application, so you can change this parameters without deploying a different .cspkg. But with this approach you will have to know that

1)      This settings can only be accessed when you application runs in an Azure environment

2)      You are limited to you custom parameters only (like appSettings ), not .NET standard configuration

About the first point you could think that if you are developing a Windows Azure application, what’s wrong using the emulator (aka DevFabric) ? There is nothing wrong, but it will decrease your development flexibility, so things like UnitTesting, Profiling, CodeCoverage, or Build Tools will be affected with the current status of the DevFabric. Not to mention that you could not have an OnPrem environment to test your application, because the DevFabric is designed to be used only in the developer machine.

Although the Azure diagnostics tools allows you to do incredible things, like intelli-trace debugging, remote profiling, or use of extensive diagnostics, there is nothing like “self-own hardware” to really debug and tune you application. Also there is one fact no one should forgot:

“If you application does not scale/perform well OnPrem it will not do on Azure (opposite is not true)”

In case you assume all this limitations, you still have the problems derived with 2). How could you change .net configuration settings that are not exportable to the service configuration?.

Current Trends

To solve all the issues mentioned above there are two main approaches in the development community:

1)      Use the .config transforms, and build-time tools to generate different configuration for each of your environments. See http://blogs.msdn.com/b/tomholl/archive/2011/12/06/automated-build-and-deployment-with-windows-azure-sdk-1-6.aspx

2)      Use a more dynamic approach based on external configuration files stored outside of your application, like Blobs. The Enterprise Library 5.0 integration pack, allows to load the EntLib configuration from Blob files, but only the EntLib configuration.

But one more time, any of this approaches satisfy the basic requirements we mention, the first one because is not desirable to have to know all the environment details at build time, neither to have different packages for each environment, or the fact that you will need to create a new package to change some basic .net configuration. And the second approach only solves problems if you are already using the EntLib.

A new Solution

So we have a new solution that allows you to obtain the better of these two worlds, while respecting well-know ALM practices. So we started with the next requirements:

1)      The Azure Package .cspkg needs to be completely independent from the environment, including standard .net application configuration settings .config files

2)      The configuration can be changed without creating a new package

3)      All the configuration information has to be included in the service configuration .cscfg file

In order to satisfy these requirements, we propose the next process:

1)      At Build time, the main Azure artifacts are created. The .cspkg will contains all the files required by the application, including the “default” web.config. The .cscfg has to be prepared with all the properties that could change.

2)      At configuration time, the release manager creates the config files for each environment; let’s call this file Env-X.Web.config.

3)      A config tool will add the parameterized settings defined in the default .cscfg, with the values defined in the Env-X.Web.config, and create a new Env-X.cscfg for each environment.

4)      The application will be deployed to a Hosted Service using the .cspkg and the Env-X.cscfg

5)      At Role start-up, the values added to the Env-X.cscfg will be written to the default web.config.

With this approach you can leverage all the benefits of the Azure platform while maintaining the flexibility of the .Net framework, based on a change-allowed configuration files.

Putting the new solution in practice

Configuration Replacement

In order to fulfill the application lifecycle requirements and put in practice the new solution we will need a way to define which application configuration settings we want to be able to modify as well as a way to replace these configuration settings.

The strategy is simple: before the Azure application starts, we will be changing the application configuration (traditional .Net configuration) with the values stored in the service configuration (Azure configuration). This will let us make dynamic configuration changes over the same package without having to generate different deployment packages already pre-configured.

The Service Definition

At development time, we define the configuration values that we want to be able to change. Considering simplicity, we are going to change the application configuration sections at once. In the Service Definition, we add new settings for that matter: the appSettings and connectionStrings.

In order to easily deal with the values with in the .cscfg file, we will store them as Base64 strings. Then, for each environment, we create the corresponding Service Configuration Env-X.cscfg files with the current configuration values.

In example, for the development environment our application has the following appSettings and connectionStrings configuration section in the web.Config file:

  <appSettings>

    <add key="webpages:Version" value="1.0.0.0" />

    <add key="ClientValidationEnabled" value="true" />

    <add key="UnobtrusiveJavaScriptEnabled" value="true" />

    <add key="SampleSetting" value="Development Environment Configuration" />

  </appSettings>

 
  <connectionStrings>
    <add 
         name="ApplicationServices" 
         connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;..."
         providerName="System.Data.SqlClient" />
    <add 
         name="DefaultConnection" 
         connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=aspnet..." 
         providerName="System.Data.SqlClient" />
  </connectionStrings>

 

 

So in the Env-X.cscfg file, we store the Base64 strings for these sections:

         <Setting 
                 name="ServiceConfigSync.appSettings" 
                 value="ICA8YXBwU2V0dGluZ3M+DQogICAgPGFkZ...V0dGluZ3M+" 
         />
         <Setting 
                 name="ServiceConfigSync.connectionStrings" 
         value="ICA8Y29ubmVjdGlvblN0cmluZ3M+DQogICAgPGFkZ...pbmdzPg==" 
         />
 

When we deploy the application to the Azure development environment we select the Env-Development.cscfg as configuration file.

Changing the configuration at Role start-up

Now, we have the actual application configuration values in the Service Configuration file so we need to replace the application configuration sections with those within the Service Configuration every time our Azure application starts. Following is the algorithm that we need to apply:

  1. 1.       Locate the current application configuration file
  2. 2.       For each configuration section stored in the Service Configuration file:
    1. a.       Read current value.
    2. b.      Decode the Base64 string.
    3. c.       Replace the content in the application configuration file.
  3. 3.       Refresh the application configuration.

To do so, we extend the RoleEntryPoint class and override the OnStart method and implement the algorithm. For Worker Role applications, the class already exists on our project, for Web Role applications we need to add a new class which derives from RoleEntryPoint.

The application configuration file location vary depending of which kind of role we are dealing with: in Worker Roles the configuration file is located in the application execution path; in Web Roles the web.Config file is in the path where the web application is deployed. Due to in Web Role applications the RoleEntryPoint.OnStart runs before the Web application domain is loaded, we have to use the ServerManager class to identify the Web Role virtual directory in IIS and obtain the physical path where it is deployed:

static private string GetRoleConfigPath()
{
   string configPath = String.Empty;
   bool configFound = false;
   using (ServerManager srvMgr = new ServerManager())
   {
      foreach (Site s in srvMgr.Sites)
      {
         if (s.Name.Contains(RoleEnvironment.CurrentRoleInstance.Id))
         {
            configPath = Path.Combine(s.Applications[0]
                         .VirtualDirectories[0]
                         .PhysicalPath, "Web.Config");
            configFound = true;
            break;
          }
       }
   }
   if (!configFound)
   { 
      configPath = Path.Combine(System.Environment.CurrentDirectory, 
                 RoleEnvironment.CurrentRoleInstance.Role.Name + ".dll.config");
   }
   return configPath;
}

To be able to change in the application configuration file, our Role must run with enough privileges as needed modify files. To ensure these privileges we have to define the execution context as “elevated” in the Service Configuration Definition (.csdef file):

<ServiceDefinition name="UseServiceConfig" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
  <WebRole name="SampleWeb" vmsize="Small">
    <Runtime executionContext="elevated"/>
         ...

 

Finally, to refresh the application configuration we have to consider that there is a difference depending on which kind of Role we have: for the Web Roles, the changes are automatically applied due to the .net infrastructure do so every time the web.config file is modified; for Worker Roles, we need to explicitly refresh every section modified using the ConfigurationManager.RefreshSection method.              

Propagating configuration changes

Once our service is deployed and started for the very first time, the value for application configuration sections are replaced during the Role start-up event, this strategy allow us to have different service configuration files (Env-X.cscfg) to be used with the same deployment package.

But, what happen with the current strategy if we need to make a configuration change to an already deployed service? Imagine that we want to change the diagnostics trace level just during the time we need to evaluate and diagnose some kind of problem. We can upgrade the service configuration file changing the section that we want (i.e. system.diagnostics) but with the approach described till now, we need to stop and start the service deployment in order make the configuration replacement.

To avoid the inconveniences of service deployment re-starts (time consuming, service disruption…), we need to make some work to propagate the changed configuration values to the application configuration. At this point, we need to use to the RoleEnvironment.Changed event which provides the Changes property that contains the collection of configuration changes that were applied to the instance. We need to implement an event handler in order to propagate the changes to the application configuration. Our event handler can be as follows:

  1. 1.        Review the Changes collection to check if there are changes in one or more of the application configuration sections previously defined (values added in the Service Definition file).
  2. 2.       If there are changes, we have to replace them into the application configuration file (the web.config or the app.config file).
  3. 3.       Finally, we need to refresh the application configuration.

With this event handler, we can have a valid mechanism to propagate hot configuration changes to the application without having to re-start service deployments.

Monitoring the configuration replacement

Other important aspect of this configuration replacement is about how to know if our configuration is being applied correctly to the application, what values are being applied to the application and, in the case that has been some issues, a mechanism to understand what is happening.

First, we will need to be able to monitor the applied configuration values: usually we need this during the initial deployment phases, when we are using new configuration values and we need to ensure that we haven’t made any mistake.

Then, once we are comfortable with the configuration values, we will need to be able to monitor if the configuration replacement is done as a whole, we don’t need to keep an eye in which exactly values are applied, instead of that, knowing if the configuration replacement is correctly applied will be enough.

To fulfill both requirements we propose to generate to different kind of events:

-          Tracing events to register every configuration section replacements. The tracing will include detailed information on what are the values that will replace the configuration sections.

-           Traditional event log entries to register the if the configuration is being replaced correctly:

  • o   An event to register that the configuration replacement is initiated.
  • o   An event to register that the configuration replacement is finalized.
  • o   And an event to register any exception or issue while the replacement is done.

Finally, we can use the Windows Azure Diagnostics infrastructure and save the events in a storage account which avoid us to connect to the service deployment instances to see if our configuration is correctly applied or review which configuration values are being applied.

The configuration tool

To easily manage the service configuration files, the configuration sections content and all the complexity related to generate the appropriate Env-X.cscfg files, in our prototype we have developed a configuration tool that allow us to:

-         

void UpdateSection(string sectionName)
{
    var sourceNode = wc.Descendants(sectionName).FirstOrDefault();
 
    if (sourceNode != null)
    { 
        string b64 = Convert.ToBase64String(
                    ASCIIEncoding.ASCII.GetBytes(sourceNode.ToString()));
        var targetNode = (from n in sc.Descendants(NS + "Setting")
                            where n.Attribute("name").Value == PREFIX + sectionName
                            select n).SingleOrDefault();
        targetNode.SetAttributeValue("value", b64);
    }
}

 


For each section, read the original values from the web config (wc)

-          Convert to Base64 and store it in the Service Configuration (sc)

-           Store this values in service configuration

 

Futures

We have plans to extend this configuration tool in a way that helps in the whole application lifecycle, generating and managing all the environment dependent configuration files and the changes that we have to deal with. So stay tuned!!

Blog - Post Feedback Form(CAPTCHA)