Wie greife ich in einer Klasse in ASP.NET Core auf die Konfiguration zu?

127

Ich habe durchgemacht Konfigurationsdokumentation zum ASP.NET-Kern . Die Dokumentation besagt, dass Sie von überall in der Anwendung auf die Konfiguration zugreifen können.

Unten ist Startup.cs von Vorlage erstellt

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

Also rein Startup.cs Konfiguration aller Einstellungen hat Startup.cs auch eine Eigenschaft mit dem NamenConfiguration

Was kann ich nicht verstehen, wie Sie auf diese Konfiguration im Controller oder irgendwo in der Anwendung zugreifen? MS empfiehlt die Verwendung eines Optionsmusters, aber ich habe nur 4-5 Schlüssel-Wert-Paare, daher möchte ich kein Optionsmuster verwenden. Ich wollte nur Zugriff auf die Konfiguration in der Anwendung haben. Wie spritze ich es in einer Klasse?

LP13
quelle
1
Wenn es sich um 4-5 Schlüsselwertpaare handelt, können Sie diese individuellen Einstellungen einfach einfügen. Ich würde diesen Ansatz oder das Optionsmuster aus Gründen der Testbarkeit empfehlen. Alle drei Methoden (einschließlich der, nach der Sie ursprünglich gefragt haben) werden als Antworten in der folgenden möglichen doppelten Frage aufgeführt: stackoverflow.com/questions/30263681/…
stephen.vakil
Überprüfen Sie diese Antwort , um von überall auf die Konfiguration als Wörterbuch zuzugreifen .
Amro
Überprüfen Sie hier für eine vollständige Codebeispiel.
Arghya C
Wenn Sie hierher kommen, weil Sie Probleme mit der Konvertierung der Framework-Konfiguration in die CORE-Konfiguration haben, ist diese Antwort für Sie stackoverflow.com/a/56498687/1704458
TS

Antworten:

147

Aktualisieren

Bei Verwendung von ASP.NET Core 2.0 wird die Instanz Ihrer Anwendung automatischIConfiguration zum Abhängigkeitsinjektionscontainer hinzugefügt . Dies funktioniert auch in Verbindung mit ConfigureAppConfigurationdemWebHostBuilder .

Beispielsweise:

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

    host.Run();
}

Es ist genauso einfach wie das Hinzufügen der IConfigurationInstanz zur Service-Sammlung als Singleton-Objekt in ConfigureServices:

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

   // ...
}

Wo Configurationist die Instanz in Ihrer StartupKlasse?

Auf diese Weise können Sie IConfigurationjeden Controller oder Service einspeisen :

public class HomeController
{
   public HomeController(IConfiguration configuration)
   {
      // Use IConfiguration instance
   }
}
Henk Mollema
quelle
4
Mollerna .... und wie wäre es, wenn Sie die Konfiguration in ein separates Klassenbibliotheksprojekt in die Lösung einfügen möchten? Versucht wie diese private statische IConfiguration _configuration {get; einstellen; } public DatabaseHelpers (IConfiguration-Konfiguration) {_configuration = configuration; } aber _configuration ist immer null ... es wird nie im Konstruktor getroffen
Dinotom
2
Das heißt, so herumzugeben IConfigurationist sehr undicht. Es ist weitaus besser, das Optionsmuster zu verwenden .
Marc L.
7
Wie kann ich direkt in einer benutzerdefinierten Klasse auf die Werte aus "appsettings.json" zugreifen? Ohne die Daten von einem Controller zu übergeben? Ist es möglich?
Tadej
2
@HenkMollema Könnten Sie hier ein Beispiel hinzufügen? Wie würde ich es einer Klasse injizieren (von wo?).
Tadej
5
@HenkMollema Die Frage war, wie man in eine Klasse injiziert ... nicht wie man in "eine Klasse injiziert, die durch Abhängigkeitsinjektion aufgelöst wurde". Ich denke, hier liegt die Fehlkommunikation ... seine Klasse wird wahrscheinlich nicht von einer Kette aufgerufen, die mit einem Controller oder einem anderen Objekt beginnt, das automatisch durch einen automatischen DI-Prozess aufgelöst wird.
BVernon
34

Der richtige Weg, es zu tun:

In .NET Core können Sie das IConfigurationals Parameter in Ihren Klassenkonstruktor einfügen, und es wird verfügbar sein.

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

Wenn Sie jetzt eine Instanz Ihrer Klasse erstellen möchten IConfiguration, können Sie dies nicht einfach tun , da Ihre Klasse injiziert wird new MyClass(), da ein IConfigurationParameter in den Konstruktor eingefügt werden muss. Daher müssen Sie Ihre Klasse als injizieren gut zur Injektionskette, was zwei einfache Schritte bedeutet:

1) Fügen Sie Ihre Klasse (n) hinzu - wo Sie die verwenden möchten IConfiguration, zu IServiceCollectionder ConfigureServices()Methode inStartup.cs

services.AddTransient<MyClass>();

2) Definieren Sie eine Instanz - sagen wir in der Controllerund injizieren Sie sie mit dem Konstruktor:

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

Jetzt sollten Sie in der Lage sein, Ihre _myClass.configurationfreien ...

Andere Option:

Wenn Sie immer noch nach einer Möglichkeit suchen, es verfügbar zu machen, ohne die Klassen in den Controller einfügen zu müssen, können Sie es in einer Datei speichern static class, die Sie in der folgenden Konfiguration konfigurieren Startup.cs:

public static class MyAppData
{
    public static IConfiguration Configuration;
}

Und Ihr StartupKonstruktor sollte so aussehen:

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

Verwenden Sie dann eine MyAppData.Configurationbeliebige Stelle in Ihrem Programm.

Konfrontieren Sie mich nicht, warum die erste Option der richtige ist. Ich kann nur sehen, dass erfahrene Entwickler auf ihrem Weg immer Mülldaten vermeiden, und es ist klar, dass es nicht die beste Vorgehensweise ist, ständig viele Daten im Speicher verfügbar zu haben. Weder ist es gut für die Leistung noch für die Entwicklung, und vielleicht ist es auch sicherer, nur das bei sich zu haben, was Sie brauchen.

Mayer Spitzer
quelle
5
Das ganze Einfügen von Konfigurationsdateien scheint irgendwie sinnlos / chaotisch. TY für die Idee der statischen Konfigurationsklasse.
Andrew
1
Die Frage war natürlich, auf die Konfiguration in jeder Klasse und nicht nur auf den Controller zuzugreifen. Und während bei der Neuentwicklung von Lean Services (Microservices) dies in Betracht gezogen werden kann, ist dies bei Migrationen ein großer Schmerz. Aus diesem Grund ist Microsoft System.Configurationfür CORE wieder auf Kurs gekommen. Jetzt können Sie wie in guten alten Zeiten auf Ihre guten alten app.configs zugreifen. Und ich spreche hier nicht von Controllern. Wir sprechen von Komponenten, die ihre eigenen Konfigurationen haben
TS
Es ermöglicht den Zugriff in jeder Klasse und nicht nur in der Steuerung, sondern muss nur in die Steuerung importiert werden, um die Abhängigkeitsinjektion zu erhalten.
Mayer Spitzer
1
Beide Methoden funktionieren, und die Argumente für oder gegen jede sind meiner Meinung nach akademisch. Ich habe beide für verschiedene Anwendungen verwendet ... jetzt dank Ihrer extrem einfachen zweiten Option. Das Erstellen einer statischen Klasse ist mit DI ziemlich schwierig.
iGanja
Die zweite Methode hilft auch bei einem häufigen Problem in .Net Core 2.0 - Objekten, die als POST-Parameter instanziiert werden (dh automatisch von JSON deserialisiert werden), bei denen Sie nicht die Möglichkeit haben, in den Konstruktor zu injizieren (zumindest nicht ohne viel von zusätzlichem Code). Dies funktioniert hervorragend für dieses Szenario
Joe Moon
30

Ich weiß, dass dies alt ist, aber angesichts der IOptions-Muster ist es relativ einfach zu implementieren:

  1. Klasse mit öffentlichen Eigenschaften zum Abrufen / Festlegen, die den Einstellungen in der Konfiguration entsprechen

    public class ApplicationSettings
    {
        public string UrlBasePath { get; set; }
    }
  2. Registrieren Sie Ihre Einstellungen

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

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

Ich bin mir nicht sicher, warum Sie das nicht einfach tun würden.

ScottC
quelle
2
Wie kann ich direkt in einer benutzerdefinierten Klasse auf die Werte aus "appsettings.json" zugreifen?
Tadej
2
@JedatKinports Sie müssen Nuget-Abhängigkeiten hinzufügen Microsoft.Extensions.Configuration, Microsoft.Extensions.Configuration.Binderund Microsoft.Extensions.Configuration.Jsondann laden Sie eine appsettings.jsonDatei wie .. und Sie müssen auch sicherstellen var config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();, dass die appsettings.jsonKopie in das Ausgabeverzeichnis aufcopy always
LP13
7

Es gibt auch eine Option, um configurationin startup.cs statisch zu machen, so dass statische Variablen praktisch sind, was Sie überall problemlos darauf zugreifen können.

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

internal static IConfiguration Configuration { get; private set; }

Dies macht die Konfiguration überall zugänglich. Startup.Configuration.GetSection...Was kann schief gehen?

Konzo
quelle
6

Ich mache es im Moment so:

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

Und dann verwende ich dies, wo ich die Daten aus der Datei appsettings.json abrufen muss:

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

Ich habe mir das Mustermuster für Optionen angesehen und Folgendes gesehen:

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

Beim Hinzufügen von Iconfiguration im Konstruktor meiner Klasse konnte ich über DI auf die Konfigurationsoptionen zugreifen.

Beispiel:

public class MyClass{

    private Iconfiguration _config;

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

    ... // access _config["myAppSetting"] anywhere in this class
}
Pieter Heemeryck
quelle
Funktioniert es, ohne MyClass in Startup.cs explizit zu erwähnen? services.AddTransient <MyClass> ();
Der Pate
Ja, eigentlich sollten Sie die Klassen erwähnen, die Sie in Startup.cs einfügen möchten, nicht umgekehrt. Aber IConfiguration ist meiner Meinung nach standardmäßig bereits zum Injizieren verfügbar.
Pieter Heemeryck
Ja es funktioniert. Ich habe dies versucht, nachdem ich den Kommentar abgegeben und die Konfigurationsimplementierung in IConfiguration eingefügt wurde. Trotzdem danke :)
Der Pate
1
@netfed Wie Mayer Spitzer in seiner Antwort feststellt, müssen Sie MyClass natürlich zum Start hinzufügen und überall dort einfügen, wo Sie es benötigen. Sie müssen also keine neue Instanz von MyClass selbst erstellen, sondern dort einfügen, wo Sie es benötigen.
Pieter Heemeryck
2

Ich weiß, dass es mehrere Möglichkeiten gibt, dies zu tun. Ich verwende Core 3.1 und habe nach der optimalen / saubereren Option gesucht. Am Ende habe ich Folgendes getan:

  1. Meine Startklasse ist standardmäßig
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. Meine appsettings.json ist so
{
  "CompanySettings": {
    "name": "Fake Co"
  }
}
  1. Meine Klasse ist ein API-Controller, daher habe ich zuerst die using-Referenz hinzugefügt und dann die IConfiguration-Schnittstelle eingefügt
using Microsoft.Extensions.Configuration;

public class EmployeeController 
{
    private IConfiguration _configuration;
    public EmployeeController(IConfiguration configuration)
    {
        _configuration = configuration;
    }
}
  1. Schließlich habe ich die GetValue-Methode verwendet
public async Task<IActionResult> Post([FromBody] EmployeeModel form)
{
    var companyName = configuration.GetValue<string>("CompanySettings:name");
    // companyName = "Fake Co"
}
user1058637
quelle
0

In den Jahren 8-2017 brachte Microsoft System.Configuration.NET CORE v4.4 heraus. Derzeit Vorschau auf v4.5 und v4.6.

Für diejenigen von uns, die an der Transformation von .Net Framework zu CORE arbeiten, ist dies von wesentlicher Bedeutung. Es ermöglicht das app.configSpeichern und Verwenden aktueller Dateien, auf die von jeder Baugruppe aus zugegriffen werden kann. Es kann wahrscheinlich sogar eine Alternative dazu sein appsettings.json, da Microsoft die Notwendigkeit dafür erkannt hat. Es funktioniert genauso wie zuvor in FW. Es gibt einen Unterschied:

In den Web - Anwendungen, [zB ASP.NET CORE WEB - API] Sie verwenden müssen app.configund nicht web.config für Ihre appSettingsoder configurationSection. Möglicherweise müssen Sie diese verwenden, web.configjedoch nur, wenn Sie Ihre Site über IIS bereitstellen. Sie platzieren IIS-spezifische Einstellungen inweb.config

Ich habe es mit netstandard20 DLL und Asp.net Core Web Api getestet und es funktioniert alles.

TS
quelle
0

Die Verwendung des Optionsmusters in ASP.NET Core ist der richtige Weg. Ich möchte nur hinzufügen, wenn Sie auf die Optionen in Ihrer startup.cs zugreifen müssen , empfehle ich, dies folgendermaßen zu tun:

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)];
}
Martin Brandl
quelle
Wenn ich also einen ganzen Unterabschnitt mit einem Dutzend Konfigurationswerten habe, auf die ich in ConfigureServices zugreifen muss, muss ich das für alle tun? Gibt es keine andere Möglichkeit, dies über das IOptions-Muster zu tun? Ich muss dies einer statischen Erweiterungsmethode hinzufügen, bei der ich meinen Nahverkehrsbus konfiguriere. Was ist auch mit diesem Vorschlag von Microsoft, das IOptions-Muster in ConfigureServices docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/…
kuldeep
Ich verwende hier keine IOPtions in ConfigureService ...
Martin Brandl
-3

Ich muss beim Start eigene Parameter lesen.
Das muss vorhanden sein, bevor der WebHost gestartet wird (da ich die URL / IP und den Port zum Abhören aus der Parameterdatei und zum Anwenden auf den WebHost benötige). Außerdem brauche ich die Einstellungen öffentlich in der gesamten Anwendung.

Nach einer Weile der Suche (kein vollständiges Beispiel gefunden, nur Schnipsel) und nach verschiedenen Versuchen und Fehlern habe ich mich entschlossen, es auf die "alte Art" mit einer eigenen INI-Datei zu machen.
Also ... wenn Sie Ihre verwenden möchten eigene INI-Datei und / oder setzen Sie die "zu hören URL / IP" Ihre eigene und / oder benötigen Sie die Einstellungen öffentlich, dies ist für Sie ...

Vollständiges Beispiel, gültig für Core 2.1 (mvc):

Erstellen Sie eine INI-Datei - Beispiel:

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

wobei die Dummyx nur als Beispiel für andere Datumstypen als Zeichenfolge enthalten sind (und auch um den Fall "falscher Parameter" zu testen (siehe Code unten).

Es wurde eine Codedatei im Stammverzeichnis des Projekts hinzugefügt, um die globalen Variablen zu speichern:

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

Der Code in program.cs wurde geändert (vor 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

    }
}

Diesen Weg:

  • Meine Anwendungskonfiguration ist von der Datei appsettings.json getrennt und ich habe keine Nebenwirkungen zu befürchten, wenn MS Änderungen in zukünftigen Versionen vornimmt ;-)
  • Ich habe meine Einstellungen in globalen Variablen
  • Ich kann die "Listen-URL" für jedes Gerät festlegen, auf dem die Anwendung ausgeführt wird (mein Entwicklungscomputer, der Intranetserver und der Internet-Server).
  • Ich kann die Einstellungen auf die alte Weise deaktivieren (einfach ein * vorher einstellen)
  • Ich kann reagieren, wenn in der INI-Datei etwas nicht stimmt (z. B. Typinkongruenz).
    Wenn z. B. ein falscher Typ festgelegt ist (z. B. wird * Dummy1 = gew7623 anstelle von Dummy1 = true aktiviert), wird der Host rot angezeigt Informationen befinden sich auf der Konsole (einschließlich der Ausnahme) und ich kann auch in der Anwendung reagieren (GV.bFehler_Ini wird auf true gesetzt, wenn Fehler mit der INI vorliegen).
FredyWenger
quelle