در این مقاله، میخواهیم در مورد configuration provider ها در ASP.NET Core صحبت کنیم. ما قبلا از JSON به عنوان یک فرمت پیشفرض در configuration استفاده کردیم و این رایجترین فرمت مورد استفاده برای پیکربندی اپلیکیشن ASP.NET Core است.
اما موارد دیگری نیز در این زمینه وجود دارد.
اگر میخواهید در طول مسیر این مقاله، ما را دنبال کنید، از نقطه شروع یعنی سورس `پروژه اعتبارسنجی options استفاده کنید. برای بررسی پروژه تکمیل شده این مقاله، از پروژه نهایی این مقاله یعنی پروژه تکمیل شده Configuration Provider ها استفاده کنید.
در این مقاله، میخواهیم در مورد عناوین زیر صحبت کنیم:
- Configuration Provider ها چه چیزهایی هستند؟
- کدام Configuration Provider ها، به طور پیشفرض موجود هستند؟
- ترتیب پیشفرض اجرای Configuration Provider ها در اپلیکیشن ASP.NET Core
- استفاده از Configuration Provider های پیشفرض
- نتیجه گیری
کارمان را شروع کنیم.
Configuration Provider ها چه چیزهایی هستند؟
هنگامی که ما یک برنامه ASP.NET Core را از یک template ایجاد می کنیم، با یک configuration به شکل یک فایل JSON به نام appsetting.json مواجه میشویم. این فایل معمولاً برای پیکربندی برنامه های ASP.NET Core استفاده می شود و هیچ مشکلی در آن وجود ندارد.
ما حتی میتوانیم این فایل را برای override کردن مقادیر پیکربندی، وابسته به environment که اپلیکیشن در حال اجراست، توسعه دهیم. بنابراین برای مثال، میتوانیم یک فایل apsettings.Production.json را برای override کردن یک connection string برای production environment ایجاد کنیم.
اما راه های زیادی برای پیکربندی اپلیکیشن ما وجود دارد. ما حتی میتوانیم از چند منبع متفاوت برای پیکربندی استفاده کنیم.
ما همچنین می توانیم هردوی host و application را پیکربندی کنیم، اما در این اینجا، ما بر روی پیکربندی application تمرکز خواهیم کرد.
با این اوصاف، مهم است که بدانیم که configuration provider های مختلف میتوانند یکدیگر را override کنند. ترتیب اجرا شدن آنها مهم است.
بنابراین کدام configuration provider ها برای ما موجود هستند؟
کدام Configuration Provider ها به طور پیشفرض موجود هستند؟
این لیستی از configuration provider های موجود در ASP.NET Core است:
- File configuration provider (پیشفرض)
- Secret Manager (پیشفرض)
- configuration provider متغیرهای محیطی (پیشفرض)
- Command-line configuration provider (پیشفرض)
- Memory configuration provider
- Azure Key Vault configuration provider
- Azure App configuration provider
- Key-per-file configuration provider
- configuration provider سفارشی
چهار provider اولی موجود در این لیست، provider هایی هستند که ما به طور پیشفرض آنها را در اختیار داریم. اینها توسط host builder پیاده سازی میشوند. مابقی provider ها را باید خودمان پیاده سازی کنیم.
configuration provider سفارشی، یک مکانیسم خیلی قدرتمند است. این نوع configuration provider، این امکان را به ما می دهد تا هر configuration provider را که می خواهیم را پیاده سازی کنیم. برای مثال بگویید، ما می خواهیم پیکربندی خود را در یک جدول پایگاه داده نگه داریم. مشکلی نیست، با چند خط کد می توانیم provider سفارشی خود را به برنامه اضافه کنیم.
یک file configuration provider تا حد زیادی بیشترین استفاده را دارد اما مواردی وجود دارد که ما باید از provider های دیگر استفاده کنیم. غیر معمول نیست که توسعه دهندگان در تیم های بزرگ توسعه در پروژه های بزرگ کار می کنند، جایی که حتی قرار دادن اطلاعات حساس در فایل apsettings.json می تواند دیگران را با مشکل روبرو کند و عملیات rollback را انجام دهد.
ما هم همچین شرایطی را تجربه کرده ایم. متغیرهای Environment و user secret ها میتوانند در این مورد به ما کمک کنند.
همچنین مسئله حساسیت مقادیر پیکربندی برای production environment نیز وجود دارد. ما نمیتوانیم از اطلاعات حساس در فایلها در production استفاده کنیم. در این مورد، فقط Azure key vault ممکن است یک راه حل مناسب برای ما باشد.
ما ذکر کردیم که configuration provider ها در یک ترتیب خاص اجرا میشوند.
بیاید یاد بگیریم که آنها به چه ترتیبی اجرا میشوند.
ترتیب پیشفرض اجرای Configuration Provider ها در اپلیکیشن ASP.NET Core
آیا متد ساده ()CreateDefaultBuilder در Program.cs را میشناسید؟
1 2 3 4 5 6 |
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); |
ثابت شده است که این متد کارهای زیادی را برای ما انجام میدهد. از جمله پیکربندی اولیه host و application ما.
از آنجایی که ما اینجا داریم در مورد پیکربندی اپلیکیشن صحبت میکنیم، در نتیجه تمرکز خود را بر روی این قسمت از پیاده سازی قرار میدهیم:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
public static IHostBuilder CreateDefaultBuilder(string[] args) { var builder = new HostBuilder(); //trimmed builder.ConfigureAppConfiguration((hostingContext, config) => { var env = hostingContext.HostingEnvironment; config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true); if (env.IsDevelopment() && !string.IsNullOrEmpty(env.ApplicationName)) { var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName)); if (appAssembly != null) { config.AddUserSecrets(appAssembly, optional: true); } } config.AddEnvironmentVariables(); if (args != null) { config.AddCommandLine(args); } }) //trimmed return builder; } |
از این پیاده سازی، میتوانیم ترتیب اجرای configuration provider ها را ببینیم. host builder از متد ()ConfigureAppConfiguration برای تعریف ترتیب بارگذاری provider های ما استفاده میکند.
اول، file configuration provider، هر دو فایلهای appsettings.json and appsettings.{EnvironmentName}.json را اضافه میکند. سپس اگر در محیط توسعه باشیم، user secret ،host builder ها را اضافه میکند. بعد از آن، متغیرهای محیطی را اعمال میکند و در آخر، اگر نیاز به override کردن موارد دیگر داشته باشیم، آرگومانهای command-line مورد استفاده قرار میگیرند.
درک این پیاده سازی، بعدا در زمانیکه provider سفارشی خود را میخواهیم پیاده سازی کنیم به ما کمک میکند.
اگر بخواهیم برخی از configuration provider ها را حذف یا حتی دوباره reorder کنیم، می توانیم از این دانش به نفع خود استفاده کنیم. همچنین چندبار فراخوانی متد ()ConfigureAppConfiguration، یک اثر افزایشی خواهد داشت.
افزودن یک فایل ساده ini Configuration
ما می توانیم این را با اضافه کردن یک منبع پیکربندی دیگر با ایجاد یک فایل ini ساده در solution root، نشان دهیم، appsettings.ini:
1 2 3 4 5 6 7 |
[Logging:Level] Default=Information Microsoft=Warning Microsoft.Hosting.Lifetime=Information [ConnectionStrings] sqlConnection=server=.; database=CodeMazeCommerce; Integrated Security=true |
حالا میتوانیم به سادگی، host builder را توسعه دهیم:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }) .ConfigureAppConfiguration((hostingContext, config) => { var env = hostingContext.HostingEnvironment; config.AddIniFile("appsettings.ini", optional: true, reloadOnChange: true) .AddIniFile($"appsettings.{env.EnvironmentName}.ini", optional: true, reloadOnChange: true); }); |
حالا اگر اپلیکیشن را اجرا کنیم، میبینیم که دو منبع دیگر به منابع موجود اضافه شدند.
اما اگر بخواهیم فقط از یک منبع واحد استفاده کنیم و نگران override شدن مقادیرمان توسط provider های مختلف مانند environment یا command-line نباشیم، باید چه کاری انجام دهیم؟
به سادگی میتوانیم این کار را با حذف کردن source ها قبل از اضافه کردن provider خود انجام دهیم:
1 2 3 4 5 6 7 8 9 |
.ConfigureAppConfiguration((hostingContext, config) => { var env = hostingContext.HostingEnvironment; config.Sources.Clear(); config.AddIniFile("appsettings.ini", optional: true, reloadOnChange: true) .AddIniFile($"appsettings.{env.EnvironmentName}.ini", optional: true, reloadOnChange: true); }); |
حالا اگر برنامه را اجرا کنیم، فقط appsettings.ini و appsettings.{EnvironmentName}.ini را به عنوان منابع پیکربندی میبینیم:
عالی.
اما ، configuration provider های دیگری نیز وجود دارند و ما نباید آنها را کنار بگذاریم. بنابراین دستور ()Clear را حذف میکنیم. ببینیم چطور میتوانیم از آنها استفاده کنیم. آنها میتوانند مفید باشند.
استفاده از Configuration Provider های پیشفرض
ما دیدیم که چطور میتوانیم یک فایل ساده پیکربندی ini را با استفاده از file configuration provider و host builder اضافه کنیم. اما ما سه روش دیگر برای تنظیم مقادیر پیکربندی داریم.
User Secret ها
User secret ها، یک مکانیسم مناسب برای ذخیره داده های حساس پیکربندی در حین توسعه هستند. استفاده از آنها آسان است و شما نیازی نیست که برای هر پروژه ای که به طور local توسعه میدهید، متغیرهای محیطی ایجاد کنید. این یک روش خوب است برای اینکه همه چیز را تمیز و ساده نگه دارید.
به طور پیشفرض، اپلیکیشن از secret ها بعد از فایلهای appsetting.json و appsettings.{Environment}.json و درست قبل از متغیرهای محیطی و آرگومانهای command-line به طور پیشفرض استفاده میکند. اگر فکر می کنید که چرا secret شما کار نمی کند، ممکن است ارزش این را داشته باشد که متغیرهای محیطی خود را بررسی کنید.
برای فعال کردن user secret ها، میتوانیم به root پروژه (ProjectConfigurationDemo) navigate کنیم و با نوشتن دستور زیر، secret manager را مقداردهی کنیم:
1 |
dotnet user-secrets init |
این باعث میشود که المنت UserSecretsId در فایل csproj ما، درون المنت PropertyGroup ایجاد شود:
1 2 3 4 |
<PropertyGroup> <TargetFramework>netcoreapp3.1</TargetFramework> <UserSecretsId>06219bf2-6545-49db-b255-908d1fabd932</UserSecretsId> </PropertyGroup> |
حالا میتوانیم یک user secret را برای تنظیم یک connection string، ست کنیم:
1 |
dotnet user-secrets set "ConnectionStrings:sqlConnection" "server=.; database=CodeMazeCommerce; Integrated Security=true" |
زمانیکه پیغام “Successfully saved … to the secret store” را دیدیم، میتوانیم تمام secret هایمان را با نوشتن دستور زیر بررسی کنیم:
1 |
dotnet user-secrets list |
یا میتوانیم با نوشتن این دستور، آن را حذف کنیم:
1 |
dotnet user-secrets remove "ConnectionStrings:sqlConnection" |
همچنین میتوانیم بر روی پروژه داخل ویژوال استودیو راست کلیک کنیم و سپس برای باز کردن فایل secrets.json، به سراغ گزینه “Manage User Secrets” برویم و secret هایمان را بررسی کرده و یا تغییر دهیم:
1 2 3 |
{ "ConnectionStrings:sqlConnection": "server=.; database=CodeMazeCommerce; Integrated Security=true" } |
حالا اگر برنامه را اجرا کنیم، مقادیر پیکربندی ما، در زمان اجرا، در دسترس خواهند بود.
دستورات مفید دیگری برای user secret ها وجود دارند، بنابراین اگر علاقه دارید، میتوانید صفحات مستندات را بررسی کنید.
فقط یادتان باشد که ما باید از user secret ها فقط برای محیط توسعه استفاده کنیم، نباید از آنها در محیطهای دیگر استفاده کنیم.
متغیرهای محیطی
ما میتوانیم همین کار مشابه را با متغیرهای محیطی انجام دهیم. اگرچه استفاده از متغیرهای محیطی کمی سخت تر است اما برای هر محیطی مناسب ترند و بنابراین می توانیم از آنها در مرحله production نیز استفاده کنیم. با این حال، آنها رمزگذاری نشده اند و اگر دستگاه آسیبی ببیند ، دیدن آنها برای همه آزاد است.
تنها چیزی که باید از آن آگاه باشیم این است که هنگام تعریف داده های پیکربندی سلسله مراتبی، باید به جای “:” همانطور که در یک فایل JSON انجام می دادیم ، از دو خط زیرین __ استفاده کنیم.
برای مثال میتوانیم connection string را به این صورت تعریف کنیم:
1 |
set ConnectionStrings__sqlConnection "server=.; database=CodeMazeCommerce; Integrated Security=true" |
و ما میتوانیم با تایپ … چک کنیم که آیا متغیر ست شده است یا خیر.
آرگومانهای Command-line
ما میتوانیم از آرگومانهای command-line برای ست کردن مقادیر پیکربندی نیز استفاده کنیم. انجام این کار رایج نیست، ما می توانیم از این برای آزمایش اینکه آیا مقادیر خاص مورد نظر به درستی کار می کنند استفاده کنیم.
ما میتوانیم configuration را از طریق command-line به سه روش مختلف ست کنیم:
1 2 3 |
dotnet run ConnectionStrings:sqlConnection=server=.; database=CodeMazeCommerce; Integrated Security=true dotnet run /ConnectionStrings:sqlConnection=server=.; database=CodeMazeCommerce; Integrated Security=true dotnet run --ConnectionStrings:sqlConnection=server=.; database=CodeMazeCommerce; Integrated Security=true |
این دستورات یکسان هستند، اما ما بهتر است آنها را با همدیگر ترکیب کنیم.
نتیجه گیری
در این مقاله، ما یاد گرفتیم که configuration provider ها چه چیزهایی هستند. configuration provider های پیشفرض و نحوه استفاده از آنها برای پیکربندی اپلیکشنمان را یاد گرفتیم. در قسمت بعدی، میخواهیم یک configuration provider سفارشی که مقادیر پیکربندیمان را از پایگاه داده میخواند را پیاده سازی کنیم.
شما میتوانید دیگر قسمتهای این سری از آموزش سریالی را از صفحه ASP.NET Core Web API پیدا کنید.