Practical .NET
Managing Production and Development Settings in ASP.NET Core
The reality is that you will need to have, at least, two different configurations: one for production and one for development. Here's how to automate those conversions.
The reality is that our applications need to be configured differently for our development, staging and production environments. As an example, the logging system you use in your production environment is probably going to be significantly different from the service you use in development (assuming you use one in development at all).
ASP.NET Core provides three tools for managing your application's configuration. At a course-grained level, you can select your appsettings file and your Startup class based on your environment. At a finer-grained level, you can examine the IHostingEnvironment or check the ASPNETCORE_ENVIRONMENT variable to make decisions in your code based on the current environment. Finally, to manage specifying what environment you're in, you have profiles.
Managing Profiles
Fundamentally, the configuration process is driven by the value in the ASPNETCORE_ENVIRONMENT environment variable (that's a mouthful: I'll just call it the "environment variable" from now on). You can't set the environment variable's value from your application's code (though you can set it through Control Panel | System | Advanced System Settings | Environment Variables, from PowerShell or through the Windows Command Prompt).
You can however, set the value of the variable through a setting in your application's launchsettings.json file. The launchsettings file organizes settings into profiles with each profile triggered by the way that the application is started.
You can find the launchsettings file nested under the Properties node in Solution Explorer, but it's probably easier to manage the file through the Properties dialog for your project. The Debug tab provides a UI that lists all the profiles in launchsettings and allows you both to update and create profiles.
In a profile, the key value is what the Debug tab calls Launch (it updates a property called "commandName" in the launchsettings file). The Launch setting controls when a profile is invoked. A profile with its Launch set to "IIS Express" will be the profile that's used when you start debugging in IIS Express.
In Visual Studio 2019 Preview, you'll find that four default profiles have been set up for ASP.NET Core projects. Only two of those require you to manage your environment variable: one called "IIS Express" (that has its Launch option set to IIS Express) and one named after your project (with its Launch option set to Project). Both profiles set the variable to "Development."
Since the environment variable defaults to "Production" and there is no profile with Launch set to "IIS," this means that if your application is running under IIS, the environment variable will be set to "Production."
Coarse-Grained Configuration
ASP.NET Core uses the environment variable to select which the appsettings.json file and the Startup.cs file will be used. With the environment variable set to "Development," for example, ASP.NET Core first uses the values in a file called appsettings.development.json and only uses the values in the appsettings.json file if the first file can't be found.
Similarly, ASP.NET Core is willing to look for a class called StartupDevelopment to handle configuring the project when the environment variable is set to "Development." This feature, however, isn't turned on by default. To activate selecting the Startup class, you'll need to modify the code in your project's Program.cs file. In that file, you'll need to change the way the code that sets the CreateWebHostBuilder method calls the UseStartup method.
By default the code in Program.cs looks like this:
public static IWebHostBuilderCreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
You must change the generic version of UseStartup used here to a version of the method that accepts the name of your project. That means, for example, for a project called CustomerManagement, you'd need to change the code to this:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup("CustomerManagement");
}
Coarse-Grained Configuration
Within your application you can perform more fine-grain checking by calling methods on the IHostingEnvironment object. You can request that object in any method that's called by ASP.NET Core (for example, either of the Configure methods in your Startup class or in the constructors for your Controllers).
Here's an example of a Controller's constructor that accepts an IHostingEnvironment object and stores it in a field:
public class CustomerController
{
IHostingEnvironment env;
public CustomerController(IHostingEnvironment env)
{
this.env = env;
}
With that code in place, any Action method in the Controller can retrieve the IHostingEnvironment object from the Controller's env property and use it.
The IHostingEnvironment object supports three methods that return true or false based on the environment variable: IsProduction, IsStaging and IsDevelopment. Typical code in an Action method that uses those methods to turn logging on or off might look like this:
if (env.IsProduction)
{
LoggingEnabled = true;
}
Those three methods are driven by the environment variable being set to "Production," "Staging" or "Development." If you'd prefer to use another value in the environment value, you can. ASP.NET Core will use whatever value you set the environment variable to when selecting appsettings files and Startup classes. With IHostingEnvironment, however, you'll need to use its IsEnvironment method, passing in the value you set the environment variable to in your profile.
Rewriting my previous example to work with the environment variable set to "Gold" would give this code:
if (env.IsEnvironment("Gold"))
{
LoggingEnabled = true;
}
It would be wonderful if our applications didn't need to be reconfigured as we move from development through staging and into production. In the meantime, however, ASP.NET Core provides the tools to automate those changes and that's ... well, not as good but as good we can get.
About the Author
Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.