Bagikan melalui


Konfigurasi di .NET

Konfigurasi di .NET dilakukan menggunakan satu atau beberapa penyedia konfigurasi . Penyedia konfigurasi membaca data konfigurasi dari pasangan kunci-nilai menggunakan berbagai sumber konfigurasi:

  • File pengaturan, seperti appsettings.json
  • Variabel lingkungan
  • Azure Key Vault
  • Azure App Configuration
  • Argumen baris perintah
  • Penyedia kustom (diinstal atau dibuat)
  • File direktori
  • Objek .NET dalam memori
  • Penyedia pihak ketiga

Nota

Untuk informasi tentang mengonfigurasi runtime .NET itu sendiri, lihat pengaturan konfigurasi .NET Runtime .

Konsep dan abstraksi

Mengingat satu atau beberapa sumber konfigurasi, jenis IConfiguration menyediakan tampilan terpadu dari data konfigurasi. Konfigurasi bersifat baca-saja, dan pola konfigurasi tidak dirancang agar dapat ditulis secara terprogram. Antarmuka IConfiguration adalah representasi tunggal dari semua sumber konfigurasi, seperti yang ditunjukkan dalam diagram berikut:

Antarmuka 'IConfiguration' adalah representasi tunggal dari semua sumber konfigurasi.

Mengonfigurasi aplikasi konsol

Aplikasi konsol .NET yang dibuat menggunakan templat perintah dotnet new atau Visual Studio pada dasarnya tidak mengekspos kapabilitas konfigurasi. Untuk menambahkan konfigurasi di aplikasi konsol .NET baru, tambahkan referensi paket ke 📦 Microsoft.Extensions.Configuration. Paket ini adalah fondasi untuk konfigurasi di aplikasi .NET. Ini menyediakan jenis ConfigurationBuilder dan jenis terkait.

using Microsoft.Extensions.Configuration;

var configuration = new ConfigurationBuilder()
    .AddInMemoryCollection(new Dictionary<string, string?>()
    {
        ["SomeKey"] = "SomeValue"
    })
    .Build();

Console.WriteLine(configuration["SomeKey"]);

// Outputs:
//   SomeValue

Kode sebelumnya:

  • Membuat instans ConfigurationBuilder baru.
  • Menambahkan sekumpulan pasangan kunci-nilai yang tersimpan dalam memori ke penyusun konfigurasi.
  • Memanggil metode Build() untuk membuat instans IConfiguration.
  • Menulis nilai kunci SomeKey ke konsol.

Meskipun contoh ini menggunakan konfigurasi dalam memori, ada banyak penyedia konfigurasi yang tersedia, mengekspos fungsionalitas untuk berbasis file, variabel lingkungan, argumen baris perintah, dan sumber konfigurasi lainnya. Untuk informasi selengkapnya, lihat Penyedia konfigurasi di .NET.

Pendekatan hosting alternatif

Umumnya, aplikasi Anda akan melakukan lebih dari sekadar membaca konfigurasi. Mereka kemungkinan akan menggunakan injeksi dependensi, pencatatan log, dan layanan lainnya. Pendekatan .NET Generic Host direkomendasikan untuk aplikasi yang menggunakan layanan ini. Sebagai gantinya, pertimbangkan untuk menambahkan referensi paket ke 📦 Microsoft.Extensions.Hosting. Ubah file Program.cs agar sesuai dengan kode berikut:

using Microsoft.Extensions.Hosting;

using IHost host = Host.CreateApplicationBuilder(args).Build();

// Application code should start here.

await host.RunAsync();

Metode Host.CreateApplicationBuilder(String[]) menyediakan konfigurasi default untuk aplikasi dalam urutan berikut, dari prioritas tertinggi hingga terendah:

  1. Argumen baris perintah menggunakan Penyedia konfigurasi baris perintah.
  2. Variabel lingkungan dengan menggunakan penyedia konfigurasi Variabel Lingkungan .
  3. Rahasia aplikasi saat aplikasi berjalan di lingkungan Development.
  4. appsettings.Environment.json menggunakan penyedia konfigurasi JSON. Misalnya, appsettings.Production.json dan appsettings.Development.json.
  5. appsettings.json menggunakan penyedia konfigurasi JSON .
  6. ChainedConfigurationProvider : Menambahkan IConfiguration yang ada sebagai sumber.

