ASP.NET Core'da herhangi bir sınıfta Configuration'a nasıl erişirim?


128

İçinden gitmiş yapılandırma belgelerinde ASP.NET çekirdeğine. Belgeler, yapılandırmaya uygulamanın herhangi bir yerinden erişebileceğinizi söylüyor.

Şablon tarafından oluşturulan Startup.cs aşağıdadır

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

Dolayısıyla, Startup.cstüm ayarları yapılandırdığımızda, Startup.cs adlı bir özelliği de var.Configuration

Neyi anlayamıyorum bu yapılandırmaya denetleyicide veya uygulamanın herhangi bir yerinde nasıl erişirsiniz? MS seçenekler örüntüsünü kullanmanızı öneriyor ancak benim yalnızca 4-5 anahtar-değer çiftim var, bu yüzden seçenekler kalıbını kullanmak istemiyorum. Sadece uygulamada Yapılandırmaya erişmek istedim. Herhangi bir sınıfa nasıl enjekte edebilirim?


1
4-5 anahtar-değer çifti ise, o zaman bu bireysel ayarları enjekte edebilirsiniz. Test edilebilirlik amacıyla bu yaklaşımı veya seçenekler modelini tavsiye ederim. Üç yöntemin tümü (başlangıçta sorduğunuz yöntem dahil), aşağıdaki olası yinelenen soruda yanıtlar olarak listelenmiştir: stackoverflow.com/questions/30263681/…
stephen.vakil

Yapılandırmaya herhangi bir yerden sözlük olarak erişmek için bu yanıtı kontrol edin .
Amro

Tam kod örneği için burayı kontrol edin .
Arghya C

Buraya , Framework yapılandırmasını CORE yapılandırmasına dönüştürmekte zorlandığınız için geldiyseniz, bu yanıt tam size göre stackoverflow.com/a/56498687/1704458
TS

Yanıtlar:


148

Güncelleme

ASP.NET Core 2.0 kullanmak , uygulamanızın örneğini otomatik olarakIConfiguration bağımlılık ekleme kapsayıcısına ekler . Bu aynı zamanda ile birlikte çalışır ConfigureAppConfigurationüzerinde WebHostBuilder.

Örneğin:

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

    host.Run();
}

IConfigurationÖrneği hizmet koleksiyonuna eklemek, şunlarda bir singleton nesnesi kadar kolaydır ConfigureServices:

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

   // ...
}

Sınıfınızdaki Configurationörnek nerede Startup?

Bu, IConfigurationherhangi bir denetleyiciye veya hizmete enjekte etmenize olanak tanır :

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

4
Mollerna .... ve yapılandırmayı çözümdeki ayrı bir sınıf kitaplığı projesine enjekte etmeye ne dersiniz? Bu özel statik IConfiguration _configuration {get; Ayarlamak; } genel DatabaseHelpers (IConfiguration yapılandırması) {_configuration = configuration; } ancak _configuration her zaman geçersizdir ... yapıcıda asla
vurulmaz

2
Bununla birlikte, IConfigurationbu şekilde dolaşmak çok sızdırıcıdır. Seçenekler modelini kullanmak çok daha iyi .
Marc L.

7
"Appsettings.json" dosyasındaki değerlere doğrudan özel bir sınıfta nasıl erişilir? Verileri bir denetleyiciden geçirmeden mi? Mümkün mü?
Tadej

2
@HenkMollema Buraya bir örnek ekleyebilir misiniz? Herhangi bir sınıfa nasıl enjekte edebilirim (nereden?).
Tadej

5
@HenkMollema Soru, "bağımlılık ekleme yoluyla çözülen herhangi bir sınıfa" nasıl enjekte edileceği değil ... herhangi bir sınıfa nasıl enjekte edileceğiydi. Sanırım yanlış iletişimin olduğu yer burası ... onun sınıfı, bir Controller ile başlayan bir zincirden veya otomatik DI işlemiyle otomatik olarak çözülen başka bir nesneden çağrılmıyor olabilir.
BVernon

35

Bunu yapmanın doğru yolu:

