66

i'm creating a console application using .NET Core 3.1 and i would like to have an appsettings json to load all environment, paths, variables,... at the beginning of the execution, and then get values from other library classes. I have created a 'Settings' class with the data included in the appsettings json. This is what i have already by looking out in tutorials but i'm not able to get any value.

//Start.cs
public class Startup
{
        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();

            Configuration = builder.Build();
        }

        public IConfiguration Configuration { get; }

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

//Settings.cs
 public class Settings
    {
        public ConnectionStrings ConnectionStrings { get; set; }
        public Logging Logging { get; set; }
        public AppSettings AppSettings { get; set; }
    ...

//A class to use it in other lib
 public class Extractor
    {
        private readonly IConfiguration _configuration;

        public Extractor(IConfiguration configuration) : this()
        {
            _configuration = configuration;
            Init();
        }

        public void Init()
        {
            // Extractor:Min is a variable included in appsettings.json
            Min = _configuration.GetValue<int>("Extractor:Min")
                                  
        }

I cannot make a proper Main as i don't know how to initialize everything...what am i missing? I think i've been going in circles for something that easy. Thanks in advance! NOTE: i need to get those variables from another library class, not in Main. I don't know how to initialize 'configuration' in other classes in order to use it. Thanks

JaviL
  • 763
  • 1
  • 5
  • 5
  • Does this answer your question? [How to read AppSettings values from a .json file in ASP.NET Core](https://stackoverflow.com/questions/31453495/how-to-read-appsettings-values-from-a-json-file-in-asp-net-core) – Ergis Dec 02 '20 at 15:39
  • For .net 6 and above, see my [answer way below](https://stackoverflow.com/a/70242856/1977871) – VivekDev May 31 '22 at 06:50

6 Answers6

79

Your example is mixing in some ASP NET Core approaches that expect your code to be hosted. To minimally solve the issue of getting options or settings from a JSON configuration, consider the following:

A config.json file, set to "Copy to Output Directory" so that it is included with the build:

{
  "MyFirstClass": {
    "Option1": "some string value",
    "Option2": 42
  },
  "MySecondClass": {
    "SettingOne": "some string value",
    "SettingTwo": 42
  }
}

The following approach will load the content from the JSON file, then bind the content to two strongly-typed options/settings classes, which can be a lot cleaner than going value-by-value:

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

// NuGet packages:
// Microsoft.Extensions.Configuration.Binder
// Microsoft.Extensions.Configuration.Json

namespace SampleConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("config.json", optional: false);

            IConfiguration config = builder.Build();

            var myFirstClass = config.GetSection("MyFirstClass").Get<MyFirstClass>();
            var mySecondClass = config.GetSection("MySecondClass").Get<MySecondClass>();
            Console.WriteLine($"The answer is always {myFirstClass.Option2}");
        }
    }

    public class MyFirstClass
    {
        public string Option1 { get; set; }
        public int Option2 { get; set; }
    }

    public class MySecondClass
    {
        public string SettingOne { get; set; }
        public int SettingTwo { get; set; }
    }
}
Adam
  • 3,339
  • 1
  • 10
  • 15
  • Thanks for the response! The problem is i need to get those variables in another library class, not in Main. I don't know how to initialize 'configuration' in other classes in order to use it. Thanks – JaviL Dec 02 '20 at 15:47
  • @JaviL You can put those settings/options classes or the IConfiguration object itself into a static, global instance, or you can look into using Dependency Injection and an IoC container (either the ASP NET Core one or another of your choice) to properly inject these options into whatever other classes expect to consume them. – Adam Dec 02 '20 at 15:57
  • Older article, but relevant to the secondary question being asked: https://andrewlock.net/using-dependency-injection-in-a-net-core-console-application/ – Adam Dec 02 '20 at 15:58
  • 1
    If you want to use `AddEnvironmentVariables` method you need to install [this package](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.EnvironmentVariables) – ivanko337 Feb 20 '22 at 22:44
  • I might be dumb, but I don't understand why we have to add classes and modify code as part of reading a config file now. I miss the old app.config days. – dpberry178 Aug 26 '22 at 14:58
  • 1
    @dpberry178 maybe you don't in simple cases, but the ability to layer composition of strongly typed (and validatable) options from multiple configuration sources and inject those into an IOC container with mechanisms for snapshots/change detection is pretty powerful. – Adam Sep 15 '22 at 17:35
32

To get started with Visual Studio 2022 and .net 6 follow the steps below. If you have the latest update of Visual Studio 2022(17.4.0 or above), you can create apps with .net 7 as well in the same lines.

If you want to just use Visual Studio Code and not Visual Studio 2022, scroll down to see the instructions.

  1. Create a new console project.
  2. Add an appsettings.json file to the project.
  3. Right click, select properties and ensure its copied to output directory.

appsettings file properties

  1. Edit the file to look something like this.

     {
       "ConnectionString": "Server=localhost;Database=tempDB;Uid=<dbUserName>;Pwd=<dbPassword>",
       "Smtp": {
         "Host": "smtp.gmail.com",
         "From": "Your Name"
       },
       "MySecondClass": {
         "SettingOne": "some string value",
         "SettingTwo": 82
       }
     }
    
  2. Edit your project csproj file to include Microsoft.Extensions.Configuration and its json counter part package. See below, note the appsettings.json file as well.

    <Project Sdk="Microsoft.NET.Sdk">

      <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net6.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
      </PropertyGroup>

      <ItemGroup>
        <PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0" />
        <PackageReference Include="Microsoft.Extensions.Configuration.json" Version="6.0.0" />
      </ItemGroup>

      <ItemGroup>
        <None Update="appsettings.json">
          <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </None>
      </ItemGroup>

    </Project>

  1. And finally your program.cs file will look like this.

     using System;
     using System.IO;
     using Microsoft.Extensions.Configuration;
    
     // See https://aka.ms/new-console-template for more information
     Console.WriteLine("Hello, World!");
    
    
     var builder = new ConfigurationBuilder()
                     .AddJsonFile($"appsettings.json", true, true);
    
     var config = builder.Build();
    
     var connectionString = config["ConnectionString"];
     var emailHost = config["Smtp:Host"];
     Console.WriteLine($"Connection String is: {connectionString}");
     Console.WriteLine($"Email Host is: {emailHost}");
     var settingTwo = config["MySecondClass:SettingOne"];
     Console.WriteLine(settingTwo);
    

If you just want to use Visual Studio Code and not Visual Studio 2022 do the following.

  1. Make a directory for a simple-console-app and cd into it.

Make a directory for console app

  1. Execute the following command to create a new console app.
dotnet new console
dotnet run

Create and run the console app

  1. Now open the project in Vs Code by running the following command.

code .

Open in Vs Code

  1. Add a new file appsettings.json and edit it to look something like this.

     {
       "ConnectionString": "Server=localhost;Database=tempDB;Uid=<dbUserName>;Pwd=<dbPassword>",
       "Smtp": {
         "Host": "smtp.gmail.com",
         "From": "Your Name"
       },
       "MySecondClass": {
         "SettingOne": "some string value",
         "SettingTwo": 82
       }
     }
    
  2. Edit your project csproj file to include Microsoft.Extensions.Configuration and its json counter part package. See below, note the appsettings.json file as well.

    <Project Sdk="Microsoft.NET.Sdk">

      <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net6.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
      </PropertyGroup>

      <ItemGroup>
        <PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0" />
        <PackageReference Include="Microsoft.Extensions.Configuration.json" Version="6.0.0" />
      </ItemGroup>

      <ItemGroup>
        <None Update="appsettings.json">
          <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </None>
      </ItemGroup>

    </Project>

  1. And finally your program.cs file will look like this.

     using System;
     using System.IO;
     using Microsoft.Extensions.Configuration;
    
     // See https://aka.ms/new-console-template for more information
     Console.WriteLine("Hello, World!");
    
    
     var builder = new ConfigurationBuilder()
                     .AddJsonFile($"appsettings.json", true, true);
    
     var config = builder.Build();
    
     var connectionString = config["ConnectionString"];
     var emailHost = config["Smtp:Host"];
     Console.WriteLine($"Connection String is: {connectionString}");
     Console.WriteLine($"Email Host is: {emailHost}");
     var settingTwo = config["MySecondClass:SettingOne"];
     Console.WriteLine(settingTwo);
    
  2. Now time to run. But first do dotnet restore and then dotnet run.

dotnet restore
dotnet run

Restore and Run

VivekDev
  • 20,868
  • 27
  • 132
  • 202
  • 2
    Your post is good, except it lacks to mention "Microsoft.Extensions.Configuration.Json" package which is also required to read json configuration files – AFract Jan 24 '22 at 10:22
  • 2
    I included the cs prof file xml as well, but somehow it did not appear. Check now. – VivekDev Jan 24 '22 at 13:06
  • On visual studio 2022 version 17.2.2, Microsoft.Extensions.Configuration,json auto included in the project. We can updated version from tools->NutGet packageManager – Tony Dong May 30 '22 at 15:09
31

http://www.techtutorhub.com/article/how-to-read-appsettings-json-configuration-file-in-dot-net-core-console-application/83

helpfull !

  1. appsettings.json (after add appsettings.json, go to property and mark the file as copy to out directory)
{
  "ConnectionString": "Server=localhost;Database=tempDB;Uid=<dbUserName>;Pwd=<dbPassword>",
  "Smtp": {
    "Host": "smtp.gmail.com",
    "Port": "587",
    "Username": "<YourGmailUserName>",
    "Password": "<YourGmailPassword>",
    "From": "Your Name"
  }
}

2.package needed

dotnet add package Microsoft.Extensions.Configuration
dotnet add package Microsoft.Extensions.Configuration.Json
  1. program.cs
using System; 
using Microsoft.Extensions.Configuration;

    class Program
        {
            static void Main(string[] args)
            {
                  var builder = new ConfigurationBuilder()
                   .AddJsonFile($"appsettings.json", true, true);
    
                var config = builder.Build();
                var connectionString = config["ConnectionString"];
                var emailHost = config["Smtp:Host"];
                Console.WriteLine($"Connection String is: {connectionString}");
                Console.WriteLine($"Email Host is: {emailHost}");
                Console.ReadLine();
            }
        }
Romylussone
  • 773
  • 1
  • 8
  • 19
15

I had the same issue with .NET Core and I found this solution to be working well:

  1. I have this appsettings.json
    {
      "App": 
      {
        "LoginCredentials": 
        {
           "ClientId": "xxx",
           "ClientSecret": "xxx",
           "TenantId": "xxx"
        },
        "DataBase": 
        {
            "PathToDatabases": "xxx"
        },
        "General": 
        {
           "PathToLogFiles": "xxx"
        }
      }

    }
  1. I created a class AppSettingsHandler.cs
    public class AppSettingsHandler
    {
        private string _filename;
        private AppSettings _config;

        public AppSettingsHandler(string filename)
        {
            _filename = filename;
            _config = GetAppSettings();
        }

        public AppSettings GetAppSettings()
        {
            var config = new ConfigurationBuilder()
               .SetBasePath(AppContext.BaseDirectory)
               .AddJsonFile(_filename, false, true)
               .Build();

            return config.GetSection("App").Get<AppSettings>();
        }
    }

  1. Then you need a "model" class for AppSettings:
    public class AppSettings
    {
        public LoginCredentialsConfiguration LoginCredentials { get; set; }
        public DatabaseConfiguration DataBase { get; set; }
        public GeneralConfiguration General { get; set; }
    }

and a model class for each of the included sub-classes, I only exemplify one here:

    public class LoginCredentialsConfiguration
    {
        public string ClientId { get; set; }
        public string ClientSecret { get; set; }
        public string TenantId { get; set; }
    }
  1. In your Program.cs class, you can now get the parameters from the appsettings.json like this:
            var aH = new AppSettingsHandler("appsettings.json");
            var aS = aH.GetAppSettings();
            var myPath = aS.DataBase.PathToDatabases;

Of course you can tweak that code so that it will match your requirements, i. e., you have to define your own classes and subclasses and of course you can extend the AppSettingsHandler.cs by also getting other sections of the appsettings.json.

  • Thanks for the response! The problem is i need to get those variables in another library class, not in Main. I don't know how to initialize 'configuration' in other classes in order to use it. Thanks – JaviL Dec 02 '20 at 15:48
  • 1
    `SetBasePath()` no longer exists in .net core 5. What is the alternative? – Kellen Stuart Jun 17 '21 at 17:05
  • 3
    install nuget packages `Microsoft.Extensions.Configuration.Json` and `Microsoft.Extensions.Configuration.Binder` – thargenediad Sep 14 '21 at 14:02
7

I've tried the followings and it's worked fine.

1- Add your launchSettings.json to your project under Properties folder.
2- Add your appsettings files to your project for each environment.
3- Add your appsettings files to your .csproj as shown below.
4- Then you can inject and reach IConfiguration that reads appsettings file according to the environment via below code.

    var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
    
    var configuration =  new ConfigurationBuilder()
         .SetBasePath(Directory.GetCurrentDirectory())
         .AddJsonFile($"appsettings.{environment}.json")
         .AddEnvironmentVariables()
         .AddCommandLine(args)
         .Build();
    
    var serviceProvider = new ServiceCollection()
        .AddSingleton<IConfiguration>(configuration)
        .BuildServiceProvider();
    
    var configurationInstance = serviceProvider.GetService<IConfiguration>();

launchSettings.json

{
  "profiles": {
    "YourProject": {
      "commandName": "Project",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "DEV"
      }
    }
  }
}


You should add your appSettings files in your .csproj file

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Autofac" Version="6.3.0" />
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
  </ItemGroup>

  <ItemGroup>
    <None Update="appsettings.DEV.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="appsettings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="appsettings.Production.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="appsettings.QA.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>

</Project>


And you may inject it anywhere

public class ConnectionService
{
    private readonly IConfiguration _configuration;

    public ConnectionService(IConfiguration configuration)
    {
        _configuration = configuration;
    }
}
Furkan Öztürk
  • 1,178
  • 11
  • 24
1

I am using dotnet 6. You just need to call CreateDefaultBuilder on Host.

await Host
.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) => 
{
    services
        .AddHostedService<ConsoleHostedService>();
})
.RunConsoleAsync();

where ConsoleHostedService implements IHostedService.

By calling ConfigureServices it will do what you need.

UncleFifi
  • 825
  • 1
  • 6
  • 9
  • Special Note, what ever settings file you add remember to set option to Copy Output to directory to Copy Always. see following for reference https://stackoverflow.com/questions/4596508/vs2010-how-to-include-files-in-project-to-copy-them-to-build-output-directory-a#:~:text=Add%20the%20file%20to%20your,See%20MSDN.&text=In%20the%20solution%20explorer%20click,your%20file%20into%20that%20folder. – UncleFifi Jun 01 '22 at 14:38
  • Where did you put this code in? Is this a custom class? Can you clarify? I checked the link from MS and it looks like there's a hundred different ways to do this. Is there a "proper" method for setting this all up in DotNet6 for a Console app (not a website)? – MC9000 Jul 29 '22 at 11:27
  • @MC9000 would you kindly look at the following github repo to see if this answers your questions. https://github.com/felipedferreira/ConsoleApp – UncleFifi Jul 29 '22 at 16:48
  • 1
    Important Note is that the appsettings.json needs to change the 'Copy to output options' to 'Copy Always'. Please advise if you need help understanding how this is done. – UncleFifi Jul 29 '22 at 16:51