Menambahkan penyedia konfigurasi akan mengambil alih nilai konfigurasi sebelumnya. Misalnya, penyedia konfigurasi Antarmuka Baris Perintah menggantikan semua nilai dari penyedia lain karena ditambahkan paling terakhir. Jika SomeKey diatur di appsettings.json dan lingkungan, nilai lingkungan digunakan karena ditambahkan setelah appsettings.json.

Mengikat

Salah satu keuntungan utama menggunakan abstraksi konfigurasi .NET adalah kemampuan untuk mengikat nilai konfigurasi ke instans objek .NET. Misalnya, penyedia konfigurasi JSON dapat digunakan untuk memetakan file appsettings.json ke objek .NET dan digunakan dengan injeksi dependensi . Ini memungkinkan pola opsi, yang menggunakan kelas untuk menyediakan akses yang sangat diketik ke grup pengaturan terkait. Pengikat default berbasis refleksi, tetapi ada alternatif generator sumber yang mudah diaktifkan.

Konfigurasi .NET menyediakan berbagai abstraksi. Pertimbangkan antarmuka berikut:

Abstraksi ini agnostik terhadap penyedia konfigurasi yang mendasarinya (IConfigurationProvider). Dengan kata lain, Anda dapat menggunakan instans IConfiguration untuk mengakses nilai konfigurasi apa pun dari beberapa penyedia.

Pengikat dapat menggunakan pendekatan yang berbeda untuk memproses nilai konfigurasi:

  • Deserialisasi langsung (menggunakan konverter bawaan) untuk tipe primitif.
  • TypeConverter untuk tipe kompleks ketika tipe tersebut memiliki satu.
  • Refleksi untuk tipe kompleks yang memiliki properti.

Nota

Pengikat memiliki beberapa batasan:

  • Properti diabaikan jika memiliki setter privat atau jenisnya tidak dapat dikonversi.
  • Properti tanpa kunci konfigurasi yang sesuai diabaikan.

Hierarki yang mengikat

Nilai konfigurasi dapat berisi data hierarkis. Objek hierarkis diwakili dengan penggunaan pemisah : dalam kunci konfigurasi. Untuk mengakses nilai konfigurasi, gunakan karakter : untuk memisahkan hierarki. Misalnya, pertimbangkan nilai konfigurasi berikut:

{
  "Parent": {
    "FavoriteNumber": 7,
    "Child": {
      "Name": "Example",
      "GrandChild": {
        "Age": 3
      }
    }
  }
}

Tabel berikut ini mewakili contoh kunci dan nilai yang sesuai untuk contoh JSON sebelumnya:

Key Value
"Parent:FavoriteNumber" 7
"Parent:Child:Name" "Example"
"Parent:Child:GrandChild:Age" 3

Skenario pengikatan tingkat lanjut

Pengikat konfigurasi memiliki perilaku dan batasan tertentu saat bekerja dengan jenis tertentu. Bagian ini mencakup subbagian berikut:

Hubungkan ke kamus

Saat Anda mengikat konfigurasi ke Dictionary<TKey,TValue> tempat nilai adalah jenis koleksi yang dapat diubah (seperti array atau daftar), pengikatan berulang ke kunci yang sama memperluas nilai koleksi alih-alih menggantinya.

Contoh berikut menunjukkan perilaku ini:

IConfiguration config = new ConfigurationBuilder()
    .AddInMemoryCollection()
    .Build();

config["Queue:0"] = "Value1";
var dict = new Dictionary<string, string[]>() { { "Queue", new[] { "InitialValue" } } };

Console.WriteLine("=== Dictionary Binding with Collection Values ===");
Console.WriteLine($"Initially: {string.Join(", ", dict["Queue"])}");

// In .NET 7+, binding extends the collection instead of replacing it.
config.Bind(dict);
Console.WriteLine($"After Bind: {string.Join(", ", dict["Queue"])}");

config["Queue:1"] = "Value2";
config.Bind(dict);
Console.WriteLine($"After 2nd Bind: {string.Join(", ", dict["Queue"])}");

Untuk informasi selengkapnya, lihat Mengikat konfigurasi ke kamus memperluas nilai.

Kunci kamus dengan titik dua

