331

Not sure what am I missing here but I am not able to get the values from my appsettings.json in my .net core application. I have my appsettings.json as:

{
    "AppSettings": {
        "Version": "One"
    }
}

Startup:

public class Startup
{
    private IConfigurationRoot _configuration;
    public Startup(IHostingEnvironment env)
    {
        _configuration = new ConfigurationBuilder()
    }
    public void ConfigureServices(IServiceCollection services)
    {
      //Here I setup to read appsettings        
      services.Configure<AppSettings>(_configuration.GetSection("AppSettings"));
    }
}

Model:

public class AppSettings
{
    public string Version{ get; set; }
}

Controller:

public class HomeController : Controller
{
    private readonly AppSettings _mySettings;

    public HomeController(IOptions<AppSettings> settings)
    {
        //This is always null
        _mySettings = settings.Value;
    }
}

_mySettings is always null. Is there something that I am missing here?

one noa
  • 345
  • 1
  • 3
  • 10
aman
  • 4,198
  • 4
  • 24
  • 36
  • 3
    Please [read the documentation](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration) on how to use configuration. You have improperly set up the configuration in your startup class. – poke Oct 25 '17 at 20:35
  • 9
    The fact that there are so many wildly different answers to this question highlights the problem. Almost makes me wonder if it's easier just to read the settings file and deserialize to an object created with an online json -> c# class generator. Having settings that aren't strongly-typed seems primitive to me. – Damien Jun 09 '21 at 23:39

24 Answers24

458

Program and Startup class

ASP.NET Core 6.x

ASP.NET Core 6.x brings another big changes in the Program class:

  • No Program.Main() boilerplate if you select to use Top level statements
  • Implicit using directives
  • No Startup class as everything is in Program file
  • Introduce WebApplication and WebApplicationBuilder

Some said these changes are good for new comers to learn ASP.NET Core. I kind of felt the other way around. I think the separation of Program and Startup made more sense, at least to me.

Anyway...

This is how Program.cs would look like:

// Program.cs
public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        builder.Services.AddControllersWithViews();

        var app = builder.Build();

        if (!app.Environment.IsDevelopment())
        {
            app.UseExceptionHandler("/errors");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthorization();

        app.MapControllerRoute(
            name: "areaRoute",
            pattern: "{area:exists}/{controller=home}/{action=index}/{id?}");
            
        app.MapControllerRoute(
            name: "default",
            pattern: "{controller=home}/{action=index}/{id?}");

        app.Run();
    }
}

You can kind of tell the section between WebApplication.CreateBuilder() and builder.Build() is what the old ConfigureServices(IServiceCollection services) used to do. And the section before app.Run() is what the old Configure() from Startup used to do.

Most importantly, IConfiguration is injected to the pipeline so you can use it on your controllers.

ASP.NET Core 3.x to 5

ASP.NET Core 3.x brings some changes that try to support other approaches such as worker services, so it replaces web host with a more generic host builder:

// Program.cs
public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            }; 
    }
}

The Startup class looks pretty similar to the 2.x version though.

ASP.NET Core 2.x

You don't need to new IConfiguration in the Startup constructor. Its implementation will be injected by the DI system.

// Program.cs
public class Program
{
    public static void Main(string[] args)
    {
        BuildWebHost(args).Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .Build();            
}

// Startup.cs
public class Startup
{
    public IHostingEnvironment HostingEnvironment { get; private set; }
    public IConfiguration Configuration { get; private set; }

    public Startup(IConfiguration configuration, IHostingEnvironment env)
    {
        this.HostingEnvironment = env;
        this.Configuration = configuration;
    }
}

ASP.NET Core 1.x

You need to tell Startup to load the appsettings files.

// Program.cs
public class Program
{
    public static void Main(string[] args)
    {
        var host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            .UseStartup<Startup>()
            .UseApplicationInsights()
            .Build();

        host.Run();
    }
}

//Startup.cs
public class Startup
{
    public IConfigurationRoot Configuration { get; private set; }

    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
            .AddEnvironmentVariables();

        this.Configuration = builder.Build();
    }
    ...
}

Getting Values

There are many ways you can get the value you configure from the app settings:

Let's say your appsettings.json looks like this:

{
    "ConnectionStrings": {
        ...
    },
    "AppIdentitySettings": {
        "User": {
            "RequireUniqueEmail": true
        },
        "Password": {
            "RequiredLength": 6,
            "RequireLowercase": true,
            "RequireUppercase": true,
            "RequireDigit": true,
            "RequireNonAlphanumeric": true
        },
        "Lockout": {
            "AllowedForNewUsers": true,
            "DefaultLockoutTimeSpanInMins": 30,
            "MaxFailedAccessAttempts": 5
        }
    },
    "Recaptcha": { 
        ...
    },
    ...
}

