ASP.NET Core – True Ultimate Guide

Section 13: Environments


ASP.NET Core Environments

In ASP.NET Core, environments are named configurations that allow you to tailor your application’s behavior to different deployment scenarios. This helps you manage settings, configurations, and middleware pipelines that are specific to development, testing, staging, or production environments.

Common Environments

  • Development: Your local development environment. It’s where you build and test your application.
  • Staging: A pre-production environment that closely mirrors your production setup. You use it for final testing and validation.
  • Production: Your live environment where users interact with your application.

Setting the Environment

ASP.NET Core reads the environment from the ASPNETCORE_ENVIRONMENT environment variable when your application starts. The value of this variable determines the active environment.

How to Set the Environment

  • launchSettings.json: For Visual Studio, you can set the ASPNETCORE_ENVIRONMENT variable in the launchSettings.json file within your project’s Properties folder.
  • Environment Variables: Set the ASPNETCORE_ENVIRONMENT variable directly in your system’s environment variables.
  • Command Line: When running your application from the command line, you can set the environment variable using the --environment or -e flag:
dotnet run --environment Staging

Using Environments in Program.cs

1. Retrieving the Environment

var builder = WebApplication.CreateBuilder(args);
var environment = builder.Environment;

The environment object gives you access to the current environment’s name and other properties.

2. Conditional Configuration

You can use conditional logic based on the environment name to configure different settings or middleware.

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage(); // Use a detailed error page in development
}
else
{
    app.UseExceptionHandler("/Error"); // Use a generic error page in production
}

3. Environment-Specific Configuration Files

  • You can create environment-specific configuration files like appsettings.Development.json, appsettings.Staging.json, and appsettings.Production.json.
  • ASP.NET Core automatically loads the appropriate configuration file based on the current environment.
  • Use these files to store settings that vary between environments, such as database connection strings or API keys.
  • These files override the settings in the appsettings.json.

Best Practices

  • Environment-Specific Configuration: Separate your configuration into environment-specific files to avoid exposing sensitive data (like production database credentials) in your development environment.
  • Middleware Pipelines: Tailor your middleware pipelines for each environment. For example, use UseDeveloperExceptionPage in development but UseExceptionHandler in production.
  • Logging: Configure different logging levels and targets for different environments (e.g., more verbose logging in development).
  • Feature Flags: Use environment variables or configuration values to toggle features on or off depending on the environment.

Example (Program.cs)

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
 
if (app.Environment.IsDevelopment())
{
    // Development-specific configuration
}
else if (app.Environment.IsStaging())
{
    // Staging-specific configuration
}
else // Production
{
    // Production-specific configuration
}
 
// ... Rest of your application setup ...

Notes

  • Flexibility: Environments allow you to easily adapt your application to different scenarios.
  • Configuration: Use environment-specific configuration files (appsettings.{Environment}.json) for organization.
  • Middleware: Customize middleware pipelines based on the environment.
  • Best Practices: Follow the best practices mentioned above to ensure a smooth deployment process and optimal behavior in each environment.

Understanding launchSettings.json

This file is primarily used by Visual Studio to configure how your ASP.NET Core application launches during development. It contains settings for different profiles (e.g., IIS Express, ProjectName) and provides a convenient way to set environment variables without modifying your system’s global environment variables.

Location

You’ll find launchSettings.json in the Properties folder within your project’s root directory.

Structure

{
    "iisSettings": { ... }, // Settings for IIS Express (if used)
    "profiles": {
        "IIS Express": { ... }, // Configuration for IIS Express profile
        "YourProjectName": {    // Configuration for running the project directly
            "commandName": "Project",
            "dotnetRunMessages": "true",
            "launchBrowser": true,
            "applicationUrl": "https://localhost:7272;http://localhost:5248", // URLs to launch
            "environmentVariables": {
                "ASPNETCORE_ENVIRONMENT": "Development" // Setting the environment
            }
        }
    }
}

Setting the ASPNETCORE_ENVIRONMENT Variable

Within the environmentVariables section of the desired profile (e.g., “YourProjectName”), you can set the ASPNETCORE_ENVIRONMENT variable to one of the standard values:

  • Development: For local development and debugging.
  • Staging: For pre-production testing.
  • Production: For the live environment.

You can also use a custom environment name if needed.

Example: Setting the Development Environment

"environmentVariables": {
    "ASPNETCORE_ENVIRONMENT": "Development"
}

How It Works

When you launch your application from Visual Studio using a specific profile, the environmentVariables settings are applied to the running process. This ensures that your application reads the correct value for ASPNETCORE_ENVIRONMENT, which in turn influences which configuration settings are loaded (from appsettings.json, appsettings.Development.json, etc.) and which middleware pipelines are used.

Important Considerations

  • Environment-Specific Configuration Files: Remember that you’ll still need to create environment-specific configuration files (e.g., appsettings.Development.json) to store settings that vary between environments. launchSettings.json only sets the environment variable.
  • Local Development: The launchSettings.json file is primarily for local development with Visual Studio. When you deploy your application to a server, you’ll typically set the ASPNETCORE_ENVIRONMENT variable through the hosting environment’s configuration (e.g., in the web server’s configuration file or environment variables).
  • Multiple Profiles: launchSettings.json can contain multiple profiles, each with its own set of environment variables. This allows you to easily switch between different configurations during development.