.NET Core'da bunu IConfigurationSınıf yapıcınıza bir parametre olarak enjekte edebilirsiniz ve kullanılabilir olacaktır.

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

Şimdi, sınıfınızın bir örneğini oluşturmak istediğinizde, sınıfınız enjekte edildiğinden IConfiguration, bunu yapamazsınız new MyClass()çünkü yapıcıya bir IConfigurationparametre enjekte edilmesi gerekir, bu nedenle sınıfınızı şu şekilde enjekte etmeniz gerekir: Enjeksiyon zincirine iyi gelir, bu da iki basit adım anlamına gelir:

Kullanmak istediğiniz - 1) Sınıf / es Ekle IConfigurationiçin, IServiceCollectionen ConfigureServices()yöntemdeStartup.cs

services.AddTransient<MyClass>();

2) Bir örnek tanımlayın - diyelim Controllerve yapıcıyı kullanarak enjekte edelim :

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

Artık _myClass.configurationözgürce eğlenebilmelisin ...

Başka seçenek:

Sınıfları denetleyiciye enjekte etmek zorunda kalmadan hala kullanılabilir hale getirmenin bir yolunu arıyorsanız, o zaman bunu static class, içinde yapılandıracağınız, aşağıdaki Startup.csgibi bir a içinde saklayabilirsiniz :

public static class MyAppData
{
    public static IConfiguration Configuration;
}

Ve Startupkurucunuz şöyle görünmeli:

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

Ardından MyAppData.Configurationprogramınızın herhangi bir yerinde kullanın .

Neden ilk seçeneğin doğru yol olduğunu benimle yüzleşmeyin, deneyimli geliştiricilerin her zaman gereksiz verilerden kaçındığını görebiliyorum ve bellekte her zaman bol miktarda veriye sahip olmanın en iyi uygulama olmadığı anlaşılıyor. ne performans ne de geliştirme için iyi ve belki de sadece ihtiyacınız olana sahip olmak daha güvenlidir.


5
Tüm bu yapılandırma dosyalarının enjekte edilmesi biraz anlamsız / dağınık görünüyor. Statik yapılandırma sınıfı fikri için TY.
Andrew

1
Tabii ki soru, sadece denetleyicide değil, herhangi bir sınıfta konfigürasyona erişimle ilgiliydi. Yalın hizmetlerin (mikro hizmetler) yeni geliştirilmesiyle bu, taşıma söz konusu olduğunda büyük bir acı olarak düşünülebilir. Bu nedenle Microsoft, System.ConfigurationCORE'u tekrar yoluna aldı. Artık eski app.configs uygulamanıza aynı eski güzel günlerdeki gibi erişebilirsiniz. Ve burada denetleyicilerden bahsetmiyorum. Kendi yapılandırmalarına sahip bileşenlerden bahsediyoruz
TS

Sadece denetleyicide değil, herhangi bir sınıfta erişime izin verir, bağımlılık enjeksiyonu elde etmek için yalnızca denetleyiciye aktarılması gerekir.
Mayer Spitzer

1
Her iki yöntem de işe yarar ve her birinin lehine veya aleyhine olan argümanlar benim görüşüme göre akademiktir. Her ikisini de farklı uygulamalar için kullandım ... şimdi, son derece kolay ikinci seçeneğiniz sayesinde. DI kullanarak statik bir sınıf oluşturmak oldukça zordur.
iGanja

İkinci yöntem aynı zamanda .Net Core 2.0'daki ortak bir soruna da yardımcı olur - POST parametresi olarak örneklenen nesneler (yani, JSON'dan otomatik olarak serileştirilmiş), yapıcıya enjekte etme fırsatınız yoktur (en azından çok fazla olmadan) ekstra kod). Bu senaryo için harika çalışıyor
Joe Moon

30

Bunun eski olduğunu biliyorum, ancak IOptions modellerinin uygulanması nispeten basittir:

  1. Yapılandırmadaki ayarlarla eşleşen genel get / set özelliklerine sahip sınıf

    public class ApplicationSettings
    {
        public string UrlBasePath { get; set; }
    }
  2. ayarlarınızı kaydedin

    public void ConfigureServices(IServiceCollection services)
    {
     ...
     services.Configure<ApplicationSettings>(Configuration.GetSection("ApplicationSettings"));
    ...
    }
  3. IOptions aracılığıyla enjekte etmek

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

Bunu neden yapmadığından emin değilim.



2
"Appsettings.json" dosyasındaki değerlere doğrudan özel bir sınıfta nasıl erişilir?
Tadej

2
Eğer gerekmez @JedatKinports Nuget bağımlılıkları eklemek için Microsoft.Extensions.Configuration, Microsoft.Extensions.Configuration.Binderve Microsoft.Extensions.Configuration.Jsonsonra yüklemek appsettings.jsongibi dosya var config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();..ve de emin olmak zorunda appsettings.jsonayarlandığında çıkış dizine kopyacopy always
LP13

7

Bunu şu anda böyle yapıyorum:

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

Ve sonra bunu appsettings.json dosyasından verileri almam gereken yerde kullanıyorum:

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

Son olarak, enjektör çılgınlığına bağlı kalmadan statik bir yöntemde çalışan bir şey. Sonunda paradoksal bağımsızlık! ; -) ... ama çok fazla NuGet paket bağımlılığı aaargh!
Louis Somers

7

Ayrıca configurationstartup.cs dosyasında statik hale getirme seçeneği vardır, böylece her yerden kolaylıkla erişebilirsiniz, statik değişkenler uygundur huh!

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

internal static IConfiguration Configuration { get; private set; }

Bu, Yapılandırmayı Startup.Configuration.GetSection...Neler ters gidebilir?


3

Seçenekler modeli örneğine baktım ve şunu gördüm:

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

Sınıfımın kurucusuna Iconfiguration eklerken, DI aracılığıyla konfigürasyon seçeneklerine erişebildim.

Misal:

public class MyClass{

    private Iconfiguration _config;

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

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

Startup.cs içinde MyClass'tan açıkça bahsetmeden çalışıyor mu, bunun gibi bir şey? services.AddTransient <MyClass> ();
The Godfather

Evet, aslında Startup.cs içinde enjekte etmek istediğiniz sınıflardan bahsetmelisiniz, tersi değil. Ama IConfiguration sanırım varsayılan olarak zaten enjekte edilebilir.
Pieter Heemeryck

Evet çalışıyor. Bunu yorum yaptıktan sonra denedim ve yapılandırma uygulaması IConfiguration'a enjekte edildi. Yine de teşekkürler :)
The Godfather

1
@netfed Mayer Spitzer'in cevabında belirttiği gibi, tabii ki MyClass'ı startup'a eklemeniz ve ihtiyacınız olan her yere enjekte etmeniz gerekecek, böylece MyClass'ın yeni bir örneğini kendiniz oluşturmanıza gerek kalmaz, onu ihtiyacınız olan yere enjekte edersiniz.
Pieter Heemeryck

2

Bunu yapmanın birkaç yolu olabileceğini biliyorum, Core 3.1 kullanıyorum ve en uygun / temiz seçeneği arıyordum ve bunu yaptım:

  1. Başlangıç ​​sınıfım varsayılan olarak
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. Appsettings.json böyledir
{
  "CompanySettings": {
    "name": "Fake Co"
  }
}
  1. Sınıfım bir API Denetleyicisi, bu yüzden önce kullanım referansını ekledim ve ardından IConfiguration arayüzünü enjekte ettim
using Microsoft.Extensions.Configuration;

public class EmployeeController 
{
    private IConfiguration _configuration;
    public EmployeeController(IConfiguration configuration)
    {
        _configuration = configuration;
    }
}
  1. Son olarak GetValue yöntemini kullandım
public async Task<IActionResult> Post([FromBody] EmployeeModel form)
{
    var companyName = configuration.GetValue<string>("CompanySettings:name");
    // companyName = "Fake Co"
}

0

8-2017'de Microsoft System.Configuration, .NET CORE v4.4 için çıktı . Şu anda v4.5 ve v4.6 önizlemesi.

.Net Framework'ten CORE'a dönüşüm üzerinde çalışan bizler için bu çok önemlidir. app.configHerhangi bir derlemeden erişilebilen mevcut dosyaları saklamaya ve kullanmaya izin verir . Muhtemelen bunun bir alternatifi olabilir appsettings.json, çünkü Microsoft buna olan ihtiyacı fark etti. FW'de eskisi gibi çalışır. Bir fark var:

Web uygulamalarında, [mesela ASP.NET CORE WEB API] Kullanmak gerek app.configve yok senin için web.config appSettingsveya configurationSection. Kullanmanız gerekebilir, web.configancak yalnızca sitenizi IIS aracılığıyla dağıtıyorsanız. IIS'ye özgü ayarlarıweb.config

Netstandard20 DLL ve Asp.net Core Web Api ile test ettim ve hepsi çalışıyor.


0

ASP.NET Core'da Options modelini kullanmak gitmenin yoludur. Eklemek istiyorum , startup.cs içindeki seçeneklere erişmeniz gerekiyorsa , bunu şu şekilde yapmanızı tavsiye ederim:

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

Yani, ConfigureServices'te erişmem gereken bir düzine yapılandırma değerine sahip bütün bir alt bölüme sahipsem, hepsini hepsi için yapmam gerekir mi? Bunu IOptions kalıbı ile yapmanın başka bir yolu yok mu? Bunu, toplu taşıma veri yolumu yapılandırdığım bir statik genişletme yöntemine eklemem gerekiyor. Ayrıca Microsoft'un ConfigureServices docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/…
kuldeep

Burada ConfigureService'de IOPtions kullanmıyorum ...
Martin Brandl

-3

Başlangıçta kendi parametrelerini okumam gerekiyor.
Bunun WebHost başlatılmadan önce orada olması gerekir (çünkü parametre dosyasından url / IP'yi ve bağlantı noktasını "dinlemek" ve WebHost'a uygulamak gerekir). Ayrıca, tüm uygulamada herkese açık olan ayarlara ihtiyacım var .

Bir süre aradıktan sonra (tam bir örnek bulunmadı, yalnızca snippet'ler) ve çeşitli deneme yanılma işlemlerinden sonra, bunu kendi .ini dosyasıyla "eski yöntemle" yapmaya karar verdim.
Yani .. .ini dosyasına sahip olun ve / veya "url / IP dinleme" yi kendiniz ayarlayın ve / veya ayarların herkese açık olması gerekir, bu sizin için ...

Tam örnek, çekirdek 2.1 (mvc) için geçerlidir:

Bir .ini dosyası oluşturun - örnek:

[Başlangıç]
URL = http://172.16.1.201:22222
[Parametre]
* Dummy1 = gew7623
Dummy1 = true
Dummy2 = 1

burada Dummyx yalnızca dizeden başka tarih türleri için örnek olarak dahil edilir (ve ayrıca "yanlış param" durumunu test etmek için (aşağıdaki koda bakın).

Global değişkenleri depolamak için projenin köküne bir kod dosyası eklendi:

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

Program.cs'deki kodu değiştirdi (CreateWebHostBuilder () öncesinde):

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

    }
}

Bu yoldan:

  • Uygulama yapılandırmam, appsettings.json'dan ayrı ve MS'in gelecek sürümlerde değişiklik yapmasından korkmam gereken hiçbir yan etki yok ;-)
  • Ayarlarım global değişkenlerde var
  • Her cihaz için "url dinlemek" ayarlayabiliyorum, uygulama çalışıyor (geliştirici makinem, intranet sunucusu ve internet sunucusu)
  • Ayarları devre dışı bırakabiliyorum, eski yöntem (önceden bir * belirleyin)
  • .İni dosyasında
    bir sorun varsa (ör. Tür uyuşmazlığı) tepki verebilirim Eğer - örneğin - yanlış bir tür ayarlanmışsa (örneğin, * Dummy1 = gew7623 Dummy1 = true yerine etkinleştirilirse) ana bilgisayar kırmızıyı gösterir bilgiler konsolda (istisna dahil) ve uygulamada da tepki verebiliyorum (.ini ile ilgili hatalar varsa GV.bFehler_Ini ist true olarak ayarlanmış)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.