Simple Way

You can inject the whole configuration into the constructor of your controller/class (via IConfiguration) and get the value you want with a specified key:

public class AccountController : Controller
{
    private readonly IConfiguration _config;

    public AccountController(IConfiguration config)
    {
        _config = config;
    }

    [AllowAnonymous]
    public IActionResult ResetPassword(int userId, string code)
    {
        var vm = new ResetPasswordViewModel
        {
            PasswordRequiredLength = _config.GetValue<int>(
                "AppIdentitySettings:Password:RequiredLength"),
            RequireUppercase = _config.GetValue<bool>(
                "AppIdentitySettings:Password:RequireUppercase")
        };

        return View(vm);
    }
}

Options Pattern

The ConfigurationBuilder.GetValue<T> works great if you only need one or two values from the app settings. But if you want to get multiple values from the app settings, or you don't want to hard code those key strings in multiple places, it might be easier to use Options Pattern. The options pattern uses classes to represent the hierarchy/structure.

To use options pattern:

  1. Define classes to represent the structure
  2. Register the configuration instance which those classes bind against
  3. Inject IOptions<T> into the constructor of the controller/class you want to get values on

1. Define configuration classes to represent the structure

You can define classes with properties that need to exactly match the keys in your app settings. The name of the class does't have to match the name of the section in the app settings:

public class AppIdentitySettings
{
    public UserSettings User { get; set; }
    public PasswordSettings Password { get; set; }
    public LockoutSettings Lockout { get; set; }
}

public class UserSettings
{
    public bool RequireUniqueEmail { get; set; }
}

public class PasswordSettings
{
    public int RequiredLength { get; set; }
    public bool RequireLowercase { get; set; }
    public bool RequireUppercase { get; set; }
    public bool RequireDigit { get; set; }
    public bool RequireNonAlphanumeric { get; set; }
}

public class LockoutSettings
{
    public bool AllowedForNewUsers { get; set; }
    public int DefaultLockoutTimeSpanInMins { get; set; }
    public int MaxFailedAccessAttempts { get; set; }
}

2. Register the configuration instance

And then you need to register this configuration instance in ConfigureServices() in the start up:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
...

namespace DL.SO.UI.Web
{
    public class Startup
    {
        ...
        public void ConfigureServices(IServiceCollection services)
        {
            ...
            var identitySettingsSection = 
                _configuration.GetSection("AppIdentitySettings");
            services.Configure<AppIdentitySettings>(identitySettingsSection);
            ...
        }
        ...
    }
}

Note: if you're not seeing the overload extension method of service.Configure<> that takes IConfiguration as parameter, you probably need to install Microsoft.Extensions.Options.ConfigurationExtensions NuGet package.

For ASP.NET Core 6.x

Due to the changes I mentioned at the beginning for ASP.NET Core 6.x, you would need to bind the section and add it to the DI in the following:

// Program.cs
public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        builder.Services.AddControllersWithViews();

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

        var app = builder.Build();

        ...

        app.Run();
    }
}

You can read more about this here.

3. Inject IOptions

Lastly on the controller/class you want to get the values, you need to inject IOptions<AppIdentitySettings> through constructor:

public class AccountController : Controller
{
    private readonly AppIdentitySettings _appIdentitySettings;

    public AccountController(IOptions<AppIdentitySettings> appIdentitySettingsAccessor)
    {
        _appIdentitySettings = appIdentitySettingsAccessor.Value;
    }