Developer Exception Page

The Developer Exception Page is a powerful tool in ASP.NET Core for diagnosing exceptions during development. It provides a detailed view of the exception, including:

  • Stack trace
  • Request details (headers, query string, cookies)
  • Routing information
  • Configuration settings

This information is invaluable for identifying and fixing issues quickly.

Environment-Specific Behavior

  • Development: The Developer Exception Page is enabled by default in the Development environment. This makes sense because during development, you want as much information as possible to help you troubleshoot.
  • Production and Other Environments: In production or other non-development environments, this page is typically disabled due to security concerns. Exposing detailed exception information to the public could reveal vulnerabilities or sensitive details about your application’s internal workings.

IWebHostEnvironment Interface: Accessing Environment Information

The IWebHostEnvironment interface gives you access to information about the hosting environment of your ASP.NET Core application. It includes properties like:

  • EnvironmentName: The name of the current environment (Development, Staging, Production, or a custom name).
  • WebRootPath: The path to the application’s web root directory.
  • ContentRootPath: The path to the application’s content root directory.

Using IWebHostEnvironment and app.Environment

// HomeController.cs
 
public class HomeController : Controller
{
    private readonly IWebHostEnvironment _webHostEnvironment; // Injected
 
    public HomeController(IWebHostEnvironment webHostEnvironment)
    {
        _webHostEnvironment = webHostEnvironment;
    }
 
    [Route("/")]
    public IActionResult Index()
    {
        ViewBag.CurrentEnviornment = _webHostEnvironment.EnvironmentName;
        return View();
    }
}

In this code, the IWebHostEnvironment is injected into the HomeController. The current environment name (_webHostEnvironment.EnvironmentName) is then assigned to ViewBag.CurrentEnvironment and sent to the view to display.

Enabling the Developer Exception Page in Specific Environments

// Program.cs
 
if (app.Environment.IsDevelopment() || app.Environment.IsStaging() || app.Environment.IsEnvironment("Beta"))
{
    app.UseDeveloperExceptionPage();
}

In this code snippet, the Developer Exception Page is only enabled if the environment is Development, Staging, or a custom environment named “Beta”. You can use app.Environment.IsDevelopment() etc. because they are just shorthands for app.Environment.EnvironmentName == "Development". This can be helpful in scenarios where you want to include staging in your development processes.

Notes

  • Purpose: The Developer Exception Page provides detailed error information during development.
  • Environments: It’s enabled by default in Development, but you can customize its behavior based on other environments.
  • IWebHostEnvironment: Use this interface to access environment information within your controllers or middleware.
  • Security: Always disable the Developer Exception Page in production to avoid exposing sensitive details.
  • Custom Error Pages: For production, use app.UseExceptionHandler to create custom error pages that provide a user-friendly message without revealing internal information.

<environment> Tag Helper

The <environment> tag helper is a versatile tool that allows you to include or exclude specific content in your views depending on the current environment.

This is particularly useful for scenarios where you want to:

  • Include Development Resources: Load unminified CSS or JavaScript files during development to facilitate debugging and testing.
  • Optimize for Production: Load minified and bundled assets in production to improve performance.
  • Display Environment-Specific Content: Show different messages, warnings, or features based on the environment.

Syntax

<environment include="Environment1,Environment2,...">
  Content to render if the environment matches any of the included environments
</environment>
 
<environment exclude="Environment1,Environment2,...">
  Content to render if the environment does NOT match any of the excluded environments
</environment>
  • include: A comma-separated list of environment names for which the content should be rendered.
  • exclude: A comma-separated list of environment names for which the content should not be rendered.

Environment Names

  • Standard: Development, Staging, Production.
  • Custom: You can also define and use your own custom environment names.

How It Works

  1. Environment Check: The <environment> tag helper reads the value of the ASPNETCORE_ENVIRONMENT environment variable to determine the current environment.
  2. Conditional Rendering: Based on the include or exclude attributes and the current environment, it either renders or skips the content within the tag helper.

Code Examples

<environment include="Development">
  <link rel="stylesheet" href="~/css/site.css" />
</environment>
 
<environment exclude="Development">
  <link rel="stylesheet" href="~/css/site.min.css" />
</environment>

In this example:

  • The unminified site.css file is loaded only in the Development environment.
  • The minified site.min.css file is loaded in all other environments.

Notes

  • Flexibility: Easily adapt your views to different environments without complex conditional logic.
  • Performance Optimization: Serve optimized assets in production while retaining flexibility in development.
  • Environment-Specific Content: Display warnings, messages, or debug tools only when needed.

Best Practices

  • Use for Static Assets: Primarily leverage the <environment> tag helper for including or excluding static files (CSS, JavaScript) based on the environment.
  • Avoid Complex Logic: Keep the content within <environment> tags relatively simple. If you need more complex logic, consider using a partial view or a view component.
  • Custom Environments: If you need more than the standard environments, define and use your own.

