Use different configuration based on environment value in ASP.NET Core

Different configuration per environment in ASP.NET Core

In .NET framework, having separate configuration is possible by having different web.config or app.config file transformations since in .NET framework configuration is stored in XML format. You can check more on this in article Separate configuration files per build config in Visual Studio IDE. This is not the case for .NET Core where you can choose in which format you are going to save your configuration 

ASP.NET Core has a built in support for environments which is based on environment variables on which it is running. Regardless of whether you are running your application on Window, Linux or Docker container you can always rely on ASPNETCORE_ENVIRONMENT variable to determine in your application on which environment is it running.

For development and debugging purposes this variable can be set inside launchSettings.json file from Visual Studio for both stand alone or IIS express host.

{"iisSettings": {"windowsAuthentication": false,"anonymousAuthentication": true,"iisExpress": {"applicationUrl": "http://localhost:63084/","sslPort": 0}},"profiles": {"IIS Express": {"commandName": "IISExpress","launchBrowser": true,"launchUrl": "api/environment","environmentVariables": {"ASPNETCORE_ENVIRONMENT": "staging"}},"Core.Config.Sample": {"commandName": "Project","launchBrowser": true,"launchUrl": "api/environment","environmentVariables": {"ASPNETCORE_ENVIRONMENT": "staging"},"applicationUrl": "http://localhost:63085/"
    }
  }
}
    

For the actual environment, outside of Visual studio, depending on the way you are hosting your app you can set this variable either via PowerShell, Bash or docker-compose.yml file for Docker container.

Windows host environment variable

On Windows, you can add this as an environment variable through Windows you to which you can access by running the following command from the Run dialog

rundll32 sysdm.cpl,EditEnvironmentVariables
    

Environment

You can also do it with a PowerShell command if you do not have access to UI

$Env:ASPNETCORE_ENVIRONMENT = "development"
    

Linux host environment variable

On Linux headless host you can set the environment variable by adding it to the application run path as a parameter in your command window

ASPNETCORE_ENVIRONMENT=Development dotnet run application.dll
    

Alternatively you can set it as environment variable prior to application run 

export ASPNETCORE_ENVIRONMENT=development
    

However, both methods will not set it permanently on the host, the environment variable will be only available for the current running session. To set it permanently you need to edit .bash_profile file on the Linux host machine. If you are using Debian distro you can edit file with nano text editor

sudo nano ~/.bash_profile
    

Now just add the following line and save the file

export ASPNETCORE_ENVIRONMENT=development
    

Now you have your environment variable set permanently.

Docker container environment variable

If you are running your application on Docker container you can easily setup the environment variable in docker-compose.yml

version: '3'

services:
  api:
    image: myapplication/api
    container_name: myapplication_api
    build:
      context: .
    ports:
      - 80:80
    environment:
      ASPNETCORE_ENVIRONMENT: Development
    volumes:
      - ./Logs:/app/Logs
#    depends_on:
    

Inside environment section you can add all environment variables you need for your application.

Code implementation

Now when we have our environment set up we can focus on code implementation. First thing is that we have our configuration files for each environment with proper values. For that purpose I am going to create appsettings.development.json and appsettings.qa.json in my project root.

Note

Visual Studio tends to create environment and config files with leading uppercase. This is not the problem on Windows but on Linux host you have to be careful because it has case sensitive file system unlike Windows. For that reason I keep both environment value and file name in lowercase format.

{
  "ConnectionStrings": {
    "DatabaseConnection": "Server=.\\SQLEXPRESS-DEV;Database=databasename;User Id=username;Password=password;"
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  }
}

    

Depending on the value of environment variable we will load the proper file if it exists, otherwise we will load appsettings.json file. All this happens on the startup where we decide which config file to inject depending on the environment

using System.IO;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace Core.Config.Sample
{
    public class Startup
    {
        private IHostingEnvironment hostingEnvironment;

        public Startup(IConfiguration configuration, IHostingEnvironment environment)
        {
            this.hostingEnvironment = environment;
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();

            #region Add Configuration
            var environmentConfig = $"appsettings.{this.hostingEnvironment.EnvironmentName.ToLower()}.json";
            environmentConfig = !File.Exists(Path.Combine(Directory.GetCurrentDirectory(), environmentConfig)) ? "appsettings.json" : environmentConfig;

            services.AddSingleton<IConfiguration>(new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile(environmentConfig)
                .Build());

            #endregion
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment() || env.IsEnvironment("development"))
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseMvc();
        }
    }
}

    

And this is pretty much it :). All we have to do is to test it and for that purpose I created EnvironmentController which will write out JSON with environment name and config setting for that environment.

As an example I used database connection string which is in most cases the environment dependent setting

using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;

namespace Core.Config.Sample.Controllers
{
    [Route("api/[controller]")]
    public class EnvironmentController : Controller
    {
        readonly IHostingEnvironment environment;
        readonly IConfiguration configuration;
        public EnvironmentController(IConfiguration configuration ,IHostingEnvironment environment)
        {
            this.environment = environment;
            this.configuration = configuration;
        }

        [HttpGet]
        public IActionResult Get()
        {
            return new JsonResult(new
            {
                Environment = this.environment.EnvironmentName,
                ConnectionString = this.configuration.GetValue<String>("ConnectionStrings:DatabaseConnection")
            });
        }

    }
}

    

The complete project is attached to this article so feel free to download it and open Vith Visual studio. Happy coding!

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