Karakter titik dua (:) dicadangkan sebagai pemisah hierarki dalam kunci konfigurasi. Ini berarti Anda tidak dapat menggunakan titik dua dalam kunci kamus saat mengikat konfigurasi. Jika kunci Anda berisi titik dua (seperti URL atau pengidentifikasi berformat lainnya), sistem konfigurasi menginterpretasikannya sebagai jalur hierarki daripada karakter harfiah. Pertimbangkan solusi berikut:

  • Gunakan karakter pemisah alternatif (seperti garis bawah __ganda ) di kunci konfigurasi Anda dan ubah secara terprogram jika diperlukan.
  • Deserialisasi konfigurasi secara manual sebagai JSON mentah menggunakan System.Text.Json atau pustaka serupa yang mendukung penggunaan titik dua dalam kunci.
  • Buat lapisan pemetaan kustom yang menerjemahkan kunci aman ke kunci target dengan menggunakan tanda titik dua.

Ikat dengan tipe IReadOnly*

Pemberi ikatan konfigurasi tidak mendukung pengikatan langsung ke IReadOnlyList<T>, IReadOnlyDictionary<TKey, TValue>, dan antarmuka koleksi yang hanya dapat dibaca lainnya. Antarmuka ini tidak memiliki mekanisme yang dibutuhkan binder untuk mengisi koleksi.

Untuk bekerja dengan koleksi yang hanya-bisa-dibaca, gunakan tipe yang dapat diubah untuk properti yang diisi binder, kemudian paparkan sebagai antarmuka hanya-bisa-dibaca untuk konsumen.

Console.WriteLine("=== IReadOnly* Types (NOT Directly Supported) ===");

var readonlyConfig = new ConfigurationBuilder()
    .AddInMemoryCollection(new Dictionary<string, string?>
    {
        ["Settings:Values:0"] = "Item1",
        ["Settings:Values:1"] = "Item2",
        ["Settings:Values:2"] = "Item3",
    })
    .Build();

// This class uses List<string> for binding, exposes as IReadOnlyList<string>.
var settings = new SettingsWithReadOnly();
readonlyConfig.GetSection("Settings").Bind(settings);

Console.WriteLine("Values bound to mutable List, exposed as IReadOnlyList:");
foreach (var value in settings.ValuesReadOnly)
{
    Console.WriteLine($"  {value}");
}

Pengimplementasian kelas konfigurasi:

class SettingsWithReadOnly
{
    // Use mutable type for binding
    public List<string> Values { get; set; } = [];

    // Expose as read-only for consumers
    public IReadOnlyList<string> ValuesReadOnly => Values;
}

Pendekatan ini memungkinkan pengikat mengisi mutable List<string> sambil menyajikan antarmuka yang tidak dapat diubah kepada pengguna melalui IReadOnlyList<string>.

Mengikat dengan konstruktor berparameter

Dimulai dengan .NET 7, pengikat konfigurasi mulai mendukung pengikatan ke tipe dengan konstruktor publik yang memiliki parameter tunggal. Ini memungkinkan jenis dan rekaman yang tidak dapat diubah diisi langsung dari konfigurasi:

Console.WriteLine("=== Parameterized Constructor Binding ===");

var ctorConfig = new ConfigurationBuilder()
    .AddInMemoryCollection(new Dictionary<string, string?>
    {
        ["AppSettings:Name"] = "MyApp",
        ["AppSettings:MaxConnections"] = "100",
        ["AppSettings:Timeout"] = "30"
    })
    .Build();

// Binding to a type with a single parameterized constructor
var appSettings = ctorConfig.GetSection("AppSettings").Get<AppSettings>();
if (appSettings != null)
{
    Console.WriteLine($"Name: {appSettings.Name}");
    Console.WriteLine($"MaxConnections: {appSettings.MaxConnections}");
    Console.WriteLine($"Timeout: {appSettings.Timeout}");
}

Kelas pengaturan yang tidak dapat diubah:

// Immutable type with single parameterized constructor.
class AppSettings
{
    public string Name { get; }
    public int MaxConnections { get; }
    public int Timeout { get; }

    public AppSettings(string name, int maxConnections, int timeout)
    {
        Name = name;
        MaxConnections = maxConnections;
        Timeout = timeout;
    }
}

