'Read appsettings.{env}.json objects in .NET 6 API - Values coming as NULL

I am using .NET 6 to create APIs. I have environment-based appsettings.json files.

I have created apt profiles in launchSettings.json as well.

I am trying to use Options pattern to read the key/values inside one of the controllers.

I get the values as NULL every single time.

When I debug the Program.cs file, I am able to see the proper values via the below line of code.

builder.Configuration.GetSection(key: "Config").Get<Config>();

Please help. Code used is as below:

Program.cs:

var builder = WebApplication.CreateBuilder(args);
var configuration = builder.Configuration;

var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");

configuration
    .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
    .AddJsonFile($"appsettings.{env}.json", true, true);

builder.Configuration.GetSection(key: "Config").Get<Config>();

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddScoped<IProductRepository, ProductRepository>();
builder.Services.AddSingleton<Config>();

Config.cs:

public class Config
    {
        public string Environment { get; set; }
        public string Type { get; set; }
    }

ProductsController.cs

    [Route("api/[controller]")]
    [ApiController]
    public class ProductsController : ControllerBase
    {
        private readonly IProductRepository _repository;
        private readonly Config _config;

        public ProductsController(IProductRepository repository,
            IOptions<Config> config)
        {
            _repository = repository;
            _config = config.Value;
        }

        [HttpGet]
        [Route("/configs")]
        public IActionResult GetConfigs()
        {
            var model = new { type = _config.Type, env = _config.Environment };
            return Ok(model);
        }

appsettings.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "Config": {
    "Environment": "local",
    "Type": "local Server"
  }
}

appsettings.Development.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "Config": {
    "Environment": "Development",
    "Type": "Development Server"
  }
}

appsettings.Staging.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "Config": {
    "Environment": "Staging",
    "Type": "Staging Server"
  }
}

launchSettings.json:

 "profiles": {
    "API - Development": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "launchUrl": "swagger",
      "applicationUrl": "https://localhost:7082;http://localhost:5082",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "API - Staging": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "https://localhost:5001;http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Staging"
      }
    }
}

Output: enter image description here



Solution 1:[1]

I think you might need to use configuration.GetSection in Services.Configure which means registering Config object from Config section of appsettings.json.

builder.Services.Configure<Config>(configuration.GetSection("Config"));

Solution 2:[2]

I think your issue is within:

configuration
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env}.json", true, true);

builder.Configuration.GetSection(key: "Config").Get<Config>();

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddScoped<IProductRepository, ProductRepository>();
builder.Services.AddSingleton<Config>();

You're currently getting a section Config and then calling Get<> on it but never applying that to anything (injecting). It would seem like the final line would do that, but there is no parameter to this function to provide something to inject.

You could:

builder.Services.Configure<Config>(builder.Configuration.GetSection("Config"));

Solution 3:[3]

services.AddOptions<Config>()
    .Bind(configuration.GetSection("Config"))
    .ValidateDataAnnotations(); // optionally validate annotations

Try using AddOptions, this should then bind.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Avogadro
Solution 3 Askar Rayapov