مقدمه

علاوه بر فایل‌های پیکربندی مانند appsettings.json یک راه دیگر برای فراهم کردن تنظیمات برای برنامه‌های ما، استفاده از متغیرهای محیطی (Environment Variables) است. متغیرهای محیطی، جفت‌های کلید-مقداری هستند که بخشی از محیط سیستم‌عامل محسوب می‌شوند. آن‌ها راهی قدرتمند برای پیکربندی رفتار برنامه بدون نیاز به تغییر هیچ فایلی فراهم می‌کنند و به خصوص در محیط‌های مدرن مانند کانتینرها (Docker) و پلتفرم‌های ابری (Cloud Platforms) بسیار پرکاربرد هستند.

فریم‌ورک .NET از طریق کلاس استاتیک System.Environment، دسترسی آسان به این متغیرها را فراهم می‌کند. در این درس، یاد می‌گیریم که چگونه متغیرهای محیطی را بخوانیم، آن‌ها را تنظیم کنیم و از آن‌ها به عنوان یک منبع پیکربندی در کنار فایل‌های JSON استفاده نماییم.

خواندن متغیرهای محیطی

کلاس Environment شامل متدهایی برای دسترسی به متغیرهای محیطی و همچنین اطلاعات کلی در مورد محیط اجرای برنامه (مانند نام ماشین، نسخه‌ی سیستم‌عامل و ...) است.

خواندن یک متغیر خاص

برای خواندن مقدار یک متغیر محیطی خاص، از متد استاتیک Environment.GetEnvironmentVariable(string variable) استفاده می‌کنیم. این متد نام متغیر را به عنوان یک رشته دریافت کرده و مقدار آن را به صورت یک رشته برمی‌گرداند. اگر متغیر مورد نظر وجود نداشته باشد، این متد مقدار null را برمی‌گرداند.

Copy Icon Program.cs
// Reading a well-known environment variable (PATH).
string pathVariable = Environment.GetEnvironmentVariable("PATH");
Console.WriteLine($"PATH variable has {pathVariable?.Length ?? 0} characters.");

// Reading a custom environment variable.
// You can set this variable in your system before running the app.
string apiKey = Environment.GetEnvironmentVariable("MY_API_KEY");
if (string.IsNullOrEmpty(apiKey))
{
    Console.WriteLine("MY_API_KEY is not set.");
}
else
{
    Console.WriteLine($"API Key: {apiKey}");
}

خواندن تمام متغیرهای محیطی

برای به دست آوردن یک دیکشنری از تمام متغیرهای محیطی موجود، می‌توانیم از متد Environment.GetEnvironmentVariables() استفاده کنیم.

Copy Icon Program.cs
using System.Collections;

IDictionary environmentVariables = Environment.GetEnvironmentVariables();
Console.WriteLine("\n--- All Environment Variables ---");
foreach (DictionaryEntry de in environmentVariables)
{
    Console.WriteLine($"{de.Key} = {de.Value}");
}

تنظیم متغیرهای محیطی

با استفاده از متد Environment.SetEnvironmentVariable(string variable, string value) می‌توانیم یک متغیر محیطی جدید ایجاد کرده یا مقدار یک متغیر موجود را تغییر دهیم.

نکته مهم: متغیرهای محیطی که به این روش تنظیم می‌شوند، فقط در محدوده‌ی پروسه‌ی فعلی و پروسه‌های فرزندی که از آن ایجاد می‌شوند، معتبر هستند. این تغییرات بر روی تنظیمات سراسری سیستم‌عامل تأثیر نمی‌گذارند و با بسته شدن برنامه از بین می‌روند.

Copy Icon Program.cs
// Set an environment variable for the current process.
Environment.SetEnvironmentVariable("TEMP_DATA", "12345");

// Read it back to confirm.
string tempData = Environment.GetEnvironmentVariable("TEMP_DATA");
Console.WriteLine($"\nTEMP_DATA = {tempData}");

ترکیب متغیرهای محیطی با سیستم پیکربندی

قدرت واقعی متغیرهای محیطی زمانی مشخص می‌شود که آن‌ها را با سیستم پیکربندی مدرن .NET (که در درس قبل دیدیم) ترکیب کنیم. ConfigurationBuilder به ما اجازه می‌دهد تا متغیرهای محیطی را به عنوان یک منبع پیکربندی اضافه کنیم.

یک قرارداد رایج این است که سیستم پیکربندی به صورت سلسله مراتبی عمل کند. یعنی ابتدا تنظیمات را از فایل appsettings.json بخواند و سپس سعی کند آن‌ها را با مقادیر موجود در متغیرهای محیطی بازنویسی (override) کند. این به ما اجازه می‌دهد تا یک پیکربندی پیش‌فرض در فایل داشته باشیم، اما در محیط‌های مختلف (مانند سرور تولید یا یک کانتینر Docker) آن را با استفاده از متغیرهای محیطی تغییر دهیم.

Copy Icon Program.cs
using Microsoft.Extensions.Configuration;

IConfiguration config = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json") // Reads from file first.
    .AddEnvironmentVariables()      // Then, overrides with environment variables.
    .Build();

// Let's assume appsettings.json has "AppTitle": "My Awesome App"
// Now, if we set an environment variable named "AppTitle" before running:
// $env:AppTitle="My Production App"  (in PowerShell)

string title = config["AppTitle"];
Console.WriteLine($"Final App Title: {title}"); // Will print "My Production App"

در این مثال، AddEnvironmentVariables پس از AddJsonFile فراخوانی شده است، بنابراین اولویت بالاتری دارد. اگر یک متغیر محیطی با نامی مشابه یک کلید در فایل json وجود داشته باشد، مقدار متغیر محیطی برنده خواهد شد. برای دسترسی به کلیدهای تودرتو مانند ConnectionStrings:DefaultConnection باید یک متغیر محیطی با نام ConnectionStrings__DefaultConnection (با دو آندرلاین) یا ConnectionStrings:DefaultConnection (در برخی شِل‌ها) تعریف کنید.