ChatGPT解决这个技术问题 Extra ChatGPT

How do I access Configuration in any class in ASP.NET Core?

I have gone through configuration documentation on ASP.NET core. Documentation says you can access configuration from anywhere in the application.

Below is Startup.cs created by template

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

        if (env.IsEnvironment("Development"))
        {
            // This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
            builder.AddApplicationInsightsSettings(developerMode: true);
        }

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

    public IConfigurationRoot Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container
    public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        services.AddApplicationInsightsTelemetry(Configuration);

        services.AddMvc();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        app.UseApplicationInsightsRequestTelemetry();

        app.UseApplicationInsightsExceptionTelemetry();

        app.UseMvc();
    }
}

So in Startup.cs we configure all the settings, Startup.cs also has a property named Configuration

What I'm not able to understand how do you access this configuration in controller or anywhere in the application? MS is recommending to use options pattern but I have only 4-5 key-value pairs so I would like not to use options pattern. I just wanted to have access to Configuration in application. How do I inject it in any class?

If it's 4-5 key value pairs then you can just inject those individual settings. I'd recommend that approach or the options pattern for testability purposes. All three methods (including the one you originally asked about) are listed as answers in the following possible duplicate question: stackoverflow.com/questions/30263681/…

H
Henk Mollema

Update

Using ASP.NET Core 2.0 will automatically add the IConfiguration instance of your application in the dependency injection container. This also works in conjunction with ConfigureAppConfiguration on the WebHostBuilder.

For example:

public static void Main(string[] args)
{
    var host = WebHost.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration(builder =>
        {
            builder.AddIniFile("foo.ini");
        })
        .UseStartup<Startup>()
        .Build();

    host.Run();
}

It's just as easy as adding the IConfiguration instance to the service collection as a singleton object in ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
   services.AddSingleton<IConfiguration>(Configuration);

   // ...
}

Where Configuration is the instance in your Startup class.

This allows you to inject IConfiguration in any controller or service:

public class HomeController
{
   public HomeController(IConfiguration configuration)
   {
      // Use IConfiguration instance
   }
}

Mollerna....and how about if you want to inject the configuration in a separate class library project in the solution? Tried like this private static IConfiguration _configuration { get; set; } public DatabaseHelpers(IConfiguration configuration) { _configuration = configuration; } but _configuration is always null...it never gets hit in the contstructor
That said, passing around IConfiguration like that is very leaky. Far better to use the Options pattern.
How to access the values from the "appsettings.json" directly in a custom class? Without passing the data from a controller? Is it possible?
@HenkMollema Could you add an example of it here? How would I inject it to any class (from where?).
@HenkMollema The question was how to inject into any class... not how to inject into "any class resolved via dependency injection". I think that's where the miscommunication is... his class is likely not being called from a chain that starts with a Controller or other object resolved automatically by automatic DI process.
B
Bernoulli IT

The right way to do it:

In .NET Core you can inject the IConfiguration as a parameter into your Class constructor, and it will be available.

public class MyClass 
{
    private IConfiguration configuration;
    public MyClass(IConfiguration configuration)
    {
        ConnectionString = new configuration.GetValue<string>("ConnectionString");
    }

Now, when you want to create an instance of your class, since your class gets injected the IConfiguration, you won't be able to just do new MyClass(), because it needs a IConfiguration parameter injected into the constructor, so, you will need to inject your class as well to the injecting chain, which means two simple steps:

1) Add your Class/es - where you want to use the IConfiguration, to the IServiceCollection at the ConfigureServices() method in Startup.cs

services.AddTransient<MyClass>();

2) Define an instance - let's say in the Controller, and inject it using the constructor:

public class MyController : ControllerBase
{
    private MyClass _myClass;
    public MyController(MyClass myClass)
    {
        _myClass = myClass;
    }

Now you should be able to enjoy your _myClass.configuration freely...

Another option:

If you are still looking for a way to have it available without having to inject the classes into the controller, then you can store it in a static class, which you will configure in the Startup.cs, something like:

public static class MyAppData
{
    public static IConfiguration Configuration;
}

And your Startup constructor should look like this:

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

Then use MyAppData.Configuration anywhere in your program.

Don't confront me why the first option is the right way, I can just see experienced developers always avoid garbage data along their way, and it's well understood that it's not the best practice to have loads of data available in memory all the time, neither is it good for performance and nor for development, and perhaps it's also more secure to only have with you what you need.


All this injecting of configuration files seems kinda pointless/messy. TY for the static configuration class idea.
The question, of course was about accessing configuration in any class and not just controller. And while with new development of lean services (microservices) this can be thought of, when it comes to migrations, this is big pain. This is why microsoft got System.Configuration for CORE back on track. Now, you can access your good old app.configs just like in good old times. And I am not talking controllers here. We're talking components that have their own configs
It allows access in any class and not just in the controller, it just requires to be imported into the controller in order to gain dependency injection.
Either method works, and the arguments for or against each are academic in my opinion. I have used both for different applications...now, thanks to your extremely easy second option. Creating a static class is rather difficult using DI.
The second method also helps with a common issue in .Net Core 2.0 - objects instantiated as a POST parameter (i.e., automatically deserialized from JSON), where you don't have the opportunity to inject into the constructor (at least not without a lot of extra code). This works great for that scenario
S
ScottC

I know this is old but given the IOptions patterns is relatively simple to implement:

Class with public get/set properties that match the settings in the configuration public class ApplicationSettings { public string UrlBasePath { get; set; } } register your settings public void ConfigureServices(IServiceCollection services) { ... services.Configure(Configuration.GetSection("ApplicationSettings")); ... } inject via IOptions public class HomeController { public HomeController(IOptions appSettings) { ... appSettings.Value.UrlBasePath ... // or better practice create a readonly private reference } }

I'm not sure why you wouldn't just do this.


How to access the values from the "appsettings.json" directly in a custom class?
@JedatKinports you need to add Nuget dependencies Microsoft.Extensions.Configuration, Microsoft.Extensions.Configuration.Binder and Microsoft.Extensions.Configuration.Json and then you load appsettings.json file like var config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();..and also you have to make sure appsettings.json copy to output directory is set to copy always
in your example. How can I use some DI class which also use ApplicationSettings in ApplicationSettings.cs?
k
konzo

There is also an option to make configuration static in startup.cs so that what you can access it anywhere with ease, static variables are convenient huh!

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

internal static IConfiguration Configuration { get; private set; }

This makes configuration accessible anywhere using Startup.Configuration.GetSection... What can go wrong?


This is by far the most simple one.
Yes, I like it. If anyone sees drawback, please share.
T
Tadej

I'm doing it like this at the moment:

// Requires NuGet package Microsoft.Extensions.Configuration.Json

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

namespace ImagesToMssql.AppsettingsJson
{
    public static class AppSettingsJson
    {           
        public static IConfigurationRoot GetAppSettings()
        {
            string applicationExeDirectory = ApplicationExeDirectory();

            var builder = new ConfigurationBuilder()
            .SetBasePath(applicationExeDirectory)
            .AddJsonFile("appsettings.json");

            return builder.Build();
        }

        private static string ApplicationExeDirectory()
        {
            var location = System.Reflection.Assembly.GetExecutingAssembly().Location;
            var appRoot = Path.GetDirectoryName(location);

            return appRoot;
        }
    }
}

And then I use this where I need to get the data from the appsettings.json file:

var appSettingsJson = AppSettingsJson.GetAppSettings();
// appSettingsJson["keyName"]

Finally something that works in a static method without depending on injector madness. Paradoxical independence at last! ;-)... but sooo many NuGet packacge dependencies aaargh!
Worth mentioning to add both Microsoft.Extensions.Configuration and Microsoft.Extensions.Configuration.Json to that code work.
Does this method mean you have to sacrifice the possibility of using appsettings.Development.json to automatically override values in appsettings.json at development time?
u
user1058637

I know there may be several ways to do this, I'm using Core 3.1 and was looking for the optimal/cleaner option and I ended up doing this:

My startup class is as default

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

public IConfiguration Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
}

My appsettings.json is like this

{
  "CompanySettings": {
    "name": "Fake Co"
  }
}

My class is an API Controller, so first I added the using reference and then injected the IConfiguration interface

using Microsoft.Extensions.Configuration;

public class EmployeeController 
{
    private IConfiguration _configuration;
    public EmployeeController(IConfiguration configuration)
    {
        _configuration = configuration;
    }
}

Finally I used the GetValue method

public async Task<IActionResult> Post([FromBody] EmployeeModel form)
{
    var companyName = configuration.GetValue<string>("CompanySettings:name");
    // companyName = "Fake Co"
}

We need to access it class library which is separate project. This is controller.
P
Pieter Heemeryck

I looked into the options pattern sample and saw this:

public class Startup
{
    public Startup(IConfiguration config)
    {
        // Configuration from appsettings.json has already been loaded by
        // CreateDefaultBuilder on WebHost in Program.cs. Use DI to load
        // the configuration into the Configuration property.
        Configuration = config;
    }
...
}

When adding Iconfiguration in the constructor of my class, I could access the configuration options through DI.

Example:

public class MyClass{

    private Iconfiguration _config;

    public MyClass(Iconfiguration config){
        _config = config;
    }

    ... // access _config["myAppSetting"] anywhere in this class
}

Does it work without explicitly mentioning MyClass in Startup.cs, something like this? services.AddTransient();
Yes, actually, you should mention the classes you want to inject in Startup.cs, not the other way around. But IConfiguration is I think by default already available to inject.
Yes, it works. I tried this after making the comment and config implementation was injected in IConfiguration. Thanks anyways :)
@netfed As Mayer Spitzer states in his answer, of course you will need to add MyClass to startup and inject it to wherever you need, so you do not need to create a new instance of MyClass yourself, you inject it where you need it.
T
T.S.

In 8-2017 Microsoft came out with System.Configuration for .NET CORE v4.4. Currently v4.5 and v4.6 preview.

For those of us, who works on transformation from .Net Framework to CORE, this is essential. It allows to keep and use current app.config files, which can be accessed from any assembly. It is probably even can be an alternative to appsettings.json, since Microsoft realized the need for it. It works same as before in FW. There is one difference:

In the web applications, [e.g. ASP.NET CORE WEB API] you need to use app.config and not web.config for your appSettings or configurationSection. You might need to use web.config but only if you deploying your site via IIS. You place IIS-specific settings into web.config

I've tested it with netstandard20 DLL and Asp.net Core Web Api and it is all working.


M
Martin Brandl

Using the Options pattern in ASP.NET Core is the way to go. I just want to add, if you need to access the options within your startup.cs, I recommend to do it this way:

CosmosDbOptions.cs:

public class CosmosDbOptions
{
    public string ConnectionString { get; set; }
}

Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    // This is how you can access the Connection String:
    var connectionString = Configuration.GetSection(nameof(CosmosDbOptions))[nameof(CosmosDbOptions.ConnectionString)];
}

so if i have like a whole subsection with a dozen config values that i need to access in ConfigureServices then I need to do it for all of them ? Is there not any other way to do this via IOptions pattern ? I need to inject this to a static extension method where i am configuring my mass transit bus. Also what about this suggestion from Microsoft about not using IOptions pattern in ConfigureServices docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/…
F
FredyWenger

I have to read own parameters by startup. That has to be there before the WebHost is started (as I need the “to listen” url/IP and port from the parameter file and apply it to the WebHost). Further, I need the settings public in the whole application.

After searching for a while (no complete example found, only snippets) and after various try-and-error's, I have decided to do it the “old way" with an own .ini file. So.. if you want to use your own .ini file and/or set the "to listen url/IP" your own and/or need the settings public, this is for you...

Complete example, valid for core 2.1 (mvc):

Create an .ini-file - example:

[Startup] URL=http://172.16.1.201:22222 [Parameter] *Dummy1=gew7623 Dummy1=true Dummy2=1

whereby the Dummyx are only included as example for other date types than string (and also to test the case “wrong param” (see code below).

Added a code file in the root of the project, to store the global variables:

namespace MatrixGuide
{
    public static class GV
    {
        // In this class all gobals are defined

        static string _cURL;
        public static string cURL // URL (IP + Port) on that the application has to listen
        {
            get { return _cURL; }
            set { _cURL = value; }
        }

        static bool _bdummy1;
        public static bool bdummy1 // 
        {
            get { return _bdummy1; }
            set { _bdummy1 = value; }
        }

        static int _idummy1;
        public static int idummy1 // 
        {
            get { return _idummy1; }
            set { _idummy1 = value; }
        }

        static bool _bFehler_Ini;
        public static bool bFehler_Ini // 
        {
            get { return _bFehler_Ini; }
            set { _bFehler_Ini = value; }
        }

        // add further  GV variables here..
    }
    // Add further classes here... 
}

Changed the code in program.cs (before CreateWebHostBuilder()):

namespace MatrixGuide
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // Read .ini file and overtake the contend in globale
            // Do it in an try-catch to be able to react to errors
            GV.bFehler_Ini = false;
            try
            {
                var iniconfig = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddIniFile("matrixGuide.ini", optional: false, reloadOnChange: true)
                .Build();
                string cURL = iniconfig.GetValue<string>("Startup:URL");
                bool bdummy1 = iniconfig.GetValue<bool>("Parameter:Dummy1");
                int idummy2 = iniconfig.GetValue<int>("Parameter:Dummy2");
                //
                GV.cURL = cURL;
                GV.bdummy1 = bdummy1;
                GV.idummy1 = idummy2;
            }
            catch (Exception e)
            {
                GV.bFehler_Ini = true;
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("!! Fehler beim Lesen von MatrixGuide.ini !!");
                Console.WriteLine("Message:" + e.Message);
                if (!(e.InnerException != null))
                {
                    Console.WriteLine("InnerException: " + e.InnerException.ToString());
                }

                Console.ForegroundColor = ConsoleColor.White;
            }
            // End .ini file processing
            //
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>() //;
            .UseUrls(GV.cURL, "http://localhost:5000"); // set the to use URL from .ini -> no impact to IISExpress

    }
}

This way:

My Application config is separated from the appsettings.json and I have no sideeffects to fear, if MS does changes in future versions ;-)

I have my settings in global variables

I am able to set the "to listen url" for each device, the applicaton run's on (my dev machine, the intranet server and the internet server)

I'm able to deactivate settings, the old way (just set a * before)

I'm able to react, if something is wrong in the .ini file (e.g. type mismatch) If - e.g. - a wrong type is set (e.g. the *Dummy1=gew7623 is activated instead of the Dummy1=true) the host shows red information's on the console (including the exception) and I' able to react also in the application (GV.bFehler_Ini ist set to true, if there are errors with the .ini)