Click here to Skip to main content
15,881,204 members
Articles / Web Development / ASP.NET

Modern Configuration for ASP.NET 4.7.1 with ConfigurationBuilders

Rate me:
Please Sign up or sign in to vote.
4.00/5 (2 votes)
21 Nov 2017Ms-PL3 min read 20.4K   7   3
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:

C#
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:

XML
<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:

XML
<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:

C#
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, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
Program Manager
United States United States
Jeff Fritz is a senior program manager in Microsoft’s Developer Division working on the .NET Community Team. As a long time web developer and application architect with experience in large and small applications across a variety of verticals, he knows how to build for performance and practicality. Four days a week, you can catch Jeff hosting a live video stream called 'Fritz and Friends' at twitch.tv/csharpfritz. You can also learn from Jeff on WintellectNow and Pluralsight, follow him on twitter @csharpfritz, and read his blog at jeffreyfritz.com

Comments and Discussions

 
QuestionHow to use secrets.xml for connectionstring? Pin
David Pierson24-May-21 15:18
David Pierson24-May-21 15:18 
QuestionHow to Config in Docker Support in VS2017 ? Pin
Member 1194109130-Oct-18 0:52
Member 1194109130-Oct-18 0:52 
QuestionProcessConfigurationSection in ConfigurationBuilder .net 4.7.1 Pin
Reza71121-Mar-18 2:09
Reza71121-Mar-18 2:09 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.