    [AllowAnonymous]
    public IActionResult ResetPassword(int userId, string code)
    {
        var vm = new ResetPasswordViewModel
        {
            PasswordRequiredLength = _appIdentitySettings.Password.RequiredLength,
            RequireUppercase = _appIdentitySettings.Password.RequireUppercase
        };

        return View(vm);
    }
}
David Liang
  • 20,385
  • 6
  • 44
  • 70
  • How can i access the Values in the Class which holds my Data? – Lukas Hieronimus Adler Jan 10 '18 at 08:09
  • @LukasHieronimusAdler: See `Controller` sample section in the original question?? Access the value by doing `IOptions settings` and `settings.Value`?? – David Liang Jan 11 '18 at 00:16
  • @DavidLiang if i change the appsettings.json file manually during runtime, my IOptions settings Object doesn't get the changed values. Whats wrong? If added this: .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) For me, it should reload on an external change right? – Lukas Hieronimus Adler Jan 12 '18 at 11:49
  • 1
    @LukasHieronimusAdler: You might want to use `IOptionsSnapshot` instead of `IOptions`. You can take a look at this article: https://offering.solutions/blog/articles/2017/02/17/automatically-reload-typed-configuration-in-asp-net-core/. I haven't had chance to try it myself though. – David Liang Jan 12 '18 at 18:06
  • @DavidLiang yes its still working, but i cant access the IOptionsSnapshot from normal Classes. If i pass the IOptionsSnapshot in the constructor like in controller-classes its needed to pass this object manually but how can i access it? Hopefully you know what i mean. Thanks for your help – Lukas Hieronimus Adler Jan 15 '18 at 10:40
  • I think you access `IOptionsSnapshot` class the same way you access `IOptions`? And in order for classes to be able to receive `IOptionsSnapshot`, you just need to inject `T` in the Startup, same way with `IOptions`! Please read through the article multiple times and find the Microsoft docs on this subject. Without taking a look at your source code, I don't get what problem you're facing. Sorry – David Liang Jan 15 '18 at 18:24
  • 34
    What a horrible step backwards from full stack .net – Aaron Oct 20 '18 at 23:48
  • 5
    Ok, so for .NET Core 3 you need Microsoft.Extensions.Options.ConfigurationExtensions package and it works fine – Tomas Bruckner Sep 29 '19 at 11:58
  • 12
    It's ridiculous that we need this much of an explanation to access a simple application setting... something that used to be one line in .NET Framework. I understand that dependency injection is generally a good thing, but in this instance it's a nuisance rather than a help. For once, it feels like C# is thinking about code, not the developer - it's all going a bit Java – Jon Story Apr 14 '20 at 17:33
  • 21
    Note for future self: The `GetValue` method is in the `Microsoft.Extensions.Configuration.Binder` Nuget package – Jérôme MEVEL Oct 06 '20 at 09:20
  • In .Net Core 3.1, **Simple Way** section mentioned above worked like charm for me. – Rajaraman Subramanian Sep 28 '21 at 05:37
  • 1
    Thank you @DavidLiang for such a thorough answer. It certainly helped me! :-) – AndyS Oct 16 '21 at 14:42
  • Suppose in the dev json file I created key called `key1` and in prod json file I create key called `key2`, then when I run the project in visual studio, it is reading both the keys. Shouldn't it read only the key from the dev json file? – variable Jan 12 '22 at 10:36
  • Suppose I change the value in the json file, then do I need to restart the application for it to pull the latest value? – variable Jan 12 '22 at 17:32
  • 1
    @variable: check your `launchSettings.json` under the Properties folder inside your startup project, and see what you have for `ASPNETCORE_ENVIRONMENT` under your IIS Express profile. It's supposed to run appsettings.{ENV}.json on top of the template file appsettings.json if you have that. – David Liang Jan 12 '22 at 20:13
  • 1
    @variable: for your other question, can you please see my reply at the beginning of this comment chain? I think I've answered a similar question before, using `IOptionsSnapshot`. – David Liang Jan 12 '22 at 20:14
  • How-to use it in MSTest project NET 6 ? – Kiquenet Jul 06 '22 at 10:05
  • In .NET 6 you have `ConfigureServices((services)) => {}` by default. By updating this to `ConfigureServices((context, services) =>{}` you can use `context.Configuration.GetSection("customSettings")` to get the settings from the JSON. – user2986756 Sep 12 '22 at 11:13
79

Just create An AnyName.cs file and paste following code.

using System;
using System.IO;
using Microsoft.Extensions.Configuration;

namespace Custom
{
    static class ConfigurationManager
    {
        public static IConfiguration AppSetting { get; }
        static ConfigurationManager()
        {
            AppSetting = new ConfigurationBuilder()
                    .SetBasePath(Directory.GetCurrentDirectory())
                    .AddJsonFile("YouAppSettingFile.json")
                    .Build();
        }
    }
}

Must replace YouAppSettingFile.json file name with your file name.
Your .json file should look like below.

{
    "GrandParent_Key" : {
        "Parent_Key" : {
            "Child_Key" : "value1"
        }
    },
    "Parent_Key" : {
        "Child_Key" : "value2"
    },
    "Child_Key" : "value3"
}

Now you can use it.
Don't forget to Add Reference in your class where you want to use.

using Custom;

Code to retrieve value.

string value1 = ConfigurationManager.AppSetting["GrandParent_Key:Parent_Key:Child_Key"];
string value2 = ConfigurationManager.AppSetting["Parent_Key:Child_Key"];
string value3 = ConfigurationManager.AppSetting["Child_Key"];
shajji
  • 1,517
  • 10
  • 14
  • 10
    Don't use this in production. This approach was what caused memory leaks in our web api. If you are using netcore you can inject IConfiguration literally anywhere, just see the above answers. – André Mantas Oct 08 '19 at 14:45
  • I would not recommend injecting `IConfiguration` everywhere, because this might cause in some security issues; what you can do instead is to create some abstraction layers of what you need from that configuration and use those where you need it. In this way your code is more secured and your code will not depend of IConfiguration or any implementation. – HellBaby Jul 31 '20 at 06:41
  • By me `ConfigurationBuilder` couldn't be found. I'm using .NET Core 3.1 – H. Pauwelyn Aug 30 '21 at 07:56
