Bagaimana cara mengakses Konfigurasi di semua kelas di ASP.NET Core?

127

Saya telah melalui dokumentasi konfigurasi pada inti ASP.NET. Dokumentasi mengatakan Anda dapat mengakses konfigurasi dari mana saja dalam aplikasi.

Di bawah ini adalah Startup.cs yang dibuat oleh 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();
    }
}

Jadi dalam Startup.cskami mengkonfigurasi semua pengaturan, Startup.cs juga memiliki properti bernamaConfiguration

Apa yang saya tidak dapat mengerti bagaimana Anda mengakses konfigurasi ini di pengontrol atau di mana pun dalam aplikasi? MS merekomendasikan untuk menggunakan pola opsi tetapi saya hanya memiliki 4-5 pasangan nilai kunci jadi saya tidak ingin menggunakan pola opsi. Saya hanya ingin memiliki akses ke Konfigurasi dalam aplikasi. Bagaimana cara menyuntikkannya di kelas mana pun?

LP13
sumber
1
Jika 4-5 pasangan nilai kunci maka Anda dapat memasukkan pengaturan individual tersebut. Saya akan merekomendasikan pendekatan itu atau pola opsi untuk tujuan pengujian. Ketiga metode (termasuk yang awalnya Anda tanyakan) terdaftar sebagai jawaban dalam kemungkinan pertanyaan duplikat berikut: stackoverflow.com/questions/30263681/…
stephen.vakil
Untuk mengakses konfigurasi sebagai kamus dari mana saja, periksa jawaban ini .
Amro
Lihat di sini untuk contoh kode lengkap.
Arghya C
Jika Anda datang ke sini karena kesulitan mengubah konfigurasi Framework ke konfigurasi CORE, jawaban ini untuk Anda stackoverflow.com/a/56498687/1704458
TS

Jawaban:

148

Memperbarui

Menggunakan ASP.NET Core 2.0 akan secara otomatis menambahkan IConfigurationinstance aplikasi Anda di wadah injeksi ketergantungan. Ini juga bekerja bersama dengan ConfigureAppConfigurationdi WebHostBuilder.

Sebagai contoh:

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

    host.Run();
}

Ini semudah menambahkan IConfigurationinstance ke koleksi layanan sebagai objek tunggal di ConfigureServices:

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

   // ...
}

Di mana Configurationcontoh di Startupkelas Anda .

Ini memungkinkan Anda untuk memasukkan IConfigurationpengontrol atau layanan apa pun:

public class HomeController
{
   public HomeController(IConfiguration configuration)
   {
      // Use IConfiguration instance
   }
}
Henk Mollema
sumber
4
Mollerna .... dan bagaimana jika Anda ingin memasukkan konfigurasi dalam proyek perpustakaan kelas terpisah dalam solusi? Mencoba seperti IConfiguration _configuration {get; set; } public DatabaseHelpers (konfigurasi IConfiguration) {_configuration = configuration; } tetapi _configuration selalu nol ... tidak pernah terkena kontstruktor
dinotom
2
Bisa dikatakan, lewat IConfigurationseperti itu sangat bocor. Jauh lebih baik menggunakan pola Opsi .
Marc L.
7
Bagaimana cara mengakses nilai dari "appsettings.json" secara langsung di kelas khusus? Tanpa melewatkan data dari pengontrol? Apa itu mungkin?
Tadej
2
@HenkMollema Bisakah Anda menambahkan contohnya di sini? Bagaimana saya menyuntikkannya ke kelas mana pun (dari mana?).
Tadej
5
@HenkMollema Pertanyaannya adalah bagaimana menyuntikkan ke dalam kelas apa pun ... bukan bagaimana menyuntikkan ke "kelas apa pun yang diselesaikan melalui injeksi ketergantungan". Saya pikir di situlah miskomunikasi ... kelasnya kemungkinan tidak dipanggil dari rantai yang dimulai dengan Pengontrol atau objek lain yang diselesaikan secara otomatis dengan proses DI otomatis.
BVernon
35

Cara yang benar untuk melakukannya:

Di .NET Core Anda dapat memasukkan IConfigurationsebagai parameter ke konstruktor Kelas Anda, dan itu akan tersedia.

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

Sekarang, ketika Anda ingin membuat sebuah instance dari kelas Anda, karena kelas Anda diinjeksi IConfiguration, Anda tidak akan dapat melakukannya begitu saja new MyClass(), karena ini membutuhkan IConfigurationparameter yang dimasukkan ke dalam konstruktor, jadi, Anda perlu memasukkan kelas Anda sebagai baik ke rantai injeksi, yang berarti dua langkah sederhana:

1) Tambah Kelas / es - di mana Anda ingin menggunakan IConfiguration, untuk IServiceCollectiondi ConfigureServices()metode dalamStartup.cs

services.AddTransient<MyClass>();

2) Definisikan sebuah instance - katakanlah di Controller, dan masukkan menggunakan konstruktor:

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

Sekarang Anda harus dapat menikmati _myClass.configuration...

Pilihan lain:

Jika Anda masih mencari cara untuk membuatnya tersedia tanpa harus memasukkan kelas ke dalam pengontrol, maka Anda dapat menyimpannya di static class, yang akan Anda konfigurasikan di Startup.cs, seperti:

public static class MyAppData
{
    public static IConfiguration Configuration;
}

Dan Startupkonstruktor Anda akan terlihat seperti ini:

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

Kemudian gunakan MyAppData.Configurationdi mana saja di program Anda.

Jangan tanyakan kepada saya mengapa opsi pertama adalah cara yang benar, saya hanya bisa melihat pengembang berpengalaman selalu menghindari data sampah di sepanjang jalan mereka, dan sangat dipahami bahwa bukan praktik terbaik untuk memiliki banyak data yang tersedia di memori setiap saat, juga tidak baik untuk kinerja dan atau untuk pengembangan, dan mungkin juga lebih aman untuk hanya membawa apa yang Anda butuhkan.

Mayer Spitzer
sumber
5
Semua penyuntikan file konfigurasi ini sepertinya tidak berguna / berantakan. TY untuk ide kelas konfigurasi statis.
Andrew
1
Pertanyaannya, tentu saja tentang mengakses konfigurasi di kelas mana pun dan bukan hanya pengontrol. Dan sementara dengan perkembangan baru layanan lean (layanan mikro), hal ini dapat dipertimbangkan, jika menyangkut migrasi, ini sangat menyakitkan. Inilah sebabnya mengapa Microsoft mendapatkan System.ConfigurationINTI kembali ke jalurnya. Sekarang, Anda dapat mengakses app.configs lama Anda seperti di masa lalu. Dan saya tidak berbicara tentang pengendali di sini. Kita membicarakan komponen yang memiliki konfigurasinya sendiri
TS
Ini memungkinkan akses di kelas apa pun dan tidak hanya di pengontrol, itu hanya perlu diimpor ke pengontrol untuk mendapatkan injeksi ketergantungan.
Mayer Spitzer
1
Metode mana pun yang berhasil, dan argumen untuk atau menentang masing-masing bersifat akademis menurut saya. Saya telah menggunakan keduanya untuk aplikasi yang berbeda ... sekarang, berkat opsi kedua Anda yang sangat mudah. Membuat kelas statis agak sulit menggunakan DI.
iGanja
Metode kedua juga membantu dengan masalah umum di .Net Core 2.0 - objek yang dibuat sebagai parameter POST (yaitu, secara otomatis dipisahkan dari JSON), di mana Anda tidak memiliki kesempatan untuk menyuntikkan ke konstruktor (setidaknya bukan tanpa banyak kode tambahan). Ini bekerja dengan baik untuk skenario itu
Joe Moon
30

Saya tahu ini sudah tua tetapi mengingat pola IOptions relatif sederhana untuk diterapkan:

  1. Kelas dengan properti get / set publik yang cocok dengan pengaturan dalam konfigurasi

    public class ApplicationSettings
    {
        public string UrlBasePath { get; set; }
    }
  2. daftarkan pengaturan Anda

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

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

