Externalizing ASP.NET Config

For ASP.NET applications, most configuration is embedded in a web.config file or some file that is ultimately loaded by or referenced from the parent web.config. In a cloud application, this becomes an anti-pattern because you need the same deployment artifact to be deployable to multiple environments without changes to support different configurations.

Connection strings in web.config are typically included in the connectionStrings XML element when using some standard Microsoft libraries for data access like Entity Framework. If you’re doing things a little outside the box, you might include a connection string as a simple key-value pair in the appSettings XML element in your configuration file.

Either way, your application needs the ability to override these with cloud-supplied values.

Example connection string in web.config:

  <add name="dbConnection" connectionString="metadata=res://*/;provider=System.Data.SqlClient;provider connection string=`Data Source=....`"/>

If you remove this entirely, then the application will likely not be able to work remotely. So the accepted practice for short term replatforming rather than modernization would be to leave the web.config settings as the local default, and then detect bound services that potentially override that.

You might have centralized code that provides a connection string to the rest of your code, as shown in this VB.NET example:

Protected Friend Shared Function EFConnectionString() as String
    Return System.Web.Configuration.WebConfigurationManager.ConnectionStrings("EFSQLConnStr").ConnectionString
End Function

In this case, you would want to perform the following steps in a re-write of this function:

  1. Detect the presence of the VCAP_SERVICES environment variable
  2. If available, parse it (it’s JSON)
  3. Locate the service you’re expecting, which might be called efsql (though you’ll probably want more informative names)
  4. Extract the SQL connection string from it and return that value
  5. If none of 1-4 worked, then return the fallback string, which can be found in web.config

In some cases, applications just use the default parameterless constructor for Entity Framework entity sets, which uses a default naming convention in web.config. You will want to override this behavior such that your application is directly responsible for providing the connection string. This will allow your application to go through the 4 logical steps outlined above prior to delivering a connection string to the code requesting it.

Backing Services (Web and others)

This pattern of externalizing the connection string for a data source must also be followed for all other backing services, including (but not limited to) SOAP services, RESTful web services, SMTP/mail server information, LDAP/security server information, and any other configuration property that can vary from environment to environment without the application deployment artifact changing.

When you are done externalizing your configuration, your application should be able to pass the following litmus test:

  • If you were to open-source your application tomorrow, would the codebase contain any URLs, usernames, passwords, host names, or other internal information that should not be publicly visible? All of these things should be fed into the application from an external source (e.g. bound services via Cloud Foundry), and never embedded in web.config or source code.