Section 6 of 6

Environments

🎯 What You'll Learn

  • Understanding ASP.NET Core environments
  • The ASPNETCORE_ENVIRONMENT variable
  • Built-in environments: Development, Staging, Production
  • Environment-specific configuration and behavior
  • Detecting environments in code
  • launchSettings.json explained
  • Setting environments in different hosting scenarios
  • Best practices for InvenTrack deployment

What Are Environments?

Environments let you configure your application differently based on where it's running. You typically have different settings, logging levels, and behaviors for development vs production.

πŸ’‘ Common Scenarios

Development: Detailed logging, Swagger UI, local database
Staging: Production-like, but for testing before release
Production: Minimal logging, no debug tools, production database

The ASPNETCORE_ENVIRONMENT Variable

ASP.NET Core determines the current environment from the ASPNETCORE_ENVIRONMENT environment variable.

Built-in Environment Names

Environment Purpose Typical Use
Development Local development Your machine, detailed errors, Swagger
Staging Pre-production testing QA environment, production-like setup
Production Live application Customer-facing, optimized, secure
ℹ️ Custom Environments

You can create custom environments like "Testing", "UAT", or "Demo". The names are case-insensitive but conventionally use PascalCase.

Setting the Environment

Method 1: launchSettings.json (Development)

When running locally with dotnet run or Visual Studio, the environment is set in Properties/launchSettings.json:

Properties/launchSettings.json JSON
{
  "profiles": {
    "http": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "https": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "https://localhost:5001;http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}
⚠️ Development Only

launchSettings.json is only used during local development. It's NOT deployed to production. Don't rely on it for production configuration!

Method 2: Environment Variable (Production)

Windows (PowerShell) PowerShell
# Set for current session
$env:ASPNETCORE_ENVIRONMENT = "Production"

# Set permanently (system-wide)
[System.Environment]::SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Production", "Machine")
Linux/macOS (Bash) Bash
# Set for current session
export ASPNETCORE_ENVIRONMENT=Production

# Add to ~/.bashrc for persistence
echo 'export ASPNETCORE_ENVIRONMENT=Production' >> ~/.bashrc

Method 3: Command Line

Terminal Shell
# Windows
dotnet run --environment Production

# Linux/macOS
ASPNETCORE_ENVIRONMENT=Production dotnet run

Method 4: Azure App Service

In Azure Portal:

  1. Navigate to your App Service
  2. Go to Configuration β†’ Application settings
  3. Add ASPNETCORE_ENVIRONMENT = Production
  4. Click Save

Method 5: Docker

Dockerfile Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:8.0
ENV ASPNETCORE_ENVIRONMENT=Production
COPY . /app
WORKDIR /app
ENTRYPOINT ["dotnet", "InvenTrack.Api.dll"]
docker-compose.yml YAML
version: '3.8'
services:
  api:
    image: inventtrack-api
    environment:
      - ASPNETCORE_ENVIRONMENT=Production
    ports:
      - "8080:80"

Detecting Environments in Code

In Program.cs

Program.cs C#
var builder = WebApplication.CreateBuilder(args);

// Check environment during configuration
if (builder.Environment.IsDevelopment())
{
    builder.Services.AddSwaggerGen();
}

var app = builder.Build();

// Check environment in middleware pipeline
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/error");
    app.UseHsts();
}

if (app.Environment.IsProduction())
{
    // Production-only configuration
}

if (app.Environment.IsStaging())
{
    // Staging-only configuration
}

if (app.Environment.IsEnvironment("UAT"))
{
    // Custom environment
}

In Controllers/Services

ProductsController.cs C#
public class ProductsController : ControllerBase
{
    private readonly IWebHostEnvironment _environment;

    public ProductsController(IWebHostEnvironment environment)
    {
        _environment = environment;
    }

    [HttpGet("info")]
    public IActionResult GetInfo()
    {
        return Ok(new
        {
            Environment = _environment.EnvironmentName,
            IsDevelopment = _environment.IsDevelopment(),
            ContentRootPath = _environment.ContentRootPath,
            WebRootPath = _environment.WebRootPath
        });
    }
}

Available Methods

Method Returns True When
IsDevelopment() Environment is "Development"
IsStaging() Environment is "Staging"
IsProduction() Environment is "Production"
IsEnvironment("UAT") Environment matches the string (case-insensitive)

Environment-Specific Configuration Files

ASP.NET Core automatically loads environment-specific configuration:

Configuration Loading Order Text
1. appsettings.json
2. appsettings.{Environment}.json  (overrides #1)
3. User Secrets (Development only)
4. Environment Variables             (overrides #1-3)
5. Command-line arguments            (overrides #1-4)

Example: Different Database per Environment

appsettings.json (Base) JSON
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=localhost;Database=InvenTrack;..."
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information"
    }
  }
}
appsettings.Development.json JSON
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=localhost;Database=InvenTrack_Dev;..."
  },
  "Logging": {
    "LogLevel": {
      "Default": "Debug",
      "Microsoft.EntityFrameworkCore": "Information"
    }
  }
}
appsettings.Production.json JSON
{
  // Connection string set via environment variable
  "Logging": {
    "LogLevel": {
      "Default": "Warning",
      "Microsoft.AspNetCore": "Error"
    }
  }
}

