Come si accede alla configurazione in qualsiasi classe in ASP.NET Core?


127

Ho esaminato la documentazione di configurazione su ASP.NET core. La documentazione dice che puoi accedere alla configurazione da qualsiasi punto dell'applicazione.

Di seguito è riportato Startup.cs creato da modello

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();
    }
}

Quindi, Startup.csquando configuriamo tutte le impostazioni, Startup.cs ha anche una proprietà denominataConfiguration

Cosa non sono in grado di capire come si accede a questa configurazione nel controller o in qualsiasi punto dell'applicazione? MS consiglia di utilizzare il pattern delle opzioni, ma ho solo 4-5 coppie chiave-valore, quindi vorrei non utilizzare il pattern delle opzioni. Volevo solo avere accesso alla configurazione nell'applicazione. Come lo inietto in qualsiasi classe?


1
Se sono 4-5 coppie di valori chiave, puoi semplicemente iniettare quelle singole impostazioni. Consiglierei questo approccio o il modello di opzioni per scopi di testabilità. Tutti e tre i metodi (incluso quello di cui hai chiesto originariamente) sono elencati come risposte nella seguente possibile domanda duplicata: stackoverflow.com/questions/30263681/…
stephen.vakil

Per accedere alla configurazione come dizionario da qualsiasi luogo, controlla questa risposta .
Amro

Controlla qui per un esempio di codice completo.
Arghya C

Se vieni qui perché stai lottando con la conversione della configurazione Framework nella configurazione CORE, questa risposta è per te stackoverflow.com/a/56498687/1704458
TS

Risposte:


148

Aggiornare

L'uso di ASP.NET Core 2.0 aggiungerà automaticamente l' IConfigurationistanza dell'applicazione nel contenitore di inserimento delle dipendenze. Funziona anche in combinazione con ConfigureAppConfigurationsu WebHostBuilder.

Per esempio:

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

    host.Run();
}

È facile come aggiungere l' IConfigurationistanza alla raccolta di servizi come oggetto singleton in ConfigureServices:

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

   // ...
}

Dov'è Configurationl'istanza nella tua Startupclasse.

Ciò consente di iniettare IConfigurationin qualsiasi controller o servizio:

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

4
Mollerna .... e che ne dici se vuoi iniettare la configurazione in un progetto di libreria di classi separato nella soluzione? Ho provato in questo modo IConfiguration statico privato _configuration {get; impostato; } DatabaseHelpers pubblici (configurazione IConfiguration) {_configuration = configurazione; } ma _configuration è sempre nulla ... non viene mai colpito nel contstructor
dinotom

2
Detto questo, passando in giro IConfiguration quel modo è molto che perde. Molto meglio usare il modello Opzioni .
Marc L.

7
Come accedere ai valori da "appsettings.json" direttamente in una classe personalizzata? Senza passare i dati da un titolare del trattamento? È possibile?
Tadej

2
@HenkMollema Potresti aggiungere un esempio qui? Come lo inietterei a qualsiasi classe (da dove?).
Tadej

5
@HenkMollema La domanda era come iniettare in qualsiasi classe ... non come iniettare in "qualsiasi classe risolta tramite iniezione di dipendenza". Penso che sia qui che si trova il problema di comunicazione ... è probabile che la sua classe non venga chiamata da una catena che inizia con un controller o un altro oggetto risolto automaticamente dal processo DI automatico.
BVernon

35

Il modo giusto per farlo:

In .NET Core è possibile inserire IConfigurationcome parametro nel costruttore della classe e sarà disponibile.

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

Ora, quando vuoi creare un'istanza della tua classe, dal momento che la tua classe viene iniettata IConfiguration, non sarai in grado di farlo new MyClass(), perché ha bisogno di un IConfigurationparametro iniettato nel costruttore, quindi, dovrai iniettare la tua classe come bene alla catena di iniezione, il che significa due semplici passaggi:

1) Aggiungi le tue classi - dove vuoi usare il file IConfiguration , al IServiceCollectional ConfigureServices()metodoStartup.cs

services.AddTransient<MyClass>();

2) Definisci un'istanza - diciamo in Controller, e iniettala usando il costruttore:

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

Ora dovresti essere in grado di goderti _myClass.configurationliberamente il tuo ...

Un'altra opzione:

Se stai ancora cercando un modo per averlo disponibile senza dover iniettare le classi nel controller, puoi memorizzarlo in un static class , che configurerai in Startup.cs, qualcosa come:

public static class MyAppData
{
    public static IConfiguration Configuration;
}

E il tuo Startup costruttore dovrebbe assomigliare a questo:

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

Quindi usa MyAppData.Configuration ovunque nel tuo programma.

Non confrontarmi sul motivo per cui la prima opzione è la strada giusta, posso solo vedere sviluppatori esperti che evitano sempre i dati inutili lungo il loro percorso, ed è ben chiaro che non è la migliore pratica avere un sacco di dati disponibili in memoria tutto il tempo, né è un bene per le prestazioni né per lo sviluppo, e forse è anche più sicuro avere con te solo ciò di cui hai bisogno.


5
Tutta questa iniezione di file di configurazione sembra un po 'inutile / disordinato. TY per l'idea della classe di configurazione statica.
Andrew

1
La domanda, ovviamente, riguardava l'accesso alla configurazione in qualsiasi classe e non solo il controller. E mentre con il nuovo sviluppo di servizi snelli (microservizi) questo può essere pensato, quando si tratta di migrazioni, questo è un grosso problema. Questo è il motivo System.Configurationper cui Microsoft è tornato in pista per CORE. Ora puoi accedere al tuo buon vecchio app.configs proprio come ai bei vecchi tempi. E non sto parlando di controllori qui. Stiamo parlando di componenti che hanno le proprie configurazioni
TS

Consente l'accesso in qualsiasi classe e non solo nel controller, richiede solo di essere importato nel controller per ottenere l'inserimento delle dipendenze.
Mayer Spitzer,

1
Entrambi i metodi funzionano e gli argomenti a favore o contro ciascuno sono accademici secondo me. Li ho usati entrambi per diverse applicazioni ... ora, grazie alla tua seconda opzione estremamente facile. Creare una classe statica è piuttosto difficile utilizzando DI.
iGanja

Il secondo metodo aiuta anche con un problema comune in .Net Core 2.0: oggetti istanziati come parametro POST (cioè, deserializzati automaticamente da JSON), in cui non hai l'opportunità di iniettare nel costruttore (almeno non senza molto di codice extra). Funziona alla grande per quello scenario
Joe Moon il

30

So che questo è vecchio ma dati i pattern IOptions è relativamente semplice da implementare:

  1. Classe con proprietà get / set pubbliche che corrispondono alle impostazioni nella configurazione

    public class ApplicationSettings
    {
        public string UrlBasePath { get; set; }
    }
  2. registra le tue impostazioni

    public void ConfigureServices(IServiceCollection services)
    {
     ...
     services.Configure<ApplicationSettings>(Configuration.GetSection("ApplicationSettings"));
    ...
    }
  3. iniettare tramite IOptions

    public class HomeController
    {
       public HomeController(IOptions<ApplicationSettings> appSettings)
       { ...
        appSettings.Value.UrlBasePath
        ...
        // or better practice create a readonly private reference
        }
     }

Non sono sicuro del motivo per cui non lo faresti.



2
Come accedere ai valori da "appsettings.json" direttamente in una classe personalizzata?
Tadej

2
@JedatKinports è necessario aggiungere le dipendenze NuGet Microsoft.Extensions.Configuration, Microsoft.Extensions.Configuration.Bindere Microsoft.Extensions.Configuration.Jsone poi caricare appsettings.jsonil file come var config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();..e anche necessario assicurarsi appsettings.jsonuna copia alla directory di output è impostato sucopy always
LP13

7

Lo sto facendo in questo momento:

// 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;
        }
    }
}

E poi lo uso dove ho bisogno di ottenere i dati dal file appsettings.json:

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

Finalmente qualcosa che funziona in un metodo statico senza dipendere dalla follia dell'iniettore. Finalmente l'indipendenza paradossale! ; -) ... ma così tante dipendenze dei pacchetti NuGet aaargh!
Louis Somers

7

C'è anche un'opzione per rendere configurationstatico in startup.cs in modo che ciò a cui puoi accedervi ovunque con facilità, le variabili statiche siano convenienti eh!

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

internal static IConfiguration Configuration { get; private set; }

Ciò rende la configurazione accessibile ovunque utilizzando Startup.Configuration.GetSection...Cosa può andare storto?


3

Ho esaminato il campione di pattern delle opzioni e ho visto questo:

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;
    }
...
}

Quando aggiungo Iconfiguration nel costruttore della mia classe, potrei accedere alle opzioni di configurazione tramite DI.

Esempio:

public class MyClass{

    private Iconfiguration _config;

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

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

Funziona senza menzionare esplicitamente MyClass in Startup.cs, qualcosa del genere? services.AddTransient <MyClass> ();
The Godfather

Sì, in realtà, dovresti menzionare le classi che vuoi inserire in Startup.cs, non il contrario. Ma IConfiguration penso sia già disponibile per impostazione predefinita per l'iniezione.
Pieter Heemeryck

Sì funziona. Ho provato questo dopo aver effettuato il commento e l'implementazione della configurazione è stata inserita in IConfiguration. Grazie comunque :)
Il Padrino

1
@netfed Come afferma Mayer Spitzer nella sua risposta, ovviamente dovrai aggiungere MyClass all'avvio e iniettarlo ovunque ti serva, quindi non è necessario creare una nuova istanza di MyClass da solo, lo inietti dove ne hai bisogno.
Pieter Heemeryck

2

So che potrebbero esserci diversi modi per farlo, sto usando Core 3.1 e stavo cercando l'opzione ottimale / più pulita e ho finito per farlo:

  1. La mia classe di avvio è quella predefinita
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();
}
  1. Il mio appsettings.json è così
{
  "CompanySettings": {
    "name": "Fake Co"
  }
}
  1. La mia classe è un controller API, quindi prima ho aggiunto il riferimento using e poi ho inserito l'interfaccia IConfiguration
using Microsoft.Extensions.Configuration;

public class EmployeeController 
{
    private IConfiguration _configuration;
    public EmployeeController(IConfiguration configuration)
    {
        _configuration = configuration;
    }
}
  1. Infine ho utilizzato il metodo GetValue
public async Task<IActionResult> Post([FromBody] EmployeeModel form)
{
    var companyName = configuration.GetValue<string>("CompanySettings:name");
    // companyName = "Fake Co"
}

0

Nell'8-2017 Microsoft uscì con System.Configuration.NET CORE v4.4. Attualmente v4.5 e v4.6 anteprima.

Per quelli di noi che lavorano alla trasformazione da .Net Framework a CORE, questo è essenziale. Consente di mantenere e utilizzare i app.configfile correnti , a cui è possibile accedere da qualsiasi assembly. Probabilmente è anche un'alternativa a appsettings.json, dal momento che Microsoft ne ha capito la necessità. Funziona come prima in FW. C'è una differenza:

Nelle applicazioni web, [es. ASP.NET CORE WEB API] devi usare app.confige non web.config per il tuo appSettingso configurationSection. Potrebbe essere necessario utilizzarlo, web.configma solo se si distribuisce il sito tramite IIS. Inserisci le impostazioni specifiche di IIS inweb.config

L'ho testato con netstandard20 DLL e Asp.net Core Web Api e funziona tutto.


0

L'uso del modello Opzioni in ASP.NET Core è la strada da percorrere. Voglio solo aggiungere, se devi accedere alle opzioni all'interno del tuo startup.cs , ti consiglio di farlo in questo modo:

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)];
}

quindi se ho un'intera sottosezione con una dozzina di valori di configurazione a cui devo accedere in ConfigureServices, allora devo farlo per tutti loro? Non c'è un altro modo per farlo tramite il pattern IOptions? Devo iniettarlo in un metodo di estensione statico in cui sto configurando il mio autobus di trasporto di massa. Che dire anche di questo suggerimento di Microsoft sul non utilizzare il pattern IOptions in ConfigureServices docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/…
kuldeep

Non uso IOPtions in ConfigureService qui ...
Martin Brandl,

-3

Devo leggere i propri parametri all'avvio.
Deve essere presente prima che il WebHost venga avviato (poiché ho bisogno dell'URL / IP e della porta "per ascoltare" dal file dei parametri e applicarli al WebHost). Inoltre, ho bisogno delle impostazioni pubbliche nell'intera applicazione.

Dopo aver cercato per un po '(nessun esempio completo trovato, solo frammenti) e dopo vari tentativi ed errori, ho deciso di farlo alla "vecchia maniera" con un proprio file .ini.
Quindi .. se vuoi usare il tuo possedere il file .ini e / o impostare "per ascoltare l'URL / IP" il proprio e / o richiedere le impostazioni pubbliche, questo è per te ...

Esempio completo, valido per core 2.1 (mvc):

Crea un file .ini - esempio:

[Avvio]
URL = http://172.16.1.201:22222
[Parametro]
* Dummy1 = gew7623
Dummy1 = true
Dummy2 = 1

per cui i Dummyx sono inclusi solo come esempio per altri tipi di data oltre alla stringa (e anche per testare il caso "parametro errato" (vedi codice sotto).

Aggiunto un file di codice nella radice del progetto, per memorizzare le variabili globali:

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... 
}

Modificato il codice in program.cs (prima di 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

    }
}

Per di qua:

  • La configurazione della mia applicazione è separata da appsettings.json e non ho effetti collaterali da temere, se MS cambia nelle versioni future ;-)
  • Ho le mie impostazioni nelle variabili globali
  • Sono in grado di impostare l '"URL di ascolto" per ogni dispositivo, l'applicazione viene eseguita (la mia macchina di sviluppo, il server intranet e il server Internet)
  • Sono in grado di disattivare le impostazioni, alla vecchia maniera (basta impostare un * prima)
  • Sono in grado di reagire, se qualcosa non va nel file .ini (ad es. Tipo non corrispondente)
    Se - ad es. - è impostato un tipo sbagliato (ad es. * Dummy1 = gew7623 è attivato invece di Dummy1 = true) l'host mostra rosso le informazioni sono sulla console (inclusa l'eccezione) e sono in grado di reagire anche nell'applicazione (GV.bFehler_Ini è impostato su true, se ci sono errori con il .ini)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.