Configuration Files (appsettings.json) in .NET Core

AZHARUL | 26-Oct-2024 09:08:17 AM | Time to read: 9 Min

In a modern .NET Core application, configuration settings are essential for maintaining flexibility and separating environment-specific variables (like database connection strings, logging preferences, and third-party service URLs) from the core code. The primary file used for this purpose is appsettings.json. In this blog we are going to guide through how to use appsettings.json effectively, including environment-specific configurations, real-world examples, and how to access configurations from c# codes.

What is appsettings.json?

appsettings.json is a simple, JSON-formatted file that stores key-value pairs, which makes it an ideal location for configuration settings like:

  • Connection strings to databases.
  • API keys and URLs for third-party services.
  • Logging levels for different environments (development, production, etc.).

Here’s an example of a basic appsettings.json file:

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=myServer;Database=myDB;User=myUser;Password=myPass;"
  },

  "Logging": {
    "LogLevel": {
      "Default": "Warning",
      "Microsoft": "Information"
    }
  },

  "ApiSettings": {
    "BaseUrl": "https://api.example.com",
    "ApiKey": "12345"
  }
}
Why Use appsettings.json?

Storing configurations in appsettings.json has several benefits:

  • Separation of concerns: You avoid hardcoding settings in your application, making it easier to change configurations between different environments (e.g., Development vs. Production).
  • Flexibility: The settings can be easily changed without recompiling the code.
  • Environment-specific configurations: You can have different settings for different environments by creating files like appsettings.Development.json and appsettings.Production.json.
Types of Configuration in appsettings.json

Here are some common configurations you will store in appsettings.json:

1. Connection Strings: Store your database connection string(s) here. Multiple connection strings can be defined if your application interacts with multiple databases.

"ConnectionStrings": {
  "DefaultConnection": "Server=myServer;Database=myDB;User=myUser;Password=myPass;"
}

2. Logging Settings: This section controls the level of information logged by different parts of the application. Levels include Trace, Debug, Information, Warning, Error, and Critical.

"Logging": {
  "LogLevel": {
    "Default": "Warning",
    "Microsoft": "Information",
    "System": "Error"
  }
}

· Default controls the logging level for general events.

· Microsoft and System allow you to fine-tune logging for specific frameworks.

3. API Settings: When your application communicates with external APIs, you can store the base URL and API keys here.

"ApiSettings": {
  "BaseUrl": "https://api.example.com",
  "ApiKey": "12345"
}

4. Custom Settings: You can create custom sections as per your application's need, e.g., SMTP settings, payment gateway configurations, etc.

"SmtpSettings": {
  "Host": "smtp.mail.com",
  "Port": 587,
  "Username": "user@mail.com",
  "Password": "securePassword"
}
Access these configurations

You can read or access these configurations from a service or repository or any other files of your project. Here, we are going to read these configurations form a controller and want to show in a view for better understanding.

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

namespace YourApp.Controllers
{
    public class HomeController : Controller
    {
        private readonly IConfiguration _configuration;

        public HomeController(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        public IActionResult Index()
        {
            // Read values from appsettings.json
            var connectionString = _configuration.GetConnectionString("DefaultConnection");
            var logLevel = _configuration.GetValue<string>("Logging:LogLevel:Default");
            var apiKey = _configuration.GetValue<string>("ApiSettings:ApiKey");
            var apiBaseUrl = _configuration.GetValue<string>("ApiSettings:BaseUrl");

            // Pass the values to the view using ViewData or ViewBag
            ViewData["ConnectionString"] = $"Connection String: {connectionString}";
            ViewData["LogLevel"] = $"Logging : {logLevel}";
            ViewData["ApiKey"] = $"API Key: {apiKey}";
            ViewData["ApiBaseUrl"] = $"API Base URL: {apiBaseUrl}";

            return View();
        }
    }
}

Lets, display these configuration values in the Index view

@{
    ViewData["Title"] = "Configuration Demo";
}

<h2>Configuration Values</h2>

<table>
    <tr>
        <th>Configuration Key</th>
        <th>Value</th>
    </tr>

    <tr>
        <td>Connection String</td>
        <td>@ViewData["ConnectionString"]</td>
    </tr>

    <tr>
        <td>Logging Level</td>
        <td>@ViewData["LogLevel"]</td>
    </tr>

    <tr>
        <td>API Key</td>
        <td>@ViewData["ApiKey"]</td>
    </tr>

    <tr>
        <td>API Base URL</td>
        <td>@ViewData["ApiBaseUrl"]</td>
    </tr>
</table>

Environment-Specific Configuration : Development, Staging, Production

When developing a .NET Core application, it's crucial to use environment-specific configuration files to handle different settings for different deployment stages. These files allow you to separate configurations like database connection strings, logging levels, API URLs, and other critical information based on the environment your app is running in. The common environment configurations are:

  • Development
  • Staging
  • Production
Creating Environment-Specific Files

In Visual Studio:

  1. Right-click the project > Add > New Item > JSON File.
  2. Name the files appsettings.Development.json, appsettings.Staging.json, and appsettings.Production.json.

Let’s dive into each one and explore why and when you should use them, along with practical tips on managing these files in Visual Studio.

1. Development Environment

The Development environment is where you actively write, debug, and test your code. You typically use a local database, and more detailed logging (such as informational and debug logs) is enabled to assist with diagnosing issues.

Why Use Development?

  • To enable detailed logging and error messages.
  • To connect to local or sandboxed databases and services.
  • To enable debugging features that shouldn’t be present in production.

Example Configuration (appsettings.Development.json):

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=localhost;Database=DevDB;User=devUser;Password=devPassword;"
  },

  "Logging": {
    "LogLevel": {
      "Default": "Debug"
    }
  },

  "ApiSettings": {
    "BaseUrl": "https://dev-api.example.com",
    "ApiKey": "dev-api-key"
  }
}

Use Case:

  • You want to see detailed logs, such as Debug level logs, and use a local development database or sandbox API to avoid interfering with production data.
2. Staging Environment

The Staging environment is an intermediary step between Development and Production. In Staging, you test your app in an environment that mimics Production as closely as possible without actually being live. This environment is used for testing purposes before deploying the app to production.

Why Use Staging?

  • To validate how your application behaves in a production-like setting.
  • To ensure that any final tests and bug fixes are done before going live.
  • To prevent bugs from creeping into the live environment by testing thoroughly.

Example Configuration (appsettings.Staging.json):

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=stagingServer;Database=StagingDB;User=stagingUser;Password=stagingPassword;"
  },

  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },

  "ApiSettings": {
    "BaseUrl": "https://staging-api.example.com",
    "ApiKey": "staging-api-key"
  }
}

Use Case:

  • You are deploying a new version of your app and want to test how it interacts with production-like services (e.g., staging databases or staging APIs) before pushing it live.
3. Production Environment

The Production environment is the live environment where your application is available to users. Performance and stability are key here, so logging is typically set to log only errors and warnings to reduce overhead.

Why Use Production?

  • To ensure that only necessary logs (warnings, errors) are recorded, optimizing performance.
  • To use live databases and services.
  • To run in a stable, optimized, and highly secure mode.

Example Configuration (appsettings.Production.json):

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=prodServer;Database=ProdDB;User=prodUser;Password=prodPassword;"
  },

  "Logging": {
    "LogLevel": {
      "Default": "Error"
    }
  },

  "ApiSettings": {
    "BaseUrl": "https://api.example.com",
    "ApiKey": "prod-api-key"
  }
}

Use Case:

  • When your app is live and being accessed by users. You want to ensure that only errors are logged, and the app runs smoothly with high performance and security in mind.
Load the Configuration Files Based on Environment in program.cs
// take an enum for the Environment Type

public enum EnvironmentType
{
    Development,
    Staging,
    Production
}

// Set up WebApplicationOptions with a specified environment
var options = new WebApplicationOptions
{
    EnvironmentName = EnvironmentType.Development.ToString() // Change to "Staging" or "Production" as needed
};

// Create a builder with the specified options
var builder = WebApplication.CreateBuilder(options);

// Add configuration files
builder.Configuration
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) // Base configuration file
    .AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true, reloadOnChange: true); // Environment-specific file
Read or Access the Loaded Environment Name
var app = builder.Build();

// Endpoint to display the currently loaded environment
app.MapGet("/environment", (IWebHostEnvironment env) =>
{
    return $"Currently loaded environment: {env.EnvironmentName}";
});

app.Run();

The configuration system is designed to support environment-specific settings by layering the main appsettings.json file with environment-specific files, such as appsettings.Development.json, appsettings.Staging.json, or appsettings.Production.json. During runtime, the configuration from appsettings.json serves as the base, while the environment-specific file overrides or extends those settings based on the current environment. For example, if you specify a different database connection string in appsettings.Development.json, it will override the default connection string in appsettings.json whenever the environment is set to Development.

This layering approach simplifies managing configurations for different stages, from development to production, without modifying the main configuration file directly.

Similarities to web.config

The appsettings.json file in .NET Core replaces much of the functionality previously handled by web.config in older .NET Framework applications. While web.config used XML format to store application settings and configuration information, appsettings.json uses JSON, providing a more modern, lightweight structure that’s easier to read and manage. Like web.config, appsettings.json can store various configuration settings, such as connection strings, logging levels, and custom application settings, but in a way that is more flexible and integrates seamlessly with .NET Core’s dependency injection and environment-based configuration system.

 

If you found this blog helpful, please share it with your peers and colleagues. Don't forget to subscribe to our YouTube channel(Visit Codexoom on YouTube) for more tutorials on ASP.NET Core and professional software development tips!

Thank you for joining us, and as always, happy coding! Until next time, stay curious and keep building amazing things. Take care!