Environment-Specific Behavior

Development Environment

Development Features C#
if (app.Environment.IsDevelopment())
{
    // Detailed error pages
    app.UseDeveloperExceptionPage();
    
    // Swagger UI for API testing
    app.UseSwagger();
    app.UseSwaggerUI();
    
    // Database error page
    app.UseDatabaseErrorPage();
    
    // Seed test data
    using (var scope = app.Services.CreateScope())
    {
        var seeder = scope.ServiceProvider.GetRequiredService<DataSeeder>();
        await seeder.SeedAsync();
    }
}

Production Environment

Production Features C#
if (app.Environment.IsProduction())
{
    // Generic error handler
    app.UseExceptionHandler("/error");
    
    // HSTS (HTTP Strict Transport Security)
    app.UseHsts();
    
    // Response compression
    app.UseResponseCompression();
    
    // Response caching
    app.UseResponseCaching();
}

Complete InvenTrack Example

Program.cs (Full Example) C#
var builder = WebApplication.CreateBuilder(args);

// Services configuration
builder.Services.AddControllers();

// Database - connection string varies by environment
builder.Services.AddDbContext<InvenTrackDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

// Development-only services
if (builder.Environment.IsDevelopment())
{
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen();
}

// Production-only services
if (builder.Environment.IsProduction())
{
    builder.Services.AddResponseCompression();
    builder.Services.AddResponseCaching();
}

var app = builder.Build();

// Middleware pipeline
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/error");
    app.UseHsts();
}

if (app.Environment.IsProduction())
{
    app.UseResponseCompression();
    app.UseResponseCaching();
}

app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();

app.Run();

Best Practices

1. Use Environment-Specific Configuration Files

  • appsettings.json - Shared defaults
  • appsettings.Development.json - Dev overrides (commit to Git)
  • appsettings.Production.json - Minimal, no secrets (commit to Git)

2. Never Hardcode Environment Names

❌ Bad C#
if (app.Environment.EnvironmentName == "Development") { ... }
βœ… Good C#
if (app.Environment.IsDevelopment()) { ... }

3. Default to Production

If ASPNETCORE_ENVIRONMENT is not set, ASP.NET Core defaults to Production. This is a safety featureβ€”better to be too restrictive than too permissive.

4. Use User Secrets in Development

Terminal Shell
dotnet user-secrets set "ConnectionStrings:DefaultConnection" "Server=localhost;..."

5. Use Environment Variables in Production

Set sensitive values (connection strings, API keys) via environment variables, not in configuration files.

6. Validate Environment-Specific Configuration

Validation C#
if (app.Environment.IsProduction())
{
    var connString = builder.Configuration.GetConnectionString("DefaultConnection");
    if (string.IsNullOrEmpty(connString))
    {
        throw new InvalidOperationException("Production connection string not configured");
    }
}

Key Takeaways

  • Environments let you configure apps differently per deployment
  • Set via ASPNETCORE_ENVIRONMENT environment variable
  • Built-in: Development, Staging, Production
  • launchSettings.json sets environment for local development
  • Detect with IsDevelopment(), IsProduction(), IsStaging()
  • Inject IWebHostEnvironment to check environment in services
  • appsettings.{Environment}.json overrides base settings
  • Configuration precedence: JSON β†’ User Secrets β†’ Env Vars β†’ Command Line
  • Default is Production if not set (safety feature)
  • Use User Secrets for development, Environment Variables for production
  • Enable different features per environment (Swagger in Dev, HSTS in Prod)
  • Validate critical configuration at startup
πŸŽ‰ Part III Complete!

Congratulations! You've completed Part III: ASP.NET Core Basics. You now understand:

  • βœ… What ASP.NET Core is and its architecture
  • βœ… Building your first Web API
  • βœ… Program.cs and the middleware pipeline
  • βœ… Configuration with appsettings.json
  • βœ… The Options Pattern for strongly-typed config
  • βœ… Managing different environments

Next up: Part IV will dive into Dependency Injectionβ€” understanding service lifetimes, registering services, and building testable, maintainable applications. The journey to building InvenTrack continues! πŸš€