Penting

Pengikat hanya mendukung jenis dengan satu konstruktor berparameter publik. Jika jenis memiliki beberapa konstruktor berparameter publik, pengikat tidak dapat menentukan mana yang akan digunakan dan pengikatan akan gagal. Gunakan konstruktor berparameter tunggal atau konstruktor tanpa parameter dengan setter properti.

Contoh dasar

Untuk mengakses nilai konfigurasi dalam bentuk dasarnya, tanpa bantuan pendekatan host generik , gunakan tipe ConfigurationBuilder secara langsung.

Tip

Jenis System.Configuration.ConfigurationBuilder berbeda dengan jenis Microsoft.Extensions.Configuration.ConfigurationBuilder. Semua konten ini khusus untuk paket dan namespace NuGet Microsoft.Extensions.*.

Pertimbangkan proyek C# berikut:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>true</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <Content Include="appsettings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.3" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.3" />
    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="10.0.3" />
  </ItemGroup>

</Project>

File proyek sebelumnya mereferensikan beberapa paket NuGet konfigurasi:

Pertimbangkan contoh file appsettings.json:

{
    "Settings": {
        "KeyOne": 1,
        "KeyTwo": true,
        "KeyThree": {
            "Message": "Oh, that's nice...",
            "SupportedVersions": {
                "v1": "1.0.0",
                "v3": "3.0.7"
            }
        },
        "IPAddressRange": [
            "46.36.198.121",
            "46.36.198.122",
            "46.36.198.123",
            "46.36.198.124",
            "46.36.198.125"
        ]
    }
}

Sekarang, mengingat file JSON ini, berikut adalah contoh pola konsumsi menggunakan penyusun konfigurasi secara langsung:

using Microsoft.Extensions.Configuration;

// Build a config object, using env vars and JSON providers.
IConfigurationRoot config = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json")
    .AddEnvironmentVariables()
    .Build();

// Get values from the config given their key and their target type.
Settings? settings = config.GetRequiredSection("Settings").Get<Settings>();

// Write the values to the console.
Console.WriteLine($"KeyOne = {settings?.KeyOne}");
Console.WriteLine($"KeyTwo = {settings?.KeyTwo}");
Console.WriteLine($"KeyThree:Message = {settings?.KeyThree?.Message}");

// Application code which might rely on the config could start here.

// This will output the following:
//   KeyOne = 1
//   KeyTwo = True
//   KeyThree:Message = Oh, that's nice...

Kode C# sebelumnya:

  • Membuat instans ConfigurationBuilder.
  • Menambahkan file "appsettings.json" yang akan dikenali oleh penyedia konfigurasi JSON.
  • Menambahkan variabel lingkungan sebagaimana dikenali oleh penyedia konfigurasi Variabel Lingkungan.
  • Mendapatkan bagian "Settings" yang diperlukan dan instans Settings yang sesuai dengan menggunakan instans config.

Objek Settings dibentuk sebagai berikut:

public sealed class Settings
{
    public required int KeyOne { get; set; }
    public required bool KeyTwo { get; set; }
    public required NestedSettings KeyThree { get; set; } = null!;
}
public sealed class NestedSettings
{
    public required string Message { get; set; } = null!;
}

Contoh dasar dengan hosting

Untuk mengakses nilai IConfiguration, Anda dapat mengandalkan kembali paket nuGet Microsoft.Extensions.Hosting. Buat aplikasi konsol baru, dan tempelkan konten file proyek berikut ke dalamnya:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>true</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <Content Include="appsettings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.3" />
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.3" />
  </ItemGroup>

</Project>

File proyek sebelumnya mendefinisikan bahwa:

  • Aplikasi ini dapat dieksekusi.
  • File appsettings.json akan disalin ke direktori output saat proyek dikompilasi.
  • Referensi paket NuGet Microsoft.Extensions.Hosting ditambahkan.

Tambahkan file appsettings.json di akar proyek dengan konten berikut:

{
    "KeyOne": 1,
    "KeyTwo": true,
    "KeyThree": {
        "Message": "Thanks for checking this out!"
    }
}

Ganti konten file Program.cs dengan kode C# berikut:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using IHost host = Host.CreateApplicationBuilder(args).Build();