60

Adding to David Liang's answer for Core 2.0 -

appsettings.json file's are linked to ASPNETCORE_ENVIRONMENT variable.

ASPNETCORE_ENVIRONMENT can be set to any value, but three values are supported by the framework: Development, Staging, and Production. If ASPNETCORE_ENVIRONMENT isn't set, it will default to Production.

For these three values these appsettings.ASPNETCORE_ENVIRONMENT.json files are supported out of the box - appsettings.Staging.json, appsettings.Development.json and appsettings.Production.json

The above three application setting json files can be used to configure multiple environments.

Example - appsettings.Staging.json

{
    "Logging": {
        "IncludeScopes": false,
        "LogLevel": {
            "System": "Information",
            "Microsoft": "Information"
        }
    },
    "MyConfig": "My Config Value for staging."
}

Use Configuration["config_var"] to retrieve any configuration value.

public class Startup
{
    public Startup(IHostingEnvironment env, IConfiguration config)
    {
        Environment = env;
        Configuration = config;
        var myconfig = Configuration["MyConfig"];
    }

    public IConfiguration Configuration { get; }
    public IHostingEnvironment Environment { get; }
}
RAM
  • 2,257
  • 2
  • 19
  • 41
A G
  • 21,087
  • 11
  • 87
  • 112
  • 1
    What about nested objects ? – Arthur Attout Apr 17 '18 at 06:44
  • 11
    Nested objects can be obtained with Configuration["MyConfig:SomethingNested"] – WeHaveCookies May 15 '18 at 22:11
  • 1
    As can be seen in the file https://github.com/aspnet/AspNetCore/blob/master/src/DefaultBuilder/src/WebHost.cs at line 167 ASP.NET Core currently loads `appsettings.json` + `appsettings.{env.EnvironmentName}.json`. So the statement that ASP.NET Core only loads Development, Staging and Production appsettings.json files is currently incorrect. – mvdgun Apr 03 '19 at 03:56
  • 1
    so am I supposed to set Windows variable `ASPNETCORE_ENVIRONMENT` every time? Things were way easier in .Net 4. These JSON fanatics did screw it up big time – Toolkit Aug 02 '19 at 10:27
  • @Toolkit You can set the environment variable globally. https://learn.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-2.2#set-the-environment – A G Aug 02 '19 at 10:31
  • Suppose in the dev json file I created key called `key1` and in prod json file I create key called `key2`, then when I run the project in visual studio, it is reading both the keys. Shouldn't it read only the key from the dev json file? – variable Jan 12 '22 at 10:36
  • Suppose I change the value in the json file, then do I need to restart the application for it to pull the latest value? – variable Jan 12 '22 at 17:32
45

I guess the simplest way is by DI. An example of reaching into Controller.

// StartUp.cs
public void ConfigureServices(IServiceCollection services)
{
    ...
    // for get appsettings from anywhere
    services.AddSingleton(Configuration);
}

public class ContactUsController : Controller
{
    readonly IConfiguration _configuration;

    public ContactUsController(
        IConfiguration configuration)
    {
        _configuration = configuration;

        // sample:
        var apiKey = _configuration.GetValue<string>("SendGrid:CAAO");
        ...
    }
}
Sith2021
  • 3,245
  • 30
  • 22
22

Suppose you have values like this in appsettings.json.

  "MyValues": {
    "Value1": "Xyz"
  }

Method 1: Without Dependency Injection

In .cs file:

static IConfiguration conf = (new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json").Build());
public static string myValue1= conf["MyValues:Value1"].ToString();

Method 2: With Dependency Injection (Recommended)

In Startup.cs file:

public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
     Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
     ...
     services.AddServices(Configuration);
}

In your Controller:

public class TestController : ControllerBase
{
    private string myValue1 { get; set; }
    public TestController(IConfiguration configuration)
    {
         this.myValue1 = configuration.GetValue<string>("MyValues:Value1");
    }
}
Abhishek Pandey
  • 349
  • 3
  • 12
18

In the constructor of Startup class, you can access appsettings.json and many other settings using the injected IConfiguration object:

Startup.cs Constructor

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;

        //here you go
        var myvalue = Configuration["Grandfather:Father:Child"];

    }

public IConfiguration Configuration { get; }

Contents of appsettings.json

  {
  "Grandfather": {
    "Father": {
      "Child": "myvalue"
    }
  }
Shadi Alnamrouti
  • 11,796
  • 4
  • 56
  • 54
12
    public static void GetSection()
    {
        Configuration = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json")
            .Build();

        string BConfig = Configuration.GetSection("ConnectionStrings")["BConnection"];

    }
  • 1
    I disagree with @CarlosABS, this is the BEST ANSWER: All the others - for some mysterious reason - assume that you are using DI and rely their answers on that. *THIS* however is the essence of the answer, at least for me :) I don't need anything beyond that, so the other answers seem somewhat bloated. – csstudent1418 Aug 10 '21 at 20:54
  • 3
    It should be added though that you need **THREE** goddamn NuGet packages for this to work: `Microsoft.Extensions.Configuration`, `Microsoft.Extensions.Configuration.FileExtensions` and `Microsoft.Extensions.Configuration.Json` . I get the whole modularity thing in .net Core but Jesus sometimes you literally need another package for every line of code ... – csstudent1418 Aug 10 '21 at 20:57
5

For ASP.NET Core 3.1 you can follow this guide:

https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1

When you create a new ASP.NET Core 3.1 project you will have the following configuration line in Program.cs:

Host.CreateDefaultBuilder(args)

This enables the following:

  1. ChainedConfigurationProvider : Adds an existing IConfiguration as a source. In the default configuration case, adds the host configuration and setting it as the first source for the app configuration.
  2. appsettings.json using the JSON configuration provider.
  3. appsettings.Environment.json using the JSON configuration provider. For example, appsettings.Production.json and appsettings.Development.json.
  4. App secrets when the app runs in the Development environment.
  5. Environment variables using the Environment Variables configuration provider.
  6. Command-line arguments using the Command-line configuration provider.

This means you can inject IConfiguration and fetch values with a string key, even nested values. Like IConfiguration["Parent:Child"];

Example:

appsettings.json

{
  "ApplicationInsights":
    {
        "Instrumentationkey":"putrealikeyhere"
    }
}

WeatherForecast.cs

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    private readonly ILogger<WeatherForecastController> _logger;
    private readonly IConfiguration _configuration;

    public WeatherForecastController(ILogger<WeatherForecastController> logger, IConfiguration configuration)
    {
        _logger = logger;
        _configuration = configuration;
    }

    [HttpGet]
    public IEnumerable<WeatherForecast> Get()
    {
        var key = _configuration["ApplicationInsights:InstrumentationKey"];

        var rng = new Random();
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = rng.Next(-20, 55),
            Summary = Summaries[rng.Next(Summaries.Length)]
        })
        .ToArray();
    }
}
Ogglas
  • 62,132
  • 37
  • 328
  • 418
  • Where can I learn more about the `IConfiguration["Parent:Child"]` syntax? – xr280xr Jun 29 '20 at 23:18
  • @xr280xr You can find the syntax details here https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1#hierarchical-configuration-data and here https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1#configuration-keys-and-values Same page different sections but that page in general contains the details. – Craig Aug 22 '20 at 15:50
  • @xr280xr Worth mentioning that using the options pattern is the preferred method of getting config values. https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1#bind-hierarchical-configuration-data-using-the-options-pattern – Craig Aug 22 '20 at 16:13
5

.NET core 3.X

no need to create new model and to set in Startup.cs.

Controller Add new package - using Microsoft.Extensions.Configuration;

public class HomeController : Controller
{
    private readonly IConfiguration _mySettings;

    public HomeController (IConfiguration mySettings)
    {
         _mySettings= mySettings;
    }
 
    //ex: you can get value on below function 
    public IEnumerable<string> Get()
    {
        var result = _config.GetValue<string>("AppSettings:Version"); // "One"
        return new string[] { result.ToString() };
    }
}
Jorge Eduardo
  • 59
  • 1
  • 3
3

In my case it was simple as using the Bind() method on the Configuration object. And then add the object as singleton in the DI.

var instructionSettings = new InstructionSettings();
Configuration.Bind("InstructionSettings", instructionSettings);
services.AddSingleton(typeof(IInstructionSettings), (serviceProvider) => instructionSettings);

The Instruction object can be as complex as you want.

{  
 "InstructionSettings": {
    "Header": "uat_TEST",
    "SVSCode": "FICA",
    "CallBackUrl": "https://UATEnviro.companyName.co.za/suite/webapi/receiveCallback",
    "Username": "s_integrat",
    "Password": "X@nkmail6",
    "Defaults": {
    "Language": "ENG",
    "ContactDetails":{
       "StreetNumber": "9",
       "StreetName": "Nano Drive",
       "City": "Johannesburg",
       "Suburb": "Sandton",
       "Province": "Gauteng",
       "PostCode": "2196",
       "Email": "ourDefaultEmail@companyName.co.za",
       "CellNumber": "0833 468 378",
       "HomeNumber": "0833 468 378",
      }
      "CountryOfBirth": "710"
    }
  }
Chris Stillwell
  • 10,266
  • 10
  • 67
  • 77
3

From Asp.net core 2.2 to above you can code as below:

Step 1. Create an AppSettings class file.

This file contains some methods to help get value by key from the appsettings.json file. Look like as code below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ReadConfig.Bsl
{
  public class AppSettings
  {
      private static AppSettings _instance;
      private static readonly object ObjLocked = new object();
      private IConfiguration _configuration;

      protected AppSettings()
      {
      }

      public void SetConfiguration(IConfiguration configuration)
      {
          _configuration = configuration;
      }

      public static AppSettings Instance
      {
          get
          {
              if (null == _instance)
              {
                  lock (ObjLocked)
                  {
                      if (null == _instance)
                          _instance = new AppSettings();
                  }
              }
              return _instance;
          }
      }

      public string GetConnection(string key, string defaultValue = "")
      {
          try
          {
              return _configuration.GetConnectionString(key);
          }
          catch
          {
              return defaultValue;
          }
      }

      public T Get<T>(string key = null)
      {
          if (string.IsNullOrWhiteSpace(key))
              return _configuration.Get<T>();
          else
              return _configuration.GetSection(key).Get<T>();
      }

      public T Get<T>(string key, T defaultValue)
      {
          if (_configuration.GetSection(key) == null)
              return defaultValue;

          if (string.IsNullOrWhiteSpace(key))
              return _configuration.Get<T>();
          else
              return _configuration.GetSection(key).Get<T>();
      }

      public static T GetObject<T>(string key = null)
      {
          if (string.IsNullOrWhiteSpace(key))
              return Instance._configuration.Get<T>();
          else
          {
              var section = Instance._configuration.GetSection(key);
              return section.Get<T>();
          }
      }

      public static T GetObject<T>(string key, T defaultValue)
      {
          if (Instance._configuration.GetSection(key) == null)
              return defaultValue;

          if (string.IsNullOrWhiteSpace(key))
              return Instance._configuration.Get<T>();
          else
              return Instance._configuration.GetSection(key).Get<T>();
      }
  }
}

Step 2. Initial configuration for AppSettings object

We need to declare and load appsettings.json file when the application starts, and load configuration information for AppSettings object. We will do this work in the constructor of the Startup.cs file. Please notice line AppSettings.Instance.SetConfiguration(Configuration);

public Startup(IHostingEnvironment evm)
{
    var builder = new ConfigurationBuilder()
      .SetBasePath(evm.ContentRootPath)
      .AddJsonFile("appsettings.json", true, true)
      .AddJsonFile($"appsettings.{evm.EnvironmentName}.json", true)
      .AddEnvironmentVariables();
    Configuration = builder.Build(); // load all file config to Configuration property 
    AppSettings.Instance.SetConfiguration(Configuration);       
}

Okay, now I have an appsettings.json file with some keys as below:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "ConnectionString": "Data Source=localhost;Initial Catalog=ReadConfig;Persist Security Info=True;User ID=sa;Password=12345;"
  },
  "MailConfig": {
    "Servers": {
      "MailGun": {
        "Pass": "65-1B-C9-B9-27-00",
        "Port": "587",
        "Host": "smtp.gmail.com"
      }
    },
    "Sender": {
      "Email": "example@gmail.com",
      "Pass": "123456"
    }
  }
}

Step 3. Read config value from an action

I make demo an action in Home controller as below :

public class HomeController : Controller
{
    public IActionResult Index()
    {
        var connectionString = AppSettings.Instance.GetConnection("ConnectionString");
        var emailSender = AppSettings.Instance.Get<string>("MailConfig:Sender:Email");
        var emailHost = AppSettings.Instance.Get<string>("MailConfig:Servers:MailGun:Host");

        string returnText = " 1. Connection String \n";
        returnText += "  " +connectionString;
        returnText += "\n 2. Email info";
        returnText += "\n Sender : " + emailSender;
        returnText += "\n Host : " + emailHost;

        return Content(returnText);
    }
}

And below is the result:

Click to see result

Brad Larson
  • 170,088
  • 45
  • 397
  • 571
2
  1. Add the required key here like this. In this case its SecureCookies:

Add the required key here like this. In this case its SecureCookies

  1. In startup.cs, add the constructor

     public Startup(IConfiguration configuration)
     {
         Configuration = configuration;
    
     }
     public IConfiguration Configuration { get; }
    
  2. Access the settings using Configuration["SecureCookies"]

ChristianYami
  • 586
  • 1
  • 9
  • 17
BIJIN PALAKKAL
  • 186
  • 1
  • 4
2

I had a similar problem in WPF (.NET Framework 5.0)

All I had to do was to register it.

services.AddSingleton<IConfiguration>(_configuration);

The config itself was configured like this (in App.xaml.cs):

var builder = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);

_configuration = builder.Build();
Icad
  • 101
  • 1
  • 6
1

This tends to happen particularly with as I'd assume because of how one configures the launch.json.

Based on this answer I had to reconfigure the base path the configuration is being searched for to that of DLL's path, and since the default setting was optional it was hard to track this down on a .net core 3.1 & net 5.0 app. Here's how I've reconfigured

Program.cs:

using System;
using System.IO;
using System.Reflection;
using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

namespace API
{
    public class Program
    {
        public static int Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
            return 0;
        }

        public static IHostBuilder CreateHostBuilder(string[] args)
        {
            return Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration(c =>
            {
                var codeBase = Assembly.GetExecutingAssembly().Location;
                var uri = new UriBuilder(codeBase);
                var path = Uri.UnescapeDataString(uri.Path);
                var assembyDirectory = Path.GetDirectoryName(path);
                c.SetBasePath(assembyDirectory);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            })
            ;
        }
    }
}

I could access the configuration fine in Startup.cs:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Model;

namespace API
{
    public class Startup
    {
        public IConfiguration Configuration { get; }

        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            var myOptions = Configuration.To<ApiConfig>();
            services.AddAuthentication(myOptions.Secret);
            services.AddControllers();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
        }
    }
}
Nae
  • 14,209
  • 7
  • 52
  • 79
  • 1
    Thank u its works. When I ran the exe extension, the config was not read, and it was fixed when I added that code to Program.cs. – Bora Karaca Jun 16 '22 at 08:38
1

I found it easiest to do it the following with .NET Core 3+. I found all the other methods of using HostBuilders etc to be a bit longwinded and not as readable. This is not specifically for ASP.Net but you can adapt it...

There is a working example here: https://github.com/NotoriousPyro/PyroNexusTradingAlertBot/blob/develop/PyroNexusTradingAlertBot/Program.cs

Create the json:

{
"GlobalConfig": {
    "BlacklistedPairs": [ "USD", "USDT", "BUSD", "TUSD", "USDC", "DAI", "USDK" ]
},
"CoinTrackingConfig": {
    "Cookie1": "",
    "Cookie2": "",
    "ApiKey": "",
    "ApiSecret": "",
    "UpdateJobs": [
    {
        "Name": "Binance",
        "Path": "binance_api",
        "JobId": 42202
    },
    {
        "Name": "Bitfinex",
        "Path": "bitfinex_api",
        "JobId": 9708
    }
    ]
},
"DiscordConfig": {
    "BotToken": ""
}
}

Create the class for the json objects:

class GlobalConfig
{
    public string[] BlacklistedPairs { get; set; }
}
class CoinTrackingConfig
{
    public string Cookie1 { get; set; }
    public string Cookie2 { get; set; }
    public string ApiKey { get; set; }
    public string ApiSecret { get; set; }
    public List<CoinTrackingUpdateJobs> UpdateJobs { get; set; }
}

class CoinTrackingUpdateJobs
{
    public string Name { get; set; }
    public string Path { get; set; }
    public int JobId { get; set; }
}

class DiscordConfig
{
    public string BotToken { get; set; }
}

Create a helper class:

private class Config
{
    private IConfigurationRoot _configuration;
    public Config(string config) => _configuration = new ConfigurationBuilder()
            .AddJsonFile(config)
            .Build();

    public T Get<T>() where T : new()
    {
        var obj = new T();
        _configuration.GetSection(typeof(T).Name).Bind(obj);
        return obj;
    }
}

The service provider options and service constructor:

public class DiscordServiceOptions
{
    public string BotToken { get; set; }
}

public DiscordService(IOptions<DiscordServiceOptions> options, ILogger<DiscordService> logger)
{
    _logger = logger;
    _client = new DiscordSocketClient();
    _client.Log += Log;
    _client.Ready += OnReady;
    _client.Disconnected += OnDisconnected;
    _client.LoginAsync(TokenType.Bot, options.Value.BotToken);
    _client.StartAsync();
}

Initialise it like so (Pass in the config into the service provider - the IOptions will be passed in when the service is built):

static async Task Main(string[] args)
{
    var _config = new Config("config.json");

    var globalConfig = config.Get<GlobalConfig>();
    var coinTrackingConfig = config.Get<CoinTrackingConfig>();
    var discordConfig = config.Get<DiscordConfig>();

    _services = new ServiceCollection()
        .AddOptions()
        .Configure<DiscordServiceOptions>(options =>
        {
            options.BotToken = discordConfig.BotToken;
        })
        .AddSingleton<IDiscordService, DiscordService>()
        .AddLogging(logging =>
        {
            logging.SetMinimumLevel(LogLevel.Trace);
            logging.AddNLog(new NLogProviderOptions
            {
                CaptureMessageTemplates = true,
                CaptureMessageProperties = true
            });
        })
        .BuildServiceProvider();
}
NotoriousPyro
  • 526
  • 3
  • 16
1
  1. appsetting.json

{   
  "Settings": {      
    "ProjectName": "Sample Project"   
  }
}
  1. Define a class with the same property name:
 public class Settings
 {
     public string ProjectName { get; set; }  
 }
  1. Add configuration in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
    services.Configure<Settings>(Configuration.GetSection("Settings")); 
}
  1. Inject into controller:
public class TestController : Controller
{
    private readonly Settings _settings;       
    
    public TestController(IOptions<Settings> settings)
    {
         _settings = settings.Value;
    }
       
    [AllowAnonymous]
    public async Task<IActionResult> test()
    {
        var _projectname = _settings.ProjectName;
                
        return View();
    }
}
Jackdaw
  • 7,626
  • 5
  • 15
  • 33
  • You also need to declare and initialize Configuration in Startup.cs. public IConfiguration Configuration { get; } public Startup(IConfiguration configuration) => Configuration = configuration; – Dranyar Feb 04 '22 at 19:29
0

I think the best option is:

  1. Create a model class as config schema

  2. Register in DI: services.Configure(Configuration.GetSection("democonfig"));

  3. Get the values as model object from DI in your controller:

    private readonly your_model myConfig;
    public DemoController(IOptions<your_model> configOps)
    {
        this.myConfig = configOps.Value;
    }
    
Meghnath Das
  • 145
  • 1
  • 6
0

In my case, I created everything from scratch and the appsettings.json too, was not loaded at all. After some debugging, I discovered that the file was never copied to the "target folder".

To fix it, I simply had to set the correct file properties.

It looks like this:

enter image description here

Krzysztof Boduch
  • 675
  • 9
  • 12
0

I just create a static class and set a config variable to it in Startup.cs

public static class GlobalConfig { 
    public static IConfiguration config { get; set; } 
}

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        GlobalConfig.config = configuration;

    }
}

Then use it anywhere:

var keyVal = GlobalConfig.config["key"];

Seems like the easiest way to access the config file and make it available anywhere.

Simon Fallai
  • 611
  • 5
  • 5
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Dec 14 '21 at 17:47
0

Adding to Abishek's answer:

If you want to import values into a static class, then just use (recommended by ReSharper):

static IConfiguration conf = (JsonConfigurationExtensions.AddJsonFile(new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()), "appsettings.json").Build());

private static string AuthorizationServiceURL { get; } = conf["ServiceUrls:AuthorizationUrl"];

// appsettings.json
{
  "ServiceUrls": {
    "AuthorizationUrl": "https://example.com/authorize"
  } 
}
Syed Rafay
  • 1,405
  • 2
  • 15
  • 19
0

Spent an hour trying to fix the same problem, my solution was to add PreserveNewest/CopyAlways for appconfig.json in csproj

<None Update="appsettings.json">
  <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
denisv
  • 319
  • 3
  • 11
0

here is an abstraction over .NET Framework and Core: web.config, app.config and appsettings.json

    static SafeDictionary<string, string> _appSettings;

    public static SafeDictionary<string, string> AppSettings {
        get {
            if (_appSettings == null)
            {
                _appSettings = ConfigurationManager.AppSettings
                    .ToDictionary()
                    .ToSafe();

                BuildAppSettings( JsonAppSettings, "");

            }

            return _appSettings;
        }
    }


    static SafeDictionary<string, string> _connectionStrings;

    public static SafeDictionary<string, string> ConnectionStrings
    {
        get
        {
            if (_connectionStrings == null)
            {
                _connectionStrings = ConfigurationManager.ConnectionStrings
                    .Cast<ConnectionStringSettings>()
                    .ToDictionary(x => x.Name, x => x.ConnectionString)
                    .ToSafe();

                foreach (var jp in JsonAppSettings["ConnectionStrings"].Cast<JProperty>())
                    _connectionStrings.Add(jp.Name, jp.Value.ToString() );

            }

            return _connectionStrings;
        }
    }

https://github.com/bitministry/common

Andrew Rebane
  • 199
  • 3
  • 12
0

You can refer to this link if the above solutions are not help. For me the Named options support using IConfigureNamedOptions works! You may also find out other methods might be helpful for you.

Named options support using IConfigureNamedOptions

0
  1. Add this in your startup. This will validate config while booting.

    services.AddOptions<YourType>().BindConfiguration("YourAppSettingSectionName").ValidateDataAnnotations().ValidateOnStart();
    
  2. Then inject IOptions in your constructer where you want to access the properties.

    public Ctor(IOptions<YourType> options)
     { 
        //Your code goes here 
     }
    

Note: The config property name should match with class property names else you'll have to map it manually.

v.t.
  • 41
  • 2