Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Modern Configuration for ASP.NET 4.7.1 with ConfigurationBuilders

0.00/5 (No votes)
21 Nov 2017 1  
Modern configuration for ASP.NET 4.7.1 with ConfigurationBuilders

I've been thinking and working with application configuration in ASP.NET applications for years, and it's become a tool that I'm very comfortable using. I can add AppSettings, create configuration sections, and manage connectionstrings without thinking twice. However, there is a problem with the current ConfigurationManager and the XML-based config file offering in the .NET Framework: how do I get configuration entries from other sources into my application so that I don’t need to build my own configuration client and tools? I just want to continue using the standard syntax to access appsettings like this:

var serviceId = ConfigurationManager.AppSettings["ServiceID"];

Introducing ConfigurationBuilders

Web.config and app.config have always been able to read external XML files, and assimilate their contents into .NET Configuration. In order to get application configuration from more sources, the ASP.NET team added the ConfigurationBuilder feature. The idea is simple: you add notation to your web.config or app.config for the ConfigurationBuildersSection and then you can load external configuration builders that will populate or modify the contents of a designated section. Let’s take a look at updating an application to get configuration from environment variables. Our standard configuration, stored in a web.config file, would look something like this:

<configuration>
	<appSettings>
		<add key="ServiceID" value="JeffsService" />
		<add key="ServiceKey" value="TopSecret" />
	</appSettings>
	
	<connectionStrings>
		<add name="default" connectionString="Data Source=mydb.db" />
	</connectionStrings>

...

</configuration>

To illustrate these configuration values, I wrote a simple application that output the values of appsettings to a web page. That page looks like this:

Outputting Configuration from Config File

If we wanted to replace the appsettings for the ServiceID and ServiceKey, as well as point the defaultConnectionString at a new value provided by an environment variable, I can introduce a ConfigurationBuilder that will read the environment variables and replace these values in the ConfigurationManager that provides configuration data to my application. We can introduce the configuration builder by adding some simple markup to our configuration file:

<configuration>
  
  <configSections>
		<section name="configBuilders" 



       type="System.Configuration.ConfigurationBuildersSection, 
       System.Configuration, Version=4.0.0.0, Culture=neutral, 
       PublicKeyToken=b03f5f7f11d50a3a" restartOnExternalChanges="false" requirePermission="false"/>
	</configSections>

  <configBuilders>
		<builders>
			<add name="Env" 



         type="MyConfigBuilders.EnvironmentConfigBuilder, MyConfigBuilders" />
		</builders>
	</configBuilders>
  
	<appSettings configBuilders="Env">
		<add key="ServiceID" value="JeffsService" />
		<add key="ServiceKey" value="TopSecret" />
	</appSettings>
 
	<connectionStrings configBuilders="Env">
		<add name="default" connectionString="Data Source=mydb.db" />
	</connectionStrings>

...

</configuration>

The introduction of the configBuilders section with an entry for the configuration builder we want to use is simple markup that can be added to any configuration file. The catch is adding the configBuilders attribute to the sections that you want to apply the config builder to. In this case, we added it to the appSettings and connectionStrings elements. When the ConfigurationManager is first used and parses this file, it will load the configurationbuilder named Env in the configBuilders section and hand these sections to it for parsing. The Env entry points to a class called EnvironmentConfigBuilder whose source looks like:

public class EnvironmentConfigBuilder : ConfigurationBuilder
	{
		private readonly IDictionary _EnvVars;

		public EnvironmentConfigBuilder()
		{
			_EnvVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process);
			if (_EnvVars.Count == 0) _EnvVars = Environment.GetEnvironmentVariables();

			Debug.WriteLine(_EnvVars.Count);
		}

		public override XmlNode ProcessRawXml(XmlNode rawXml)
		{
			foreach (DictionaryEntry envVar in _EnvVars)
			{
				var pair = (Key: envVar.Key.ToString(), Value: envVar.Value.ToString());

				if (rawXml.HasChildNodes 
					&& rawXml.SelectSingleNode($"add[@key='{pair.Key}']") != null)
				{
					rawXml.SelectSingleNode($"add[@key='{pair.Key}']")
						.Attributes["value"].Value = pair.Value;
				}
			}

			return rawXml;			
		}

		public override ConfigurationSection ProcessConfigurationSection(
			ConfigurationSection configSection)
		{
			return base.ProcessConfigurationSection(configSection);
		}
	}
}

That’s a pretty simple class that processes the XML handed to it, and replaces the values with any matching environment variable names. In a sample application that reports its appsettings values on a web page, I would see the following with appropriate values set in my production space:

Settings Overridden from Environment Variables

Settings Overridden from Environment Variables in Production

Usage with Docker

This means that we can use this same application with the configuration builders attached and push settings into our container from outside. If we build this application with the Docker for Windows image microsoft/aspnet:4.7.1, we can then inject settings from outside the instance of the container. I’ll run my container with a command like the following:

docker run -d -p 80:80 -e ServiceID=Docker -e ServiceKey=DockerKey myapp

... and if I browse to my running container on Windows, I’ll now see the following:

AppSettings Overridden in a Docker Container

Summary

With no code changes, we’re able to inject settings into our application from an outside source that isn’t just another file. You can write configuration builders that read configuration from any source, and just update your web.config to consume that new configuration builder. In the weeks ahead, look for an official set of configuration builders from the ASP.NET team that supports JSON files, environment variables, and a number of other sources. I’ve even heard a request to write a configuration builder to read from an INI file.

Stay tuned, as we make using your applications in containers and on cloud services even easier.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here