// Ask the service provider for the configuration abstraction.
IConfiguration config = host.Services.GetRequiredService<IConfiguration>();

// Get values from the config given their key and their target type.
int keyOneValue = config.GetValue<int>("KeyOne");
bool keyTwoValue = config.GetValue<bool>("KeyTwo");
string? keyThreeNestedValue = config.GetValue<string>("KeyThree:Message");

// Write the values to the console.
Console.WriteLine($"KeyOne = {keyOneValue}");
Console.WriteLine($"KeyTwo = {keyTwoValue}");
Console.WriteLine($"KeyThree:Message = {keyThreeNestedValue}");

// Application code which might rely on the config could start here.

await host.RunAsync();

// This will output the following:
//   KeyOne = 1
//   KeyTwo = True
//   KeyThree:Message = Thanks for checking this out!

Saat Anda menjalankan aplikasi ini, Host.CreateApplicationBuilder menentukan perilaku untuk menemukan konfigurasi JSON dan mengeksposnya melalui instans IConfiguration. Dari instans host, Anda dapat meminta instans IConfiguration kepada penyedia layanan lalu meminta nilai.

Tip

Menggunakan instans mentah IConfiguration dengan cara ini, meskipun nyaman, tidak menskalakan dengan sangat baik. Ketika aplikasi tumbuh dalam kompleksitas, dan konfigurasi yang sesuai menjadi lebih kompleks, kami sarankan Anda menggunakan pola opsi sebagai alternatif.

Contoh dasar dengan hosting dan menggunakan API pengindeks

Pertimbangkan konten file appsettings.json yang sama dari contoh sebelumnya:

{
    "SupportedVersions": {
        "v1": "1.0.0",
        "v3": "3.0.7"
    },
    "IPAddressRange": [
        "46.36.198.123",
        "46.36.198.124",
        "46.36.198.125"
    ]
}

Ganti konten file Program.cs dengan kode C# berikut:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using IHost host = Host.CreateApplicationBuilder(args).Build();

// Ask the service provider for the configuration abstraction.
IConfiguration config = host.Services.GetRequiredService<IConfiguration>();

// Get values from the config given their key and their target type.
string? ipOne = config["IPAddressRange:0"];
string? ipTwo = config["IPAddressRange:1"];
string? ipThree = config["IPAddressRange:2"];
string? versionOne = config["SupportedVersions:v1"];
string? versionThree = config["SupportedVersions:v3"];

// Write the values to the console.
Console.WriteLine($"IPAddressRange:0 = {ipOne}");
Console.WriteLine($"IPAddressRange:1 = {ipTwo}");
Console.WriteLine($"IPAddressRange:2 = {ipThree}");
Console.WriteLine($"SupportedVersions:v1 = {versionOne}");
Console.WriteLine($"SupportedVersions:v3 = {versionThree}");

// Application code which might rely on the config could start here.

await host.RunAsync();

// This will output the following:
//     IPAddressRange:0 = 46.36.198.123
//     IPAddressRange:1 = 46.36.198.124
//     IPAddressRange:2 = 46.36.198.125
//     SupportedVersions:v1 = 1.0.0
//     SupportedVersions:v3 = 3.0.7

Nilai diakses menggunakan API pengindeks di mana setiap kunci adalah string, dan nilainya adalah string. Konfigurasi mendukung properti, objek, array, dan kamus.

Penyedia konfigurasi

Tabel berikut menunjukkan penyedia konfigurasi yang tersedia untuk aplikasi .NET Core.

Penyedia konfigurasi Menyediakan konfigurasi dari
Azure App Configuration Azure App Configuration
Azure Key Vault Azure Key Vault
baris perintah Parameter baris perintah
Khusus Sumber kustom
Variabel lingkungan Variabel lingkungan
File File JSON, XML, dan INI
Kunci-per-file File direktori
Memory Koleksi data dalam memori
Rahasia aplikasi (manajer rahasia) File di direktori profil pengguna

Tip

Urutan penambahan penyedia konfigurasi itu penting. Ketika beberapa penyedia konfigurasi digunakan dan lebih dari satu penyedia menentukan kunci yang sama, yang terakhir ditambahkan digunakan.

Untuk informasi selengkapnya tentang berbagai penyedia konfigurasi, lihat penyedia Konfigurasi di .NET.

Lihat juga