63

I am trying to access appsetting.json file from a class library. So far the solution that I found is to create a configuration class implementing interface IConfiguration from Microsoft.Extensions.Configuration and add the json file to class and read from the same.

var configuration = new Configuration();
configuration.AddJsonFile("appsetting.json");
var connectionString= configuration.Get("connectionString");

This seems to be bad option as we have to add the json file each time we have to access the appsetting configuration. Dont we have any alternative like ConfigurationManager in ASP.NET.

Stephen Kennedy
  • 20,585
  • 22
  • 95
  • 108
cpr43
  • 2,942
  • 1
  • 18
  • 18
  • 1
    Possible duplicate of [Using IConfiguration in C# Class Library](https://stackoverflow.com/questions/27880433/using-iconfiguration-in-c-sharp-class-library) – William Ardila Dec 05 '17 at 02:34
  • 1
    Is the same issue that [Using IConfiguration in C# Class Library](https://stackoverflow.com/q/27880433/1647238), see [my answer](https://stackoverflow.com/a/47645131/1647238) – William Ardila Dec 05 '17 at 02:35
  • 1
    For those who simply looking to migrate to CORE from Framework, this is more suitable https://stackoverflow.com/a/56498687/1704458 – T.S. Jun 07 '19 at 17:36

7 Answers7

66

I know an answer has already been accepted, but this questions is a top hit on Google and OPs question is about class libraries and not an ASP.NET Web App or a WebApi which is what the accepted answer uses.

IMO, class libraries should not use application settings and should be agnostic to such settings. If you need application settings in your class library, then you should provide those settings from your consumer. You can see an example of this On This SO Question

Community
  • 1
  • 1
Stephen P.
  • 2,221
  • 2
  • 15
  • 16
  • 10
    I partially agree; for **test projects** that are setup as class libraries in a dotnet core solution, it is perfectly acceptable to use or embed appsettings. In this case, the test project e.g. class library _is_ the consumer of course. – Juliën Dec 29 '16 at 15:31
  • @Moriarty True, but in some cases you may also have multiple environments that your test suite may be executed in. In this case, embedded settings would not work (e.g. You have integration testing which needs to know what environment to talk to an API). I don't think it's always true one way or another and is always case by case. – Stephen P. Jan 11 '17 at 21:05
  • 3
    Of course class libraries should use connection string pointing to a local db instance. Whereas that setting is overwritten by the CI system to use another instance. IMHO THIS answer has not yet a solution. Its not about asp.net core its about .NET CORE reading an appsettings! – Pascal Feb 26 '18 at 21:02
  • 6
    @StephenPorter I disagree. In a highly compartmentalized ecosystem where each DLL might utilizes configurable features the main consumer has no idea what is going on down in layers. For example, imaging assembly can be configured to utilize different imaging providers. Thankfully, Microsoft introduced `System.Configuration` back to CORE, which supports `app.config` files. This is especially essential for those who migrates projects from framework to core – T.S. Jun 07 '19 at 17:29
  • I agree with @StephenPorter, if you have a data layer that needs to be completely abstracted from the other components, a way to reference the connection string outside of the compiled code is essential. – Tyson Gibby Dec 13 '21 at 18:04
  • @T.S. I'm not sure you're actually disagreeing with me here. You basically agree with my statement, you just seem to disagree on whether to use the options pattern vs pulling configs straight from an app.config using System.Configuration. If you're arguing that a library absolutely has to have some sort of configuration exist in order to work... you most likely have a poor design; however, there can be cases where it makes sense as nothing in software development is universal :) – Stephen P. Dec 14 '21 at 22:44
  • 1
    @StephenP. you said - *"IMO, class libraries should not use application settings"*. Looks like even Microsoft is disagreed with this postulate. Because you take `Entity Framework` as example an it has bunch of stuff in the `.config` and EF is a class library. So, I don't know. May be you had a different meaning? – T.S. Dec 15 '21 at 17:41
  • @T.S. I think you may have a misunderstanding of what I'm saying. Some libraries may have their own configurations that configure specifically how they operate, but something that is particular to your own application (application settings) should not go into a library you're building for it. The EF team didn't build in configuration values for your specific project into EF for you and your project right? You still provide those values for your project when you configure your EF setup. Again, we agree... you just prefer to provide your application settings a different way, which is fine. – Stephen P. Dec 20 '21 at 21:00
  • 1
    I have been building .net apps commercially since its inception and will say, there definitely ARE cases, especially in building large scale re-usable components, when you want to develop class libraries that are self contained with their own unique config settings (e.g. so they can be shared between multiple client apps) and not rely on any external startup process, etc. Answering the wrong question has just turned into 'Im not going to admit I got it wrong' exercise. – Mark Worrall May 05 '22 at 15:15
44

I'm assuming you want to access the appsettings.json file from the web application since class libraries don't have an appsettings.json by default.

I create a model class that has properties that match the settings in a section in appsettings.json.

Section in appsettings.json

"ApplicationSettings": {
    "SmtpHost": "mydomain.smtp.com",
    "EmailRecipients": "me@mydomain.com;other@mydomain.com"
}   

Matching model class

namespace MyApp.Models
{
    public class AppSettingsModel
    {
        public string SmtpHost { get; set; }
        public string EmailRecipients { get; set; }
    }
}

Then populate that model class and add it to the IOptions collection in the DI container (this is done in the Configure() method of the Startup class).

services.Configure<AppSettingsModel>(Configuration.GetSection("ApplicationSettings"));

// Other configuration stuff

services.AddOptions();

Then you can access that class from any method that the framework calls by adding it as a parameter in the constructor. The framework handles finding and providing the class to the constructor.

public class MyController: Controller
{
    private IOptions<AppSettingsModel> settings;

    public MyController(IOptions<AppSettingsModel> settings)
    {
        this.settings = settings;
    }
}

Then when a method in a class library needs the settings, I either pass the settings individually or pass the entire object.

Stephen P.
  • 2,221
  • 2
  • 15
  • 16
Clint B
  • 4,610
  • 2
  • 18
  • 22
  • 2
    Not sure if something has changed since this was accepted as an answer, but it didn't work for me when I started a new project two days ago. The changes I made to get it working were: Instead of IOptions settings;, I had to change it to AppSettingsModel settings; Then in controller constructor, I changed this line this.settings = settings; to this.settings = settings.Value; Then it started working. – Syed Mar 16 '17 at 09:57
  • 1
    If you aren't getting intelliscense on `settings`, there are a couple things that have to be changed in the above example. Refer to this microsoft document: [here](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration?tabs=basicconfiguration) – Post Impatica Oct 04 '17 at 17:42
  • 37
    Original poster asked how to access the config from a class library, not from an ASP.Net MVC controller. – Joe Irby Dec 22 '18 at 14:46
  • 1
    This should not be the accepted answer, as it answers a different question and so misleading. The question clearly states 'from a class library' – Mark Worrall May 05 '22 at 15:07
28

Besides the questions has an accepted answer, I believe that there is no one that applies to just a class library without having Startup projects or having dependencies with Asp.NetCore stack or IServiceCollection.

This is how I achieved to read the config from a class library:

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

public class ConfigSample
{
    public ConfigSample
    {
            IConfigurationBuilder builder = new ConfigurationBuilder();
            builder.AddJsonFile(Path.Combine(Directory.GetCurrentDirectory(), "appsettings.json"));

            var root = builder.Build();
            var sampleConnectionString = root.GetConnectionString("your-connection-string");
    }
}

The following nuget packages are required:

  • Microsoft.Extensions.Configuration
  • Microsoft.Extensions.Configuration.FileExtensions
  • Microsoft.Extensions.FileProviders.Abstractions
  • Newtonsoft.Json
  • Microsoft.Extensions.Configuration.Json
Community
  • 1
  • 1
  • 1
    How does this solution take into account the environment the application is using? For example if I publish the application with "Production"-environment, the code should read appsettings.Production.json instead of appsettings.json. – Esko Sep 07 '22 at 08:41
  • @Esko exactly... have you found a solution? – Gianni B. Jul 14 '23 at 13:57
9

I know that the question has an accepted answer but the question is about class libraries and the way to read appsettings.json from a classlibrary is the following:

Create a model that has the properties that will match those in your settings file:

public class ConfigurationManager
{
    public string BaseUrl { get; set; }
}

Add the actual settings in your appsettings.json

  "ConfigurationManager": {
    "BaseUrl": "myValue"
  }

Now register the appsettings.json section with your model in startup.cs:

 services.Configure<ConfigurationManager>(Configuration.GetSection("ConfigurationManager"));

In your class library create a class that is using

using Microsoft.Extensions.Options;

And get your configuration settings :

using Microsoft.Extensions.Options;


public class KeyUrls: IKeyUrls
{
    public string BaseUrl = "";
    private readonly IOptions<ConfigurationManager> _configurationService;

    public KeyUrls(IOptions<ConfigurationManager> configurationservice)
    {
        _configurationService = configurationservice;
        BaseUrl = _configurationService.Value.BaseUrl;
    }

    public  string GetAllKeyTypes()
    {
        return $"{BaseUrl}/something";
    }

    public  string GetFilteredKeys()
    {
        return $"{BaseUrl}/something2";
    }
}

For further details check This

ThunD3eR
  • 3,216
  • 5
  • 50
  • 94
  • It may be too late to ask a question on this but I think I have a similar scenario as above. Assuming your KeyUrls class is in some another project and your services.Configure code is in some another project. How do call your GetAllKeyTypes method ? If using IKeyUrls obj= new KeyUrls(); is the one then do you get the configuration values in construction. As I am facing compile time error on this for all the obvious reasons. – Aditya Pewekar Jan 13 '20 at 18:10
8

It's easy to do that

string c = Directory.GetCurrentDirectory();
IConfigurationRoot configuration = 
newConfigurationBuilder().SetBasePath(c).AddJsonFile("appsettings.json").Build();
string connectionStringIs = configuration.GetConnectionString("MyConnection"); 

From the last line you can get connection string

if you want to configure the context, write the extra following code:

optionsBuilder.UseSqlServer(connectionStringIs); //inside protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)

don't forget to install and use these packages:-

using Microsoft.Extensions.Configuration; 
using Microsoft.Extensions.Configuration.FileExtensions; 
using Newtonsoft.Json; 
using Microsoft.Extensions.Configuration.Json; 
using System.IO;
Ahmed Mohammed
  • 126
  • 1
  • 3
1

Works in class constructor DI. Microsoft Docs Here

  • 4
    Welcome to StackOverflow. Can you provide more details? Perhaps a code snippet and explanation? Check out the help center section for tips on answering questions https://stackoverflow.com/help/answering – Noel Apr 16 '20 at 15:53
-1
Directory.SetCurrentDirectory(AppContext.BaseDirectory);
var builder = new ConfigurationBuilder().SetBasePath (  Path.Combine(Directory.GetCurrentDirectory())   )
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
Roman Pokrovskij
  • 9,449
  • 21
  • 87
  • 142
Sanaj
  • 1
  • 4
    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-ask). – Community Sep 14 '21 at 17:52