Using the ASP.NET Core Environment Feature to manage Development vs. Production for any config file type
ASP.NET Core can understand what "environment" it's running under. For me, that's "development," "test," "staging," "production," but for you it can be whatever makes you happy. By default, ASP.NET understand Development, Staging, and Production.
You can the change how your app behaves by asking "IsDevelopment" to do certain things. For example:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
if (env.IsProduction() || env.IsStaging() || env.IsEnvironment("Staging_2"))
{
app.UseExceptionHandler("/Error");
}
There are helpers for the standard environments, or I can just pass in a string.
You can also make Environmental decisions with taghelpers like this in your Views/Razor Pages. I did this when I dynamically generated my robots.txt files:
@page
@{
Layout = null;
this.Response.ContentType = "text/plain";
}
# /robots.txt file for http://www.hanselman.com/
User-agent: *
<environment include="Development,Staging">Disallow: /</environment>
<environment include="Production">Disallow: /blog/private
Disallow: /blog/secret
Disallow: /blog/somethingelse</environment>
This is a really nice way to include things like banners or JavaScript when your site is running in a certain environment. These are easily set as environment variables if you're running in a container. If you're running in an Azure App Service you set the environment from the Config blade:
Now that I've moved this blog to Azure, we have a number of config files that are specific to this blog. Since the configuration features of ASP.NET are so flexible it was easy to extend this idea of environments to our own config files.
Our Startup class sets up the filesnames of our various config files. Note the second line, if we have no environment, we just look for the regular file name.
public Startup(IWebHostEnvironment env)
{
hostingEnvironment = env;
var envname = string.IsNullOrWhiteSpace(hostingEnvironment.EnvironmentName) ?
"." : string.Format($".{hostingEnvironment.EnvironmentName}.");
SiteSecurityConfigPath = Path.Combine("Config", $"siteSecurity{envname}config");
IISUrlRewriteConfigPath = Path.Combine("Config", $"IISUrlRewrite{envname}config");
SiteConfigPath = Path.Combine("Config", $"site{envname}config");
MetaConfigPath = Path.Combine("Config", $"meta{envname}config");
AppSettingsConfigPath = $"appsettings.json";
...
Here's the files in my Visual Studio. Note that another benefit of this naming structure is that the files nest nicely underneath their parent file.
The formalization of environments is not a new thing, but the adoption of it deeply into our application at every level has allowed us to move from dev to staging to production very easily. It's very likely that you have done this in your application, but you may have rolled your own solution. Take a look if you can remove code and adopt this built in technique.
Here's some articles I've already written on the subject of moving this blog to the cloud:
- Real World Cloud Migrations: Moving a 17 year old series of sites from bare metal to Azure
- Dealing with Application Base URLs and Razor link generation while hosting ASP.NET web apps behind Reverse Proxies
- Updating an ASP.NET Core 2.2 Web Site to .NET Core 3.1 LTS
- Making a cleaner and more intentional azure-pipelines.yml for an ASP.NET Core Web App
- Moving an ASP.NET Core from Azure App Service on Windows to Linux by testing in WSL and Docker first
If you find any issues with this blog like
- Broken links and 404s where you wouldn't expect them
- Broken images, zero byte images, giant images
- General oddness
Please file them here https://github.com/shanselman/hanselman.com-bugs and let me know!
Sponsor: Suffering from a lack of clarity around software bugs? Give your customers the experience they deserve and expect with error monitoring from Raygun.com. Installs in minutes, try it today!
About Scott
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
About Newsletter
Comments are closed.
I prefer to use XML Custom transformation rules, and to deploy only the transformed .config file without (.Development.config, .Staging.config, .Production.config). I currently use them in Build Pipelines and makes build artifact clearer.
And the code in " Startup()" method could be skipped.