Set the Environment from the Terminal

  • Flexibility: Setting the environment variable directly from the terminal allows you to easily switch between different environments without modifying configuration files or IDE settings.
  • Automation: This approach is easily scriptable, enabling you to automate deployment processes and seamlessly change configurations for different environments.
  • Non-Windows Environments: If you’re working on macOS or Linux, the terminal is the primary way to manage environment variables.

Setting ASPNETCORE_ENVIRONMENT in PowerShell

# Windows, macOS, Linux
$env:ASPNETCORE_ENVIRONMENT = "Development" # Set to Development
$env:ASPNETCORE_ENVIRONMENT = "Production"  # Set to Production

Scope: In PowerShell, environment variables set with $env: are typically limited to the current session. To make them persistent, you need to modify the system or user environment variables.

Setting ASPNETCORE_ENVIRONMENT in Command Prompt

set ASPNETCORE_ENVIRONMENT=Development  # Set to Development
set ASPNETCORE_ENVIRONMENT=Production   # Set to Production

Scope: By default, variables set with the set command are temporary and only apply to the current command prompt session. To make them persistent, use the /M switch:

setx ASPNETCORE_ENVIRONMENT Development /M  # Set for the user account (persistent)

Setting ASPNETCORE_ENVIRONMENT on macOS and Linux (bash)

export ASPNETCORE_ENVIRONMENT=Development  # Set to Development
export ASPNETCORE_ENVIRONMENT=Production   # Set to Production

Making Environment Variables Persistent

Windows (System Properties):

  1. Right-click on “This PC” and select “Properties”.
  2. Click on “Advanced system settings”.
  3. Click the “Environment Variables” button.
  4. Under “System variables” (or “User variables” for a specific user), click “New”.
  5. Enter ASPNETCORE_ENVIRONMENT as the variable name and the desired environment as the value.

macOS and Linux (Shell Configuration Files):

  • Edit your shell’s configuration file (.bashrc, .zshrc, etc.) and add the following line (replacing Development with your desired environment):
export ASPNETCORE_ENVIRONMENT=Development
  • After saving the file, run source ~/.bashrc (or the appropriate command for your shell) to reload the configuration.

Important Considerations

  • Overriding: When multiple ways of setting the environment are used, the most specific one takes precedence. For example, a value set in the terminal will override the value in launchSettings.json.
  • Case-Sensitivity (Linux/macOS): Environment variable names are case-sensitive on Linux and macOS. Be sure to use the correct capitalization (ASPNETCORE_ENVIRONMENT).
  • Environment-Specific Configuration Files: Even after setting the environment variable, ensure you have the corresponding appsettings.{Environment}.json files in your project to load the correct settings for that environment.

Example: Running Your App with Different Environments

# PowerShell
$env:ASPNETCORE_ENVIRONMENT = "Development"
dotnet run
# Command Prompt (Windows)
set ASPNETCORE_ENVIRONMENT=Production
dotnet run
# bash (macOS/Linux)
export ASPNETCORE_ENVIRONMENT=Staging
dotnet run

Key Points to Remember

  • Purpose: Provide named configurations to tailor your app’s behavior for different scenarios (development, staging, production, etc.).
  • Environment Variable:
    • ASPNETCORE_ENVIRONMENT is the key environment variable.
    • Its value determines the active environment.
  • Setting the Environment:
    • launchSettings.json (Development): Set within the environmentVariables section of a profile.
    • System Environment Variables: Set directly on your machine (persistent).
    • Command Line: Use --environment or -e flag when running the app (e.g., dotnet run --environment Staging).
  • IWebHostEnvironment Interface:
    • Use it in your code to access environment information (e.g., EnvironmentName, WebRootPath).
    • Inject it into your controllers or middleware:
private readonly IWebHostEnvironment _env;
 
public MyController(IWebHostEnvironment env)
{
    _env = env;
}
  • Environment-Specific Configuration:
    • Create files like appsettings.Development.json, appsettings.Staging.json, etc.
    • ASP.NET Core automatically loads the appropriate file based on the environment.
    • Override base settings in appsettings.json.
  • Conditional Configuration (In Program.cs):
    • Use if (app.Environment.IsDevelopment()) or similar methods to apply settings or middleware based on the environment.
if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
  • Default Environments:
    • Development: Default for local development.
    • Staging: Typically used for pre-production testing.
    • Production: The live environment.
  • Custom Environments: You can define and use your own environment names.
  • Best Practices:
    • Separate Configurations: Keep environment-specific settings in separate files.
    • Tailor Middleware: Use different middleware pipelines for different environments (e.g., enable DeveloperExceptionPage only in development).
    • Logging: Adjust logging levels based on the environment.
    • Feature Flags: Use environment variables to toggle features on/off.

Interview Tips

  • Explain the Why: Be able to articulate the reasons for using environments (configuration, security, flexibility).
  • Configuration: Show how you would use appsettings.{Environment}.json files to manage environment-specific settings.
  • Middleware: Explain how you would customize middleware pipelines based on the environment.
  • Deployment: Discuss how you would set the environment variable when deploying to different servers.