Saya tidak yakin mengapa Anda tidak melakukan ini begitu saja.

ScottC
sumber
2
Bagaimana cara mengakses nilai dari "appsettings.json" secara langsung di kelas khusus?
Tadej
2
@JedatKinports Anda perlu menambahkan dependensi Nuget Microsoft.Extensions.Configuration, Microsoft.Extensions.Configuration.Binderdan Microsoft.Extensions.Configuration.Jsonkemudian Anda memuat appsettings.jsonfile seperti var config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();.. dan juga Anda harus memastikan appsettings.jsonsalin ke direktori output disetel kecopy always
LP13
7

Saya melakukannya seperti ini sekarang:

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

Dan kemudian saya menggunakan ini di mana saya perlu mendapatkan data dari file appsettings.json:

var appSettingsJson = AppSettingsJson.GetAppSettings();
// appSettingsJson["keyName"]
Tadej
sumber
Akhirnya sesuatu yang bekerja dalam metode statis tanpa tergantung pada kegilaan injektor. Kemerdekaan paradoks akhirnya! ; -) ... tapi terlalu banyak dependensi paket NuGet aaargh!
Louis Somers
7

Ada juga opsi untuk membuat configurationstatis di startup.cs sehingga apa yang bisa Anda akses di mana saja dengan mudah, variabel statis nyaman ya!

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

internal static IConfiguration Configuration { get; private set; }

Ini membuat konfigurasi dapat diakses di mana saja menggunakan Startup.Configuration.GetSection...Apa yang bisa salah?

konzo
sumber
3

Saya melihat ke contoh pola opsi dan melihat ini:

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

Saat menambahkan Iconfiguration di konstruktor kelas saya, saya dapat mengakses opsi konfigurasi melalui DI.

Contoh:

public class MyClass{

    private Iconfiguration _config;

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

    ... // access _config["myAppSetting"] anywhere in this class
}
Pieter Heemeryck
sumber
Apakah ini berfungsi tanpa secara eksplisit menyebutkan MyClass di Startup.cs, seperti ini? services.AddTransient <MyClass> ();
The Godfather
Ya, sebenarnya, Anda harus menyebutkan kelas yang ingin Anda masukkan di Startup.cs, bukan sebaliknya. Tapi IConfiguration menurut saya secara default sudah tersedia untuk inject.
Pieter Heemeryck
Ya, itu berhasil. Saya mencoba ini setelah membuat komentar dan implementasi konfigurasi disuntikkan ke IConfiguration. Terima kasih :)
The Godfather
1
@netfed Seperti yang dinyatakan Mayer Spitzer dalam jawabannya, tentu saja Anda perlu menambahkan MyClass ke startup dan menyuntikkannya ke mana pun Anda butuhkan, jadi Anda tidak perlu membuat instance baru dari MyClass sendiri, Anda menyuntikkannya di tempat yang Anda butuhkan.
Pieter Heemeryck
2

Saya tahu mungkin ada beberapa cara untuk melakukan ini, saya menggunakan Core 3.1 dan sedang mencari opsi optimal / bersih dan akhirnya saya melakukan ini:

  1. Kelas startup saya sebagai 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();
}
  1. Appsettings.json saya seperti ini
{
  "CompanySettings": {
    "name": "Fake Co"
  }
}
  1. Kelas saya adalah Pengontrol API, jadi pertama-tama saya menambahkan referensi penggunaan dan kemudian menyuntikkan antarmuka IConfiguration
using Microsoft.Extensions.Configuration;

public class EmployeeController 
{
    private IConfiguration _configuration;
    public EmployeeController(IConfiguration configuration)
    {
        _configuration = configuration;
    }
}
  1. Akhirnya saya menggunakan metode GetValue
public async Task<IActionResult> Post([FromBody] EmployeeModel form)
{
    var companyName = configuration.GetValue<string>("CompanySettings:name");
    // companyName = "Fake Co"
}
pengguna1058637
sumber
0

Pada 8-2017 Microsoft keluar dengan System.Configurationuntuk .NET CORE v4.4. Saat ini pratinjau v4.5 dan v4.6.

