Overwriting configuration values with environment variable in ASP.NET Core
Image from Pixabay

Overwriting configuration values with environment variable in ASP.NET Core

Using environment specific variables to overwrite configuration values in ASP.NET Core

It is obvious that no matter what is the size and complexity of your application, configuration values on your local development machine and the environment where the application is going to run will be different. To avoid any hard-coding and recompilation of your code, the most common practice is to store application and environment specific values to configuration files.

Although ASP.NET Core provides great out of the box solution for having multiple configuration files depending on the environment (Use multiple environments in ASP.NET Core), there are still things that should not reside in the configuration files.

With everyday growing cloud code repositories, especially public ones supported by companies, it is quite easy to by mistake submit environment specific configuration values which should be available only on the environment and in some cases not even available to developers that are working on a project. The best solution for these cases would be using any type of values such as Azure Key Vault if you host your application the Azure Cloud or perhaps HashiCorp Vault if you are hosting your application premises. In cases when you are not working on a large size application this can be an overhead in terms of infrastructure or maybe even cost. For small size application environment variables look like a reasonable place to store environment specific values.

Note

There are some cons in storing application parameters to environment variables apporach especially if you do not encrypt values you store in environment variables. Another concern is that environment variables are available to all processes running on your host. This can be a potential security vulnerability.

We are not going to focus much on the security perspective in this article but rather to see how you can use environment variables as your configuration in ASP.NET Core without making any changes to code.

Simple JSON configuration on ASP.NET Core

To start simple let's see how configuration works out of the box with ASP.NET Core project template and JSON files. I created two config files where first one (appconfig.json) is the default one and second one (appsetting.Development.json) is the one that will be loaded if environment is set to Development (environment variable ASPNETCORE_ENVIRONMENT). Default environment for ASP.NET Core is Production, but since we are running our project from Visual Studio on local we have this value set to Development in lauchSettings.json file.

{
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:65230",
      "sslPort": 44389
    }
  },
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "api/default",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "ConfigSample.Api": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "api/default",
      "applicationUrl": "https://localhost:5001;http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

    

Development launch configuration (lauchSettings.json) file is quite convenient for cases where you rely on environment variables. You can test you application behavior by just modifying this file and running your code from Visual Studio IDE

Note

launchSettings.json is by default listed as ignored file in .gitignore in Visual Studio gitignore template https://github.com/github/gitignore/blob/master/VisualStudio.gitignore which makes it a lot safer for storing credentials than storing them to configuration file if you are not using any type of secrets storage or vaults. It makes pushing your secrets to Git repository more unlikely that with JSON configuration files as it is by default ignored for the commits you make

And this is Development environment configuration file. To make things easier to debug and more obvious I added DEV to configuration values. 

appsettings.Development.json 

{
  "AppName": "My Application name DEV",
  "ApiOptions": {
    "Name": "Option name DEV",
    "Desciption": "Option description DEV",
    "Enabled": true
  }
}

    

To avoid using strings all around your project I strongly recommend using Options pattern. For our sample application, options model would look like the following

using System;

namespace ConfigSample.Api.Options
{
    public class ApiOptions
    {
        public String Name { get; set; }
        public String Description { get; set; }
        public Boolean Enabled { get; set; }
    }
}

    

Once you have your configuration options model, only thing lesft is to configure it in Startup.cs class. 

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.Configure<ApiOptions>(Configuration.GetSection("ApiOptions"));
        }
    

Consuming options is quite easy as it is injected into constructors of the controller. You can see in the following snippet that there are no hard-coded strings as it would be the case if you access injected IConfiguration implementation instance as you would usually do if you are no using options pattern

using System;
using ConfigSample.Api.Options;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;

namespace ConfigSample.Api.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class DefaultController : ControllerBase
    {

        IConfiguration _configuration;
        ApiOptions _options;

        public DefaultController(IConfiguration configuration, IOptions<ApiOptions> options)
        {
            _configuration = configuration;
            _options = options.Value;
        }

        [HttpGet]
        public String GetName()
        {
            return _configuration.GetValue<String>("AppName");
        }

        [HttpGet("options")]
        public ApiOptions GetOptions()
        {
            return _options;
        }

    }
}
    

Let's try out if the configuration is working and we are getting values with DEV. We have two endpoints so here is the output from both

Config Dev

The second endpoint returns configuration section as a model

Config Options Dev

Overriding config values with environment variables

Now when we have our configuration in place and running properly, we can see how ASP.NET Core uses environment variables to override configuration files values.

Since we are going to test this in debug mode from Visual Studio, updating launchSettings.json file. to have clear results in the POSTMAN response, I replaced DEV values with local

{
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:65230",
      "sslPort": 44389
    }
  },
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "api/default",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "AppName": "My Application name LOCAL",
        "ApiOptions__Name": "Option name LOCAL"
      }
    },
    "ConfigSample.Api": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "api/default",
      "applicationUrl": "https://localhost:5001;http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "AppName": "My Application name LOCAL",
        "ApiOptions__Name": "Option name LOCAL"
      }
    }
  }
}

    

Note that I am overriding both AppName configuration key and also key which is in ApiOptions section. To set value which sits inside section it is recommended to use "__" instead of colon ":" since first option works on all platforms while second one may cause different issues on different platforms.

Let's see what will be the output in POSTMAN

Config Local

And options endpoint is also updated since IOptions basically relies on IConfiguration with only binding added on top

Config Options Local

Setting up environment variables on a Windows host

If you are running your applications on Windows host you can also try it out by setting environment variables from Windows options or running the following command from elevated permissions (Administrator) console window.

rundll32.exe sysdm.cpl,EditEnvironmentVariables

Or you can do it directly from the elevated console window

setx /M ASPNETCORE_ENVIRONMENT "Development"
setx /M AppName "My Application name LOCAL"
setx /M ApiOptions__Name "Option name LOCAL"

To check more options on setting ASP.NET Core environment variables on different types of hosts you can check Different ways to set environment variable for .NET Core application article.

References

Disclaimer

Purpose of the code contained in snippets or available for download in this article is solely for learning and demo purposes. Author will not be held responsible for any failure or damages caused due to any other usage.


About the author

DEJAN STOJANOVIC

Dejan is a passionate Software Architect/Developer. He is highly experienced in .NET programming platform including ASP.NET MVC and WebApi. He likes working on new technologies and exciting challenging projects

CONNECT WITH DEJAN  Loginlinkedin Logintwitter Logingoogleplus Logingoogleplus

JavaScript

read more

SQL/T-SQL

read more

Umbraco CMS

read more

PowerShell

read more

Comments for this article