Jak uzyskać dostęp do konfiguracji w dowolnej klasie w ASP.NET Core?


127

Przejrzałem dokumentację konfiguracji dotyczącą ASP.NET core. Dokumentacja mówi, że możesz uzyskać dostęp do konfiguracji z dowolnego miejsca w aplikacji.

Poniżej znajduje się plik Startup.cs utworzony przez szablon

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

Więc Startup.cskonfigurujemy wszystkie ustawienia, Startup.cs ma również właściwość o nazwieConfiguration

Czego nie jestem w stanie zrozumieć, jak uzyskujesz dostęp do tej konfiguracji w kontrolerze lub w dowolnym miejscu w aplikacji? MS zaleca użycie wzorca opcji, ale mam tylko 4-5 par klucz-wartość, więc nie chciałbym używać wzorca opcji. Chciałem tylko mieć dostęp do konfiguracji w aplikacji. Jak wstrzyknąć to w dowolnej klasie?


1
Jeśli jest to 4-5 par kluczowych wartości, możesz po prostu wstrzyknąć te indywidualne ustawienia. Poleciłbym to podejście lub wzorzec opcji do celów testowalności. Wszystkie trzy metody (w tym ta, o którą pierwotnie pytałeś) są wymienione jako odpowiedzi w następującym możliwym zduplikowanym pytaniu: stackoverflow.com/questions/30263681/…
— stephen.vakil

Aby uzyskać dostęp do konfiguracji jako słownika z dowolnego miejsca, zaznacz tę odpowiedź .
— Amro

Sprawdź tutaj pełny przykład kodu.
— Arghya C

Jeśli przyjeżdżasz tutaj, ponieważ nie możesz się doczekać konwersji konfiguracji Framework do konfiguracji CORE, ta odpowiedź jest dla Ciebie stackoverflow.com/a/56498687/1704458
— TS,

Odpowiedzi:


148

Aktualizacja

Użycie ASP.NET Core 2.0 spowoduje automatyczne dodanie IConfigurationwystąpienia aplikacji w kontenerze iniekcji zależności. Działa to również w połączeniu z ConfigureAppConfigurationnaWebHostBuilder .

Na przykład:

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

    host.Run();
}

Jest to tak proste, jak dodanie IConfigurationinstancji do kolekcji usług jako pojedynczego obiektu w ConfigureServices:

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

   // ...
}

Gdzie Configurationjest instancja w twojej Startupklasie.

Pozwala to na wprowadzenie IConfigurationdowolnego kontrolera lub usługi:

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

4
Mollerna… a co powiesz na to, że chcesz wstrzyknąć konfigurację w oddzielnym projekcie biblioteki klas w rozwiązaniu? Próbowałem tak jak ta prywatna statyczna IConfiguration _configuration {get; zestaw; } public DatabaseHelpers (konfiguracja IConfiguration) {_configuration = configuration; } ale _configuration jest zawsze zerowa ... nigdy nie zostanie trafiona w konstruktor
— dinotom

2
To powiedziawszy, przechodzenie w IConfigurationten sposób jest bardzo nieszczelne. O wiele lepiej jest użyć wzorca Options .
— Marc L.

7
Jak uzyskać dostęp do wartości z „appsettings.json” bezpośrednio w niestandardowej klasie? Bez przekazywania danych od administratora? Czy to możliwe?
— Tadej

2
@HenkMollema Czy możesz dodać tutaj przykład? Jak bym wstrzyknął to do dowolnej klasy (skąd?).
— Tadej

5
@HenkMollema Pytanie brzmiało, jak wstrzyknąć do dowolnej klasy ... a nie jak wstrzyknąć do „dowolnej klasy rozwiązanej przez wstrzykiwanie zależności”. Myślę, że to jest błąd w komunikacji ... jego klasa prawdopodobnie nie jest wywoływana z łańcucha, który zaczyna się od kontrolera lub innego obiektu rozwiązanego automatycznie przez automatyczny proces DI.
— BVernon

34

Właściwy sposób, aby to zrobić:

W .NET Core możesz wstrzyknąć IConfigurationparametr jako parametr do konstruktora klasy i będzie on dostępny.

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

Teraz, gdy chcesz utworzyć instancję swojej klasy, ponieważ twoja klasa zostanie wstrzyknięta IConfiguration, nie będziesz w stanie tego zrobić new MyClass(), ponieważ wymaga ona IConfigurationparametru wstrzykniętego do konstruktora, więc będziesz musiał wstrzyknąć swoją klasę jako dobrze do łańcucha wtrysku, co oznacza dwa proste kroki:

1) Dodaj swoje klasy (klasy) - gdzie chcesz użyć IConfiguration, do metody IServiceCollectionat ConfigureServices()wStartup.cs

services.AddTransient<MyClass>();

2) Zdefiniuj instancję - powiedzmy w Controller, i wstrzyknij ją za pomocą konstruktora:

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

Teraz powinieneś móc _myClass.configurationswobodnie cieszyć się ...

Inna opcja:

Jeśli nadal szukasz sposobu na udostępnienie go bez konieczności wstrzykiwania klas do kontrolera, możesz zapisać go w pliku static class, który skonfigurujesz wStartup.cs , coś takiego:

public static class MyAppData
{
    public static IConfiguration Configuration;
}

Twój Startupkonstruktor powinien wyglądać tak:

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

Następnie użyj MyAppData.Configuration dowolnego miejsca w programie.

Nie konfrontuj mnie, dlaczego pierwsza opcja jest właściwa, widzę tylko, że doświadczeni programiści zawsze unikają danych śmieciowych po drodze i dobrze rozumiemy, że nie jest najlepszą praktyką, aby mieć mnóstwo danych dostępnych w pamięci przez cały czas, nie jest to również dobre dla wydajności ani dla rozwoju, a być może bezpieczniej jest mieć tylko to, czego potrzebujesz.


5
Całe to wstrzykiwanie plików konfiguracyjnych wydaje się bezcelowe / nieporządne. TY dla koncepcji statycznej klasy konfiguracji.
— Andrew,

1
Pytanie oczywiście dotyczyło dostępu do konfiguracji w dowolnej klasie, a nie tylko kontrolera. I chociaż można pomyśleć o nowym rozwoju usług lean (mikrousług), w przypadku migracji jest to duży ból. Dlatego firma Microsoft System.Configurationwróciła do CORE. Teraz możesz uzyskać dostęp do starych, dobrych app.configs, tak jak za dawnych dobrych czasów. I nie mówię tutaj o kontrolerach. Mówimy o komponentach, które mają własne konfiguracje
— TS,

Umożliwia dostęp w dowolnej klasie, a nie tylko w kontrolerze, wymaga po prostu zaimportowania do kontrolera w celu uzyskania iniekcji zależności.
— Mayer Spitzer

1
Obie metody działają, a argumenty za lub przeciw każdej z nich są moim zdaniem akademickie. Używałem obu do różnych zastosowań ... teraz, dzięki twojej niezwykle łatwej drugiej opcji. Tworzenie klasy statycznej jest dość trudne przy użyciu DI.
— iGanja

Druga metoda pomaga również w przypadku typowego problemu w .Net Core 2.0 - obiektów tworzonych jako parametr POST (tj. Automatycznie deserializowanych z JSON), gdzie nie masz możliwości wstrzyknięcia do konstruktora (przynajmniej nie bez dodatkowego kodu). To świetnie sprawdza się w tym scenariuszu
— Joe Moon

30

Wiem, że to jest stare, ale biorąc pod uwagę wzorce IOptions, jest stosunkowo proste do zaimplementowania:

  1. Klasa z publicznymi właściwościami get / set, które pasują do ustawień w konfiguracji

    public class ApplicationSettings
    {
        public string UrlBasePath { get; set; }
    }
  2. zarejestruj swoje ustawienia

    public void ConfigureServices(IServiceCollection services)
    {
     ...
     services.Configure<ApplicationSettings>(Configuration.GetSection("ApplicationSettings"));
    ...
    }
  3. wstrzyknąć przez IOptions

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

Nie jestem pewien, dlaczego po prostu tego nie zrobiłeś.



2
Jak uzyskać dostęp do wartości z „appsettings.json” bezpośrednio w niestandardowej klasie?
— Tadej

2
@JedatKinports musisz dodać zależności Nuget Microsoft.Extensions.Configuration, Microsoft.Extensions.Configuration.Bindera Microsoft.Extensions.Configuration.Jsonnastępnie załadować appsettings.jsonplik taki jak ... a var config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();także upewnić się, że appsettings.jsonkopiowanie do katalogu wyjściowego jest ustawione nacopy always
— LP13

7

Istnieje również opcja configurationstatyczna w pliku startup.cs, dzięki czemu zmienne statyczne są wygodne, jeśli masz do nich łatwy dostęp, hę!

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

internal static IConfiguration Configuration { get; private set; }

Dzięki temu konfiguracja jest dostępna w dowolnym miejscu przy użyciu Startup.Configuration.GetSection...Co może pójść nie tak?


6

W tej chwili robię to tak:

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

A potem używam tego, gdzie muszę pobrać dane z pliku appsettings.json:

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

3

Zajrzałem do próbki wzoru opcji i zobaczyłem to:

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

Dodając Iconfiguration w konstruktorze mojej klasy, mogłem uzyskać dostęp do opcji konfiguracyjnych przez DI.

Przykład:

public class MyClass{

    private Iconfiguration _config;

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

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

Czy to działa bez wyraźnego wspominania o MyClass w Startup.cs, coś takiego? services.AddTransient <MyClass> ();
— Ojciec chrzestny

Tak, właściwie powinieneś wspomnieć o klasach, które chcesz wstrzyknąć w Startup.cs, a nie na odwrót. Ale IConfiguration jest, jak sądzę, domyślnie już dostępny do wstrzyknięcia.
— Pieter Heemeryck

Tak to działa. Próbowałem tego po skomentowaniu, a implementacja konfiguracji została wstrzyknięta w IConfiguration. Dzięki tak czy siak :)
— Ojciec chrzestny

1
@netfed Jak stwierdza Mayer Spitzer w swojej odpowiedzi, oczywiście będziesz musiał dodać MyClass do uruchamiania i wstrzyknąć go tam, gdzie potrzebujesz, więc nie musisz samodzielnie tworzyć nowej instancji MyClass, wstrzykujesz ją tam, gdzie jej potrzebujesz.
— Pieter Heemeryck

2

Wiem, że może być na to kilka sposobów, używam Core 3.1 i szukałem optymalnej / czystszej opcji i skończyło się na tym:

  1. Moja klasa startowa jest domyślnie
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. Mój plik appsettings.json wygląda tak
{
  "CompanySettings": {
    "name": "Fake Co"
  }
}
  1. Moja klasa jest kontrolerem API, więc najpierw dodałem odwołanie using, a następnie wstrzyknąłem interfejs IConfiguration
using Microsoft.Extensions.Configuration;

public class EmployeeController 
{
    private IConfiguration _configuration;
    public EmployeeController(IConfiguration configuration)
    {
        _configuration = configuration;
    }
}
  1. Wreszcie użyłem metody GetValue
public async Task<IActionResult> Post([FromBody] EmployeeModel form)
{
    var companyName = configuration.GetValue<string>("CompanySettings:name");
    // companyName = "Fake Co"
}

0

W 8-2017 Microsoft wypuścił System.Configurationdla .NET CORE v4.4. Obecnie wersja zapoznawcza wersji 4.5 i 4.6 .

Dla tych z nas, którzy pracują nad transformacją z .Net Framework do CORE, jest to niezbędne. Umożliwia przechowywanie i używanie aktualnych app.configplików, do których można uzyskać dostęp z dowolnego zestawu. Prawdopodobnie może to być nawet alternatywa dlaappsettings.json , ponieważ Microsoft zdał sobie sprawę z takiej potrzeby. Działa tak samo jak wcześniej w FW. Jest jedna różnica:

W aplikacjach internetowych [np. ASP.NET CORE WEB API] musisz używać, app.configa nie web.config dla swojego appSettingslub configurationSection. Może być konieczne użycie, web.configale tylko w przypadku wdrażania witryny za pośrednictwem usług IIS. Umieszczasz ustawienia specyficzne dla usług IIS w programieweb.config

Przetestowałem to z netstandard20 DLL i Asp.net Core Web Api i wszystko działa.


0

Najlepszym sposobem jest użycie wzorca opcji w ASP.NET Core . Chcę tylko dodać, jeśli potrzebujesz dostępu do opcji w swoim startup.cs , polecam zrobić to w ten sposób:

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

więc jeśli mam całą podsekcję z kilkunastoma wartościami konfiguracyjnymi, do których potrzebuję dostępu w ConfigureServices, muszę to zrobić dla nich wszystkich? Czy nie ma innego sposobu, aby to zrobić za pomocą wzorca IOptions? Muszę wstrzyknąć to do statycznej metody rozszerzenia, w której konfiguruję mój autobus komunikacji zbiorowej. A co z sugestią firmy Microsoft dotyczącą niestosowania wzorca IOptions w programie ConfigureServices docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/ ...
— kuldeep

Nie używam IOPtions w ConfigureService tutaj ...
— Martin Brandl

-3

Muszę odczytać własne parametry przy starcie.
To musi być tam przed uruchomieniem WebHost (ponieważ potrzebuję adresu URL / IP „do nasłuchiwania” i portu z pliku parametrów i zastosowania go do hosta WebHost). Ponadto potrzebuję ustawień publicznych w całej aplikacji.

Po dłuższym wyszukiwaniu (nie znaleziono pełnego przykładu, tylko fragmenty) i po różnych próbach i błędach, zdecydowałem się zrobić to w „stary sposób” z własnym plikiem .ini.
Więc ... jeśli chcesz użyć swojego mieć własny plik .ini i / lub ustaw "do nasłuchiwania url / IP" swoje własne i / lub potrzebujesz publicznych ustawień, to jest dla ciebie ...

Kompletny przykład, ważny dla rdzenia 2.1 (MVC):

Utwórz plik .ini - przykład:

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

przy czym Dummyx są uwzględniane tylko jako przykład dla innych typów dat niż string (a także do testowania przypadku „zły parametr” (patrz kod poniżej).

Dodano plik kodu w katalogu głównym projektu do przechowywania zmiennych globalnych:

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

Zmieniono kod w program.cs (przed 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

    }
}

Tą drogą:

  • Moja konfiguracja aplikacji jest oddzielona od pliku appsettings.json i nie mam żadnych skutków ubocznych, których należy się obawiać, jeśli MS wprowadzi zmiany w przyszłych wersjach ;-)
  • Mam swoje ustawienia w zmiennych globalnych
  • Jestem w stanie ustawić „adres URL do nasłuchiwania” dla każdego urządzenia, na którym działa aplikacja (moja maszyna deweloperska, serwer intranetowy i serwer internetowy)
  • Jestem w stanie dezaktywować ustawienia, stary sposób (po prostu ustaw * przed)
  • Jestem w stanie zareagować, jeśli coś jest nie tak w pliku .ini (np.
    Niezgodność typów) Jeśli - np. - ustawiony jest niewłaściwy typ (np. * Dummy1 = gew7623 jest aktywowany zamiast Dummy1 = true) host wyświetla kolor czerwony informacje są na konsoli (w tym wyjątek) i mogę zareagować również w aplikacji (GV.bFehler_Ini jest ustawione na true, jeśli wystąpią błędy z .ini)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.