Bagi kita, yang mengerjakan transformasi dari .Net Framework ke CORE, ini penting. Ini memungkinkan untuk menyimpan dan menggunakan app.configfile saat ini , yang dapat diakses dari perakitan apa pun. Bahkan mungkin bisa menjadi alternatif appsettings.json, karena Microsoft menyadari kebutuhannya. Ini bekerja sama seperti sebelumnya di FW. Ada satu perbedaan:

Dalam aplikasi web, [mis. ASP.NET CORE WEB API] Anda perlu menggunakan app.configdan bukan web.config untuk appSettingsatau configurationSection. Anda mungkin perlu menggunakan web.configtetapi hanya jika Anda menyebarkan situs Anda melalui IIS. Anda menempatkan pengaturan khusus IIS keweb.config

Saya telah mengujinya dengan netstandard20 DLL dan Asp.net Core Web Api dan semuanya berfungsi.

TS
sumber
0

Menggunakan pola Opsi di ASP.NET Core adalah cara yang harus dilakukan. Saya hanya ingin menambahkan, jika Anda perlu mengakses opsi dalam startup.cs Anda , saya sarankan untuk melakukannya dengan cara ini:

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
sumber
jadi jika saya memiliki seluruh sub-bagian dengan selusin nilai konfigurasi yang perlu saya akses di ConfigureServices, maka saya perlu melakukannya untuk semuanya? Apakah tidak ada cara lain untuk melakukan ini melalui pola IOptions? Saya perlu menyuntikkan ini ke metode ekstensi statis tempat saya mengonfigurasi bus angkutan massal saya. Juga bagaimana dengan saran dari Microsoft ini tentang tidak menggunakan pola IOptions di ConfigureServices docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/…
kuldeep
Saya tidak menggunakan IOPtions di ConfigureService di sini ...
Martin Brandl
-3

Saya harus membaca parameter sendiri saat memulai.
Itu harus ada di sana sebelum WebHost dimulai (karena saya membutuhkan url / IP "untuk mendengarkan" dan port dari file parameter dan menerapkannya ke WebHost). Selanjutnya, saya membutuhkan pengaturan publik di seluruh aplikasi.

Setelah mencari beberapa saat (tidak ada contoh lengkap yang ditemukan, hanya cuplikan) dan setelah berbagai coba-coba, saya memutuskan untuk melakukannya dengan "cara lama" dengan file .ini sendiri.
Jadi .. jika Anda ingin menggunakan memiliki file .ini dan / atau mengatur "untuk mendengarkan url / IP" Anda sendiri dan / atau memerlukan pengaturan publik, ini untuk Anda ...

Contoh lengkap, valid untuk core 2.1 (mvc):

Buat file .ini - contoh:

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

dimana Dummyx hanya disertakan sebagai contoh untuk tipe tanggal lain selain string (dan juga untuk menguji kasus “salah param” (lihat kode di bawah).

Menambahkan file kode di root proyek, untuk menyimpan variabel global:

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

Mengubah kode di program.cs (sebelum 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

    }
}

Cara ini:

  • Konfigurasi Aplikasi saya dipisahkan dari appsettings.json dan saya tidak memiliki efek samping yang perlu ditakuti, jika MS memang berubah di versi mendatang ;-)
  • Saya memiliki pengaturan saya di variabel global
  • Saya dapat menyetel "untuk mendengarkan url" untuk setiap perangkat, aplikasi dijalankan (mesin dev saya, server intranet dan server internet)
  • Saya dapat menonaktifkan pengaturan, dengan cara lama (cukup setel * sebelumnya)
  • Saya dapat bereaksi, jika ada yang salah dalam file .ini (mis. Tipe mismatch)
    Jika - eg - tipe yang salah disetel (mis. * Dummy1 = gew7623 diaktifkan alih-alih Dummy1 = true) host menunjukkan warna merah informasi ada di konsol (termasuk pengecualian) dan saya dapat bereaksi juga dalam aplikasi (GV.bFehler_Ini ist disetel ke true, jika ada kesalahan dengan .ini)
FredyWenger
sumber