18

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.

6
  • 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<MySettingsClas>()` but you should leave it to the main application to actually read them from its sources Commented May 28, 2018 at 9: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 Commented May 28, 2018 at 9: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 Commented May 28, 2018 at 9: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 Commented May 28, 2018 at 9:16
  • @PanagiotisKanavos I was referring to the question, not to your comment, which is in fact correct (I also upvoted it) Commented May 28, 2018 at 9:20

2 Answers 2

22

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.

Sign up to request clarification or add additional context in comments.

6 Comments

good solution, thanks! However i have understood why i shouldn't do it... :D
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
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?
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()
@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.
|
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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.