16

i have started a new RESTful project using .NET Core Framework.

I divided my solution in two parts: Framework (set of .NET standard libraries) and Web (RESTful project).

With Framework folder i provide some of library for furthers web project and into one of these i'd like to provide a Configuration class with the generic method T GetAppSetting<T>(string Key).

My question is: how can i get the access to the AppSettings.json file in .NET Standard?

I have found so many example about reading this file, but all these examples read the file into the web project and no-one do this into an extarnal library. I need it to have reusable code for Others project.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Lollo
  • 535
  • 2
  • 5
  • 18
  • 4
    Don't do that any more. Don't try to read the config from the *libraries* themselves. The config classes are a dependency that should be injected. Your assemblies should define the config classes *and* contain Configuration setup code to match them to settings (eg configurationBuilder.Configure()` but you should leave it to the main application to actually read them from its sources – Panagiotis Kanavos May 28 '18 at 09:13
  • Note that you're coupling your .NET Standard library to a .NET Core Web project, since you want to read a json file specific to those kind of projects. Usually you'd pass the configuration down to the library, not the other way around – BgrWorker May 28 '18 at 09:14
  • BTW app.config never worked on *assemblies*. The Settings defined default values and the schema for loading them from the application's app.config. You couldn't change the settings by modifying an assembly's app.config, you had to change the default values – Panagiotis Kanavos May 28 '18 at 09:14
  • @BgrWorker there is no coupling. In fact, the coupling is *removed*. The main app could be anything : the Microsoft.Extensions.Configuration, DI, Logging are all .NET Standard 2.0 assemblies that can be used in any runtime. I use them in my Full framework applications too – Panagiotis Kanavos May 28 '18 at 09:16
  • @PanagiotisKanavos I was referring to the question, not to your comment, which is in fact correct (I also upvoted it) – BgrWorker May 28 '18 at 09:20
  • @PanagiotisKanavos so i have to read the json configuration from my .net core project and then use DI to inject the configuration to my libraries? – Lollo May 28 '18 at 09:48

2 Answers2

21

As already mentioned in the comments, you really shouldn't do it. Inject a configured IOptions<MyOptions> using dependency injection instead.

However, you can still load a json file as configuration:

IConfiguration configuration = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory()) // Directory where the json files are located
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
    .Build();

// Use configuration as in every web project
var myOptions = configuration.GetSection("MyOptions").Get<MyOptions>();

Make sure to reference the Microsoft.Extensions.Configuration and Microsoft.Extensions.Configuration.Json packages. For more configuration options see the documentation.

Ahmed Mansour
  • 527
  • 5
  • 13
Bruno Zell
  • 7,761
  • 5
  • 38
  • 46
  • 2
    good solution, thanks! However i have understood why i shouldn't do it... :D – Lollo May 28 '18 at 15:01
  • 4
    In order to get this code to build I had to add 3 nuget packages: Microsoft.Extensions.Configuration, Microsoft.Extensions.Configuration.Binder, Microsoft.Extensions.Configuration.Json – goPlayerJuggler Jun 05 '20 at 10:09
  • In this scenario what if you also want to support `UserSecrets` as well? I tried that by adding `AddUserSecrets(Assembly.GetEntryAssembly())` but apparently it does not make any difference. Any ideas how to get this working in this context? – Thomas Purrer Feb 22 '22 at 17:24
  • **Update** from my side: This is working straight forward with `UserSecrets`. The order is important here! First call `AddJsonFile` *and then* `AddUserSecrets`. Found the answer here: [Calling AddUserSecrets() before AddJsonFile()](https://stackoverflow.com/a/53471931/4265355) – Thomas Purrer Feb 22 '22 at 20:28
  • This code doesn't work for .net standard 2.0 version. Not sure if it works in .net core. – Ashutosh Kumar May 23 '23 at 20:55
  • 1
    @goPlayerJuggler THANK YOU for explaining the additional packages required for this to work in .NET Standard. These are not mentioned in any of the documentation or any of the answers. There was no way to know this until I found your comment. It's extremely frustrating trying to utilize Microsoft libraries when they rarely tell you which additional libraries you'll need just to get their libraries to work, and they aren't included in any of the dependency lists. – Bryan Williams Jul 06 '23 at 15:24
2

I extended this scenario in order to manage also (optional) User Secrets (from package: Microsoft.Extensions.Configuration.UserSecrets):

IConfiguration configuration = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory()) // Directory where the json files are located
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
    .AddUserSecrets(Assembly.GetEntryAssembly(),optional:true);
    .Build();

The order of adding Json Files and User Secrets is important here. See Calling AddJsonFile and AddUserSecrets

I fully agree this is not the preferred way (instead use IOptions<> and Dependency Injection and let the application configure the library). But I am mentioning this because I was working on an (very old) library which was reading from app.config (xml). This library can't be configured from the application, instead the library does it directly (expecting values in app.config). This library is used for Full Framework, .NET Core and .NET5 (or newer) applications now. So I had to support appsettings.json as well. It was not really possible to adapt the library in a way so that the application can provide the necessary configuration values to the library. Because of that I added support for JSON to it (for the time being - maybe later on we can spend more effort to make it configureable from the application)

Finally I also support environments and my code looks like this:

var builder = new ConfigurationBuilder()
                      .SetBasePath(Directory.GetCurrentDirectory())
                      .AddJsonFile("appsettings.json", optional: true, reloadOnChange: false);
            
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
if (!string.IsNullOrEmpty(environment))
{
    builder = builder.AddJsonFile(string.Format("appsettings.{0}.json", environment), optional: true, reloadOnChange: false);
    if (string.Equals(environment, "Development", StringComparison.CurrentCultureIgnoreCase))
    {
        builder = builder.AddUserSecrets(Assembly.GetEntryAssembly(),optional:true);
    }
}

Note that I decided to manage User Secrets only for Development scope.