ASP.NET Core 2.2 基礎知識(六)【Configuration】
ASP.NET Core
中的應用配置基於配置提供程式建立的鍵值對。 配置提供程式將配置資料從各種配置源讀取到鍵值對:
- Azure Key Vault
- 命令列引數
- (已安裝或已建立的)自定義提供程式
- 目錄檔案
- 環境變數
- 記憶體中的 .NET 物件
- 設定檔案
選項模式是本主題中描述的配置概念的擴充套件。 選項使用類來表示相關設定的組。 有關使用選項模式的詳細資訊,請參閱 ASP.NET Core 中的選項模式
。
這三個包均包括在 Microsoft.AspNetCore.App 元包
中。
主機與應用配置
在配置並啟動應用之前,配置並啟動主機。 主機負責應用程式啟動和生存期管理。 應用和主機均使用本主題中所述的配置提供程式進行配置。 主機配置鍵值對成為應用的全域性配置的一部分。 有關在構建主機時如何使用配置提供程式以及配置源如何影響主機配置的詳細資訊,請參閱 ASP.NET Core 中的 Web 主機和通用主機
。
預設配置
基於 ASP.NET Core dotnet new
模板的 Web 應用在生成主機時會呼叫 CreateDefaultBuilder
。 CreateDefaultBuilder
為應用提供預設配置。
- 主機配置通過以下方式提供:
- 使用
環境變數配置提供程式
,通過字首為ASPNETCORE_
(例如,ASPNETCORE_ENVIRONMENT
)的環境變數提供。 - 使用
命令列配置提供程式
,通過命令列引數提供。
- 使用
- 應用配置通過以下方式提供(按以下順序):
- 使用
檔案配置提供程式
,通過appsettings.json
提供。 - 使用
檔案配置提供程式
,通過appsettings.{Environment}.json
提供。 - 應用在使用入口程式集的
Development
環境中執行時的機密管理器
。 - 使用
環境變數配置提供程式
,通過環境變數提供。 - 使用
命令列配置提供程式
,通過命令列引數提供。
- 使用
本主題後面將介紹配置提供程式。 有關主機和 CreateDefaultBuilder
的更多資訊,請參閱 ASP.NET Core Web 主機
。
安全性
採用以下最佳實踐:
- 請勿在配置提供程式程式碼或純文字配置檔案中儲存密碼或其他敏感資料。
- 不要在開發或測試環境中使用生產機密。
- 請在專案外部指定機密,避免將其意外提交到原始碼儲存庫。
詳細瞭解如何使用多個環境
和管理使用 Secret Manager 的開發中的應用機密的安全儲存
(包括使用環境變數儲存敏感資料的建議)。 Secret Manager 使用檔案配置提供程式將使用者機密儲存在本地系統上的 JSON 檔案中。 本主題後面將介紹檔案配置提供程式。
Azure Key Vault 是安全儲存應用機密的一種選擇。 有關更多資訊,請參見在 ASP.NET Core 中的 azure 金鑰保管庫配置提供程式
。
分層配置資料
配置 API 能夠通過在配置鍵中使用分隔符來展平分層資料以保持分層配置資料。
在以下 JSON 檔案中,兩個節的結構化層次結構中存在四個鍵:
{
"section0": {
"key0": "value",
"key1": "value"
},
"section1": {
"key0": "value",
"key1": "value"
}
}
將檔案讀入配置時,將建立唯一鍵以保持配置源的原始分層資料結構。 使用冒號 (:
) 展平節和鍵以保持原始結構:
- section0:key0
- section0:key1
- section1:key0
- section1:key1
GetSection
和 GetChildren
方法可用於隔離各個節和配置資料中某節的子節。 稍後將在GetSection、GetChildren 和 Exists
中介紹這些方法。GetSection
在Microsoft.Extensions.Configuration 包中,後者在 Microsoft.AspNetCore.App 元包
中。
約定
在應用啟動時,將按照指定的配置提供程式的順序讀取配置源。
應用啟動後,在更改基礎設定檔案時,檔案配置提供程式可以過載配置。 本主題後面將介紹檔案配置提供程式。
應用的依賴關係注入 (DI)
容器中提供了IConfiguration
。配置提供程式不能使用 DI,因為主機在設定這些提供程式時 DI 不可用。
配置鍵採用以下約定:
- 鍵不區分大小寫。 例如,
ConnectionString
和connectionstring
被視為等效鍵。 - 如果由相同或不同的配置提供程式設定相同鍵的值,則鍵上設定的最後一個值就是所使用的值。
- 分層鍵
- 在配置 API 中,冒號分隔符 (
:
) 適用於所有平臺。 - 在環境變數中,冒號分隔符可能無法適用於所有平臺。 而所有平臺均支援採用雙下劃線 (
__
),並可以將其轉換為冒號。 - 在 Azure Key Vault 中,分層鍵使用
--
(兩個破折號)作為分隔符。 將機密載入到應用的配置中時,必須提供程式碼以用冒號替換破折號。
- 在配置 API 中,冒號分隔符 (
ConfigurationBinder
支援使用配置鍵中的陣列索引將陣列繫結到物件。 陣列繫結將在將陣列繫結到類
部分中進行介紹。
配置值採用以下約定:
- 值是字串。
NULL
值不能儲存在配置中或繫結到物件。
提供程式
下表顯示了 ASP.NET Core
應用可用的配置提供程式。
提供程式 | 通過以下物件提供配置… |
---|---|
Azure Key Vault 配置提供程式(安全主題) | Azure Key Vault |
命令列配置提供程式 | 命令列引數 |
自定義配置提供程式 | 自定義源 |
環境變數配置提供程式 | 環境變數 |
檔案配置提供程式 | 檔案(INI、JSON、XML) |
Key-per-file 配置提供程式 | 目錄檔案 |
記憶體配置提供程式 | 記憶體中集合 |
使用者機密 (Secret Manager)(安全主題) | 使用者配置檔案目錄中的檔案 |
按照啟動時指定的配置提供程式的順序讀取配置源。 本主題中所述的配置提供程式按字母順序進行介紹,而不是按程式碼排列順序進行介紹。 程式碼中的配置提供程式應以特定順序排列以符合基礎配置源的優先順序。
配置提供程式的典型順序為:
- 檔案(
appsettings.json、appsettings.{Environment}.json
,其中{Environment}
是應用的當前託管環境) - Azure 金鑰保管庫
- 使用者機密 (
Secret Manager
)(僅限開發環境中) - 環境變數
- 命令列引數
通常的做法是將命令列配置提供程式置於一系列提供程式的末尾,以允許命令列引數替代由其他提供程式設定的配置。
在使用 CreateDefaultBuilder
初始化新的 WebHostBuilder
時,將使用此提供程式序列。 有關詳細資訊,請參閱Web 主機:設定主機
。
ConfigureAppConfiguration
構建主機時呼叫 ConfigureAppConfiguration
以指定應用的配置提供程式以及 CreateDefaultBuilder
自動新增的配置提供程式:
public class Program
{
public static Dictionary<string, string> arrayDict = new Dictionary<string, string>
{
{"array:entries:0", "value0"},
{"array:entries:1", "value1"},
{"array:entries:2", "value2"},
{"array:entries:4", "value4"},
{"array:entries:5", "value5"}
};
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(Directory.GetCurrentDirectory());
config.AddInMemoryCollection(arrayDict);
config.AddJsonFile("json_array.json", optional: false, reloadOnChange: false);
config.AddJsonFile("starship.json", optional: false, reloadOnChange: false);
config.AddXmlFile("tvshow.xml", optional: false, reloadOnChange: false);
config.AddEFConfiguration(options => options.UseInMemoryDatabase("InMemoryDb"));
config.AddCommandLine(args);
})
.UseStartup<Startup>();
}
命令列配置提供程式
CommandLineConfigurationProvider
在執行時從命令列引數鍵值對載入配置。
要啟用命令列配置,請在 ConfigurationBuilder
的例項上呼叫 AddCommandLine
擴充套件方法。
使用 CreateDefaultBuilder
初始化新的WebHostBuilder
時會自動呼叫 AddCommandLine
。 有關詳細資訊,請參閱Web 主機:設定主機
。
此外,CreateDefaultBuilder
也會載入:
appsettings.json
和appsettings.{Environment}.json
的可選配置。使用者機密 (Secret Manager)
(在開發環境中)。- 環境變數。
CreateDefaultBuilder
最後新增命令列配置提供程式。 在執行時傳遞的命令列引數會替代由其他提供程式設定的配置。
CreateDefaultBuilder
在構造主機時起作用。 因此,CreateDefaultBuilder
啟用的命令列配置可能會影響主機的配置方式。
構建主機時呼叫 ConfigureAppConfiguration
以指定應用的配置。
CreateDefaultBuilder
已經呼叫了 AddCommandLine
。 如果需要提供應用配置並仍然能夠使用命令列引數覆蓋該配置,請在ConfigureAppConfiguration
中呼叫應用的其他提供程式並最後呼叫 AddCommandLine
。
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
// Call other providers here and call AddCommandLine last.
config.AddCommandLine(args);
})
.UseStartup<Startup>();
}
直接建立 WebHostBuilder
時,請使用以下配置呼叫UseConfiguration
:
var config = new ConfigurationBuilder()
// Call additional providers here as needed.
// Call AddCommandLine last to allow arguments to override other configuration.
.AddCommandLine(args)
.Build();
var host = new WebHostBuilder()
.UseConfiguration(config)
.UseKestrel()
.UseStartup<Startup>();
示例
2.x 示例應用利用靜態便捷方法 CreateDefaultBuilder
來構建主機,其中包括對 AddCommandLine
的呼叫。
- 在專案的目錄中開啟命令提示符。
- 為
dotnet run
命令提供命令列引數dotnet run CommandLineKey=CommandLineValue
。 - 應用執行後,在
http://localhost:5000
開啟應用的瀏覽器。 - 觀察輸出是否包含提供給
dotnet run
的配置命令列引數的鍵值對。
自變數
該值必須後跟一個等號 (=
),否則當值後跟一個空格時,鍵必須具有字首(--
或 /
)。 如果使用等號(例如,CommandLineKey=
),則該值可以為 null
。
鍵字首 | 示例 |
---|---|
無字首 | CommandLineKey1=value1 |
雙劃線 (-- ) |
--CommandLineKey2=value2 , --CommandLineKey2 value2 |
正斜槓 (/ ) |
/CommandLineKey3=value3 , /CommandLineKey3 value3 |
在同一命令中,不要將使用等號的命令列引數鍵值對與使用空格的鍵值對混合使用。
示例命令:
dotnet run CommandLineKey1=value1 --CommandLineKey2=value2 /CommandLineKey3=value3
dotnet run --CommandLineKey1 value1 /CommandLineKey2 value2
dotnet run CommandLineKey1= CommandLineKey2=value2
交換對映
交換對映支援鍵名替換邏輯。 使用ConfigurationBuilder
手動構建配置時,可以為 AddCommandLine
方法提供交換替換字典。
當使用交換對映字典時,會檢查字典中是否有與命令列引數提供的鍵匹配的鍵。 如果在字典中找到命令列鍵,則傳回字典值(鍵替換)以將鍵值對設定為應用的配置。 對任何具有單劃線 (-
) 字首的命令列鍵而言,交換對映都是必需的。
交換對映字典鍵規則:
- 交換必須以單劃線 (
-
) 或雙劃線 (--
) 開頭。 - 交換對映字典不得包含重複鍵。
構建主機時呼叫 ConfigureAppConfiguration
以指定應用的配置:
public class Program
{
public static readonly Dictionary<string, string> _switchMappings =
new Dictionary<string, string>
{
{ "-CLKey1", "CommandLineKey1" },
{ "-CLKey2", "CommandLineKey2" }
};
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
// Do not pass the args to CreateDefaultBuilder
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder()
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddCommandLine(args, _switchMappings);
})
.UseStartup<Startup>();
}
如前面的示例所示,當使用交換對映時,對 CreateDefaultBuilder
的呼叫不應傳遞引數。 CreateDefaultBuilder
方法的 AddCommandLine
呼叫不包括對映的交換,並且無法將交換對映字典傳遞給 CreateDefaultBuilder
。 如果引數包含對映的交換並傳遞給 CreateDefaultBuilder
,則其 AddCommandLine
提供程式無法使用 FormatException
進行初始化。 解決方案不是將引數傳遞給 CreateDefaultBuilder
,而是允許 ConfigurationBuilder
方法的 AddCommandLine
方法處理引數和交換對映字典。
建立交換對映字典後,它將包含下表所示的資料。
鍵 | 值 |
---|---|
-CLKey1 |
CommandLineKey1 |
-CLKey2 |
CommandLineKey2 |
如果在啟動應用時使用了交換對映的鍵,則配置將接收字典提供的金鑰上的配置值:
dotnet run -CLKey1=value1 -CLKey2=value2
執行上述命令後,配置包含下表中顯示的值。
鍵 | 值 |
---|---|
CommandLineKey1 |
value1 |
CommandLineKey2 |
value2 |
環境變數配置提供程式
EnvironmentVariablesConfigurationProvider
在執行時從環境變數鍵值對載入配置。
要啟用環境變數配置,請在 ConfigurationBuilder
的例項上呼叫AddEnvironmentVariables
擴充套件方法。
在環境變數中使用分層鍵時,冒號分隔符 (:
) 可能無法適用於所有平臺。 所有平臺均支援採用雙下劃線 (__
),並可以用冒號替換。
藉助 Azure 應用服務,使用者可以在 Azure 門戶中設定使用環境變數配置提供程式替代應用配置的環境變數。 有關詳細資訊,請參閱Azure 應用:使用 Azure 門戶替代應用配置
。
初始化一個新的 WebHostBuilder
時,對於字首為 ASPNETCORE_
的環境變數,會自動呼叫 AddEnvironmentVariables
。 有關詳細資訊,請參閱 Web 主機:設定主機
。
此外,CreateDefaultBuilder
也會載入:
- 來自沒有字首的環境變數的應用配置,方法是通過呼叫不帶字首的
AddEnvironmentVariables
。 - appsettings.json 和 appsettings.{Environment}.json 的可選配置。
使用者機密 (Secret Manager)
(在開發環境中)。- 命令列引數。
環境變數配置提供程式是在配置已根據使用者機密和 appsettings
檔案建立後呼叫。 在此位置呼叫提供程式允許在執行時讀取的環境變數替代由使用者機密和 appsettings
檔案設定的配置。
構建主機時呼叫ConfigureAppConfiguration
以指定應用的配置。
如果需要從其他環境變數提供應用配置,請在ConfigureAppConfiguration
中呼叫應用的其他提供程式,並使用字首呼叫 AddEnvironmentVariables
。
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
// Call additional providers here as needed.
// Call AddEnvironmentVariables last if you need to allow environment
// variables to override values from other providers.
config.AddEnvironmentVariables(prefix: "PREFIX_");
})
.UseStartup<Startup>();
}
直接建立 WebHostBuilder
時,請使用以下配置呼叫UseConfiguration
:
var config = new ConfigurationBuilder()
.AddEnvironmentVariables()
.Build();
var host = new WebHostBuilder()
.UseConfiguration(config)
.UseKestrel()
.UseStartup<Startup>();
示例
2.x 示例應用利用靜態便捷方法 CreateDefaultBuilder
來構建主機,其中包括對 AddEnvironmentVariables
的呼叫。
- 執行示例應用。 在
http://localhost:5000
開啟應用的瀏覽器。 - 觀察輸出是否包含環境變數
ENVIRONMENT
的鍵值對。 該值反映了應用執行的環境,在本地執行時通常為Development
。
為了使應用呈現的環境變數列表簡短,應用將環境變數篩選為以下列內容開頭的變數:
- ASPNETCORE_
- urls
- 日誌記錄
- ENVIRONMENT
- contentRoot
- AllowedHosts
- applicationName
- CommandLine
如果希望公開應用可用的所有環境變數,請將 Pages/Index.cshtml.cs
中的 FilteredConfiguration
更改為以下內容:
FilteredConfiguration = _config.AsEnumerable();
字首
為 AddEnvironmentVariables
方法提供字首時,將篩選載入到應用的配置中的環境變數。 例如,要篩選字首 CUSTOM_
上的環境變數,請將字首提供給配置提供程式:
var config = new ConfigurationBuilder()
.AddEnvironmentVariables("CUSTOM_")
.Build();
建立配置鍵值對時,將去除字首。
靜態便捷方法 CreateDefaultBuilder
建立一個WebHostBuilder
以建立應用的主機。 建立 WebHostBuilder
時,它會在字首為 ASPNETCORE_
的環境變數中找到其主機配置。
連線字串字首
針對為應用環境配置 Azure 連線字串所涉及的四個連線字串環境變數,配置 API 具有特殊的處理規則。 如果沒有向 AddEnvironmentVariables
提供字首,則具有表中所示字首的環境變數將載入到應用中。
連線字串字首 | 提供程式 |
---|---|
CUSTOMCONNSTR_ |
自定義提供程式 |
MYSQLCONNSTR_ |
MySQL |
SQLAZURECONNSTR_ |
Azure SQL 資料庫 |
SQLCONNSTR_ |
SQL Server |
當發現環境變數並使用表中所示的四個字首中的任何一個載入到配置中時:
- 通過刪除環境變數字首並新增配置鍵節 (
ConnectionStrings
) 來建立配置鍵。 - 建立一個新的配置鍵值對,表示資料庫連線提供程式(
CUSTOMCONNSTR_
除外,它沒有宣告的提供程式)。
環境變數鍵 | 轉換的配置鍵 | 提供程式配置條目 |
---|---|---|
CUSTOMCONNSTR_<KEY> |
ConnectionStrings:<KEY> |
配置條目未建立。 |
MYSQLCONNSTR_<KEY> |
ConnectionStrings:<KEY> |
鍵:ConnectionStrings:<KEY>_ProviderName :值: MySql.Data.MySqlClient |
SQLAZURECONNSTR_<KEY> |
ConnectionStrings:<KEY> |
鍵:ConnectionStrings:<KEY>_ProviderName :值: System.Data.SqlClient |
SQLCONNSTR_<KEY> |
ConnectionStrings:<KEY> |
鍵:ConnectionStrings:<KEY>_ProviderName :值: System.Data.SqlClient |
檔案配置提供程式
FileConfigurationProvider
是從檔案系統載入配置的基類。 以下配置提供程式專用於特定檔案型別:
- INI 配置提供程式
- JSON 配置提供程式
- XML 配置提供程式
INI 配置提供程式
IniConfigurationProvider
在執行時從 INI 檔案鍵值對載入配置。
若要啟用 INI 檔案配置,請在 ConfigurationBuilder
的例項上呼叫AddIniFile
擴充套件方法。
冒號可用作 INI 檔案配置中的節分隔符。
過載允許指定:
- 檔案是否可選。
- 如果檔案更改,是否過載配置。
IFileProvider
用於訪問該檔案。
構建主機時呼叫 ConfigureAppConfiguration
以指定應用的配置:
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(Directory.GetCurrentDirectory());
config.AddIniFile("config.ini", optional: true, reloadOnChange: true);
})
.UseStartup<Startup>();
}
基路徑使用 SetBasePath
設定。 SetBasePath
在 Microsoft.Extensions.Configuration.FileExtensions 包中,後者在 Microsoft.AspNetCore.App
元包中。
直接建立 WebHostBuilder
時,請使用以下配置呼叫 UseConfiguration
:
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddIniFile("config.ini", optional: true, reloadOnChange: true)
.Build();
var host = new WebHostBuilder()
.UseConfiguration(config)
.UseKestrel()
.UseStartup<Startup>();
基路徑使用 SetBasePath
設定。 SetBasePath
在 Microsoft.Extensions.Configuration.FileExtensions 包中,後者在 Microsoft.AspNetCore.App
元包中。
INI 配置檔案的通用示例:
[section0]
key0=value
key1=value
[section1]
subsection:key=value
[section2:subsection0]
key=value
[section2:subsection1]
key=value
以前的配置檔案使用 value
載入以下鍵:
- section0:key0
- section0:key1
- section1:subsection:key
- section2:subsection0:key
- section2:subsection1:key
JSON 配置提供程式
JsonConfigurationProvider
在執行時期間從 JSON 檔案鍵值對載入配置。
若要啟用 JSON 檔案配置,請在ConfigurationBuilder
的例項上呼叫AddJsonFile
擴充套件方法。
過載允許指定:
- 檔案是否可選。
- 如果檔案更改,是否過載配置。
IFileProvider
用於訪問該檔案。
使用 CreateDefaultBuilder
初始化新的 WebHostBuilder
時,會自動呼叫 AddJsonFile
兩次。 呼叫該方法來從以下檔案載入配置:
- appsettings.json – 首先讀取此檔案。 該檔案的環境版本可以替代
appsettings.json
檔案提供的值。 - appsettings.{Environment}.json– 根據
IHostingEnvironment.EnvironmentName
載入檔案的環境版本。
有關詳細資訊,請參閱 Web 主機:設定主機
。
此外,CreateDefaultBuilder
也會載入:
- 環境變數。
使用者機密 (Secret Manager)
(在開發環境中)。- 命令列引數。
首先建立 JSON 配置提供程式。 因此,使用者機密、環境變數和命令列引數會替代由 appsettings
檔案設定的配置。
構建主機時呼叫 ConfigureAppConfiguration
以指定除 appsettings.json
和 appsettings.{Environment}.json
以外的檔案的應用配置:
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(Directory.GetCurrentDirectory());
config.AddJsonFile("config.json", optional: true, reloadOnChange: true);
})
.UseStartup<Startup>();
}
基路徑使用 SetBasePath
設定。 SetBasePath
在 Microsoft.Extensions.Configuration.FileExtensions 包中,後者在Microsoft.AspNetCore.App 元包
中。
直接建立 WebHostBuilder
時,請使用以下配置呼叫 UseConfiguration
:
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("config.json", optional: true, reloadOnChange: true)
.Build();
var host = new WebHostBuilder()
.UseConfiguration(config)
.UseKestrel()
.UseStartup<Startup>();
基路徑使用 SetBasePath
設定。 SetBasePath
在 Microsoft.Extensions.Configuration.FileExtensions 包中,後者在 Microsoft.AspNetCore.App 元包
中。
示例
2.x 示例應用利用靜態便捷方法 CreateDefaultBuilder
來構建主機,其中包括對 AddJsonFile
的兩次呼叫。 配置從 appsettings.json
和 appsettings.{Environment}.json
進行載入。
- 執行示例應用。 在
http://localhost:5000
開啟應用的瀏覽器。 - 觀察輸出是否包含表中所示的配置的鍵值對,具體取決於環境。 記錄配置鍵使用冒號 (
:
) 作為分層分隔符。
鍵 | 開發值 | 生產值 |
---|---|---|
Logging:LogLevel:System | 資訊 | 資訊 |
Logging:LogLevel:Microsoft | 資訊 | 資訊 |
Logging:LogLevel:Default | 除錯 | Error |
AllowedHosts | * | * |
XML 配置提供程式
XmlConfigurationProvider
在執行時從 XML
檔案鍵值對載入配置。
若要啟用 XML 檔案配置,請在 ConfigurationBuilder
的例項上呼叫 AddXmlFile
擴充套件方法。
過載允許指定:
- 檔案是否可選。
- 如果檔案更改,是否過載配置。
IFileProvider
用於訪問該檔案。
建立配置鍵值對時,將忽略配置檔案的根節點。 不要在檔案中指定文件型別定義 (DTD) 或名稱空間。
構建主機時呼叫 ConfigureAppConfiguration
以指定應用的配置:
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(Directory.GetCurrentDirectory());
config.AddXmlFile("config.xml", optional: true, reloadOnChange: true);
})
.UseStartup<Startup>();
}
基路徑使用 SetBasePath
設定。 SetBasePath
在 Microsoft.Extensions.Configuration.FileExtensions 包中,後者在Microsoft.AspNetCore.App 元包
中。
直接建立 WebHostBuilder
時,請使用以下配置呼叫UseConfiguration
:
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddXmlFile("config.xml", optional: true, reloadOnChange: true)
.Build();
var host = new WebHostBuilder()
.UseConfiguration(config)
.UseKestrel()
.UseStartup<Startup>();
基路徑使用 SetBasePath
設定。 SetBasePath
在 Microsoft.Extensions.Configuration.FileExtensions 包中,後者在 Microsoft.AspNetCore.App 元包
中。
XML 配置檔案可以為重複節使用不同的元素名稱:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<section0>
<key0>value</key0>
<key1>value</key1>
</section0>
<section1>
<key0>value</key0>
<key1>value</key1>
</section1>
</configuration>
以前的配置檔案使用 value
載入以下鍵:
- section0:key0
- section0:key1
- section1:key0
- section1:key1
如果使用 name
屬性來區分元素,則使用相同元素名稱的重複元素可以正常工作:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<section name="section0">
<key name="key0">value</key>
<key name="key1">value</key>
</section>
<section name="section1">
<key name="key0">value</key>
<key name="key1">value</key>
</section>
</configuration>
以前的配置檔案使用 value
載入以下鍵:
- section:section0?key0
- section:section0?key1
- section:section1?key0
- section:section1?key1
屬性可用於提供值:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<key attribute="value" />
<section>
<key attribute="value" />
</section>
</configuration>
以前的配置檔案使用 value
載入以下鍵:
- key:attribute
- section?attribute
Key-per-file 配置提供程式
KeyPerFileConfigurationProvider
使用目錄的檔案作為配置鍵值對。 該鍵是檔名。 該值包含檔案的內容。 Key-per-file
配置提供程式用於 Docker
託管方案。
若要啟用 Key-per-file
配置,請在 ConfigurationBuilder
的例項上呼叫 AddKeyPerFile
擴充套件方法。 檔案的 directoryPath
必須是絕對路徑。
過載允許指定:
- 配置源的
Action<KeyPerFileConfigurationSource>
委託。 - 目錄是否可選以及目錄的路徑。
雙下劃線字元 (__
) 用作檔名中的配置鍵分隔符。 例如,檔名 Logging__LogLevel__System
生成配置鍵 Logging:LogLevel:System
。
構建主機時呼叫 ConfigureAppConfiguration
以指定應用的配置:
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(Directory.GetCurrentDirectory());
var path = Path.Combine(Directory.GetCurrentDirectory(), "path/to/files");
config.AddKeyPerFile(directoryPath: path, optional: true);
})
.UseStartup<Startup>();
}
基路徑使用 SetBasePath
設定。 SetBasePath
在 Microsoft.Extensions.Configuration.FileExtensions 包中,後者在 Microsoft.AspNetCore.App 元包
中。
直接建立 WebHostBuilder
時,請使用以下配置呼叫 UseConfiguration
:
var path = Path.Combine(Directory.GetCurrentDirectory(), "path/to/files");
var config = new ConfigurationBuilder()
.AddKeyPerFile(directoryPath: path, optional: true)
.Build();
var host = new WebHostBuilder()
.UseConfiguration(config)
.UseKestrel()
.UseStartup<Startup>();
記憶體配置提供程式
MemoryConfigurationProvider
使用記憶體中集合作為配置鍵值對。
若要啟用記憶體中集合配置,請在 ConfigurationBuilder
的例項上呼叫 AddInMemoryCollection
擴充套件方法。
可以使用 IEnumerable<KeyValuePair<String,String>>
初始化配置提供程式。
構建主機時呼叫 ConfigureAppConfiguration
以指定應用的配置:
public class Program
{
public static readonly Dictionary<string, string> _dict =
new Dictionary<string, string>
{
{"MemoryCollectionKey1", "value1"},
{"MemoryCollectionKey2", "value2"}
};
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddInMemoryCollection(_dict);
})
.UseStartup<Startup>();
}
直接建立 WebHostBuilder
時,請使用以下配置呼叫 UseConfiguration
:
var dict = new Dictionary<string, string>
{
{"MemoryCollectionKey1", "value1"},
{"MemoryCollectionKey2", "value2"}
};
var config = new ConfigurationBuilder()
.AddInMemoryCollection(dict)
.Build();
var host = new WebHostBuilder()
.UseConfiguration(config)
.UseKestrel()
.UseStartup<Startup>();
GetValue
ConfigurationBinder.GetValue<T>
從具有指定鍵的配置中提取一個值,並將其轉換為指定型別。 如果未找到該鍵,則過載允許你提供預設值。
以下示例使用鍵 NumberKey
從配置中提取字串值,鍵入該值作為 int
,並將值儲存在變數 intValue
中。 如果在配置鍵中找不到 NumberKey
,則 intValue
會接收 99
的預設值:
var intValue = config.GetValue<int>("NumberKey", 99);
GetSection、GetChildren
和 Exists
對於下面的示例,請考慮以下 JSON 檔案。 在兩個節中找到四個鍵,其中一個包含一對子節:
{
"section0": {
"key0": "value",
"key1": "value"
},
"section1": {
"key0": "value",
"key1": "value"
},
"section2": {
"subsection0" : {
"key0": "value",
"key1": "value"
},
"subsection1" : {
"key0": "value",
"key1": "value"
}
}
}
將檔案讀入配置時,會建立以下唯一的分層鍵來儲存配置值:
- section0:key0
- section0:key1
- section1:key0
- section1:key1
- section2:subsection0:key0
- section2:subsection0:key1
- section2:subsection1:key0
- section2:subsection1:key1
GetSection
IConfiguration.GetSection
使用指定的子節鍵提取配置子節。 GetSection
在 Microsoft.Extensions.Configuration 包中,後者在 Microsoft.AspNetCore.App 元包
中。
若要返回僅包含 section1
中鍵值對的 IConfigurationSection
,請呼叫 GetSection
並提供節名稱:
var configSection = _config.GetSection("section1");
configSection
不具有值,只有金鑰和路徑。
同樣,若要獲取 section2:subsection0
中鍵的值,請呼叫 GetSection
並提供節路徑:
var configSection = _config.GetSection("section2:subsection0");
GetSection
永遠不會返回 null
。 如果找不到匹配的節,則返回空 IConfigurationSection
。
當 GetSection
返回匹配的部分時,Value
未填充。 存在該部分時,返回一個 Key
和 Path
部分。
GetChildren
在 section2
上呼叫 IConfiguration.GetChildren
會獲得 IEnumerable<IConfigurationSection>
,其中包括:
subsection0
subsection1
var configSection = _config.GetSection("section2");
var children = configSection.GetChildren();
存在
使用 ConfigurationExtensions.Exists
確定配置節是否存在:
var sectionExists = _config.GetSection("section2:subsection2").Exists();
給定示例資料,sectionExists
為 false
,因為配置資料中沒有 section2:subsection2
節。
繫結至類
可以使用選項模式將配置繫結到表示相關設定組的類。 有關更多資訊,請參見ASP.NET Core 中的選項模式
。
配置值作為字串返回,但呼叫 Bind
可以構造 POCO 物件。 Bind
在 Microsoft.Extensions.Configuration.Binder 包中,後者在 Microsoft.AspNetCore.App 元包
中。
示例應用包含 Starship
模型 (Models/Starship.cs):
public class Starship
{
public string Name { get; set; }
public string Registry { get; set; }
public string Class { get; set; }
public decimal Length { get; set; }
public bool Commissioned { get; set; }
}
當示例應用使用 JSON 配置提供程式載入配置時,starship.json 檔案的 starship
節會建立配置:
{
"starship": {
"name": "USS Enterprise",
"registry": "NCC-1701",
"class": "Constitution",
"length": 304.8,
"commissioned": false
},
"trademark": "Paramount Pictures Corp. http://www.paramount.com"
}
建立以下配置鍵值對:
鍵 | 值 |
---|---|
starship:name | USS Enterprise |
starship:registry | NCC-1701 |
starship:class | Constitution |
starship:length | 304.8 |
starship:commissioned | False |
trademark | Paramount Pictures Corp. http://www.paramount.com |
示例應用使用 starship
鍵呼叫 GetSection
。 starship
鍵值對是獨立的。 在子節傳入 Starship
類的例項時呼叫 Bind
方法。 繫結例項值後,將例項分配給用於呈現的屬性:
var starship = new Starship();
_config.GetSection("starship").Bind(starship);
Starship = starship;
GetSection
在 Microsoft.Extensions.Configuration 包中,後者在Microsoft.AspNetCore.App 元包
中。
繫結至物件圖
Bind
能夠繫結整個 POCO 物件圖。 Bind
在 Microsoft.Extensions.Configuration.Binder 包中,後者在Microsoft.AspNetCore.App 元包
中。
該示例包含 TvShow
模型,其物件圖包含 Metadata
和 Actors
類 (Models/TvShow.cs):
public class TvShow
{
public Metadata Metadata { get; set; }
public Actors Actors { get; set; }
public string Legal { get; set; }
}
public class Metadata
{
public string Series { get; set; }
public string Title { get; set; }
public DateTime AirDate { get; set; }
public int Episodes { get; set; }
}
public class Actors
{
public string Names { get; set; }
}
示例應用有一個包含配置資料的 tvshow.xml 檔案:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<tvshow>
<metadata>
<series>Dr. Who</series>
<title>The Sun Makers</title>
<airdate>11/26/1977</airdate>
<episodes>4</episodes>
</metadata>
<actors>
<names>Tom Baker, Louise Jameson, John Leeson</names>
</actors>
<legal>(c)1977 BBC https://www.bbc.co.uk/programmes/b006q2x0</legal>
</tvshow>
</configuration>
使用 Bind
方法將配置繫結到整個 TvShow
物件圖。 將繫結例項分配給用於呈現的屬性:
var tvShow = new TvShow();
_config.GetSection("tvshow").Bind(tvShow);
TvShow = tvShow;
ConfigurationBinder.Get<T>
繫結並返回指定型別。 Get<T>
比使用 Bind
更方便。 以下程式碼顯示如何將 Get<T>
與前面的示例一起使用,該示例允許將繫結例項直接分配給用於呈現的屬性:
TvShow = _config.GetSection("tvshow").Get<TvShow>();
Get
在 Microsoft.Extensions.Configuration.Binder 包中,後者在Microsoft.AspNetCore.App 元包
中。 ASP.NET Core 1.1 或更高版本中提供了 Get<T>
。 GetSection
在 Microsoft.Extensions.Configuration 包中,後者在Microsoft.AspNetCore.App 元包
中。
將陣列繫結至類
示例應用演示了本部分中介紹的概念。
Bind
支援使用配置鍵中的陣列索引將陣列繫結到物件。 公開數字鍵段(:0:
、:1:
、… :{n}:
)的任何陣列格式都能夠與 POCO 類陣列進行陣列繫結。 Bind
在 Microsoft.Extensions.Configuration.Binder 包中,後者在 Microsoft.AspNetCore.App 元包
中。
備註
繫結是按約定提供的。 不需要自定義配置提供程式實現陣列繫結。
記憶體中陣列處理
請考慮下表中所示的配置鍵和值。
鍵 | 值 |
---|---|
array:entries:0 | value0 |
array:entries:1 | value1 |
array:entries:2 | value2 |
array:entries:4 | value4 |
array:entries:5 | value5 |
使用記憶體配置提供程式在示例應用中載入這些鍵和值:
public class Program
{
public static Dictionary<string, string> arrayDict = new Dictionary<string, string>
{
{"array:entries:0", "value0"},
{"array:entries:1", "value1"},
{"array:entries:2", "value2"},
{"array:entries:4", "value4"},
{"array:entries:5", "value5"}
};
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(Directory.GetCurrentDirectory());
config.AddInMemoryCollection(arrayDict);
config.AddJsonFile("json_array.json", optional: false, reloadOnChange: false);
config.AddJsonFile("starship.json", optional: false, reloadOnChange: false);
config.AddXmlFile("tvshow.xml", optional: false, reloadOnChange: false);
config.AddEFConfiguration(options => options.UseInMemoryDatabase("InMemoryDb"));
config.AddCommandLine(args);
})
.UseStartup<Startup>();
}
該陣列跳過索引 #3
的值。 配置繫結程式無法繫結 null 值,也無法在繫結物件中建立 null 條目,這在演示將此陣列繫結到物件的結果時變得清晰。
在示例應用中,POCO
類可用於儲存繫結的配置資料:
public class ArrayExample
{
public string[] Entries { get; set; }
}
將配置資料繫結至物件:
var arrayExample = new ArrayExample();
_config.GetSection("array").Bind(arrayExample);
GetSection
在 Microsoft.Extensions.Configuration 包中,後者在Microsoft.AspNetCore.App 元包
中。
還可以使用 ConfigurationBinder.Get<T>
語法,從而產生更精簡的程式碼:
ArrayExample = _config.GetSection("array").Get<ArrayExample>();
繫結物件(ArrayExample
的例項)從配置接收陣列資料。
ArrayExample.Entries 索引 |
ArrayExample.Entries 值 |
---|---|
0 | value0 |
1 | value1 |
2 | value2 |
3 | value4 |
4 | value5 |
繫結物件中的索引 #3
保留 array:4
配置鍵的配置資料及其值 value4
。 當繫結包含陣列的配置資料時,配置鍵中的陣列索引僅用於在建立物件時迭代配置資料。 無法在配置資料中保留 null 值,並且當配置鍵中的陣列跳過一個或多個索引時,不會在繫結物件中建立 null 值條目。
可以在由任何在配置中生成正確鍵值對的配置提供程式繫結到 ArrayExample
例項之前提供索引 #3
的缺失配置項。 如果示例包含具有缺失鍵值對的其他 JSON 配置提供程式,則 ArrayExample.Entries
與完整配置陣列相匹配:
missing_value.json:
{
"array:entries:3": "value3"
}
在 ConfigureAppConfiguration
中:
config.AddJsonFile("missing_value.json", optional: false, reloadOnChange: false);
將表中所示的鍵值對載入到配置中。
鍵 | 值 |
---|---|
array:entries:3 | value3 |
如果在 JSON 配置提供程式包含索引 #3
的條目之後繫結 ArrayExample
類例項,則 ArrayExample.Entries
陣列包含該值。
ArrayExample.Entries 索引 |
ArrayExample.Entries 值 |
---|---|
0 | value0 |
1 | value1 |
2 | value2 |
3 | value3 |
4 | value4 |
5 | value5 |
JSON 陣列處理
如果 JSON 檔案包含陣列,則會為具有從零開始的節索引的陣列元素建立配置鍵。 在以下配置檔案中,subsection
是一個陣列:
{
"json_array": {
"key": "valueA",
"subsection": [
"valueB",
"valueC",
"valueD"
]
}
}
JSON 配置提供程式將配置資料讀入以下鍵值對:
鍵 | 值 |
---|---|
json_array:key | valueA |
json_array:subsection:0 | valueB |
json_array:subsection:1 | valueC |
json_array:subsection:2 | valueD |
在示例應用中,以下 POCO
類可用於繫結配置鍵值對:
public class JsonArrayExample
{
public string Key { get; set; }
public string[] Subsection { get; set; }
}
繫結後,JsonArrayExample.Key
儲存值 valueA
。 子節值儲存在 POCO
陣列屬性 Subsection
中。
JsonArrayExample.Subsection 索引 |
JsonArrayExample.Subsection 值 |
---|---|
0 | valueB |
1 | valueC |
2 | valueD |
自定義配置提供程式
該示例應用演示瞭如何使用實體框架 (EF)
建立從資料庫讀取配置鍵值對的基本配置提供程式。
提供程式具有以下特徵:
- EF 記憶體中資料庫用於演示目的。 若要使用需要連線字串的資料庫,請實現輔助
ConfigurationBuilder
以從另一個配置提供程式提供連線字串。 - 提供程式在啟動時將資料庫表讀入配置。 提供程式不會基於每個鍵查詢資料庫。
- 未實現更改時過載,因此在應用啟動後更新資料庫對應用的配置沒有任何影響。
定義用於在資料庫中儲存配置值的 EFConfigurationValue
實體。
Models/EFConfigurationValue.cs:
public class EFConfigurationValue
{
public string Id { get; set; }
public string Value { get; set; }
}
新增 EFConfigurationContext
以儲存和訪問配置的值。
EFConfigurationProvider/EFConfigurationContext.cs:
public class EFConfigurationContext : DbContext
{
public EFConfigurationContext(DbContextOptions options) : base(options)
{
}
public DbSet<EFConfigurationValue> Values { get; set; }
}
建立用於實現 xref:Microsoft.Extensions.Configuration.IConfigurationSource 的類。
EFConfigurationProvider/EFConfigurationSource.cs:
public class EFConfigurationSource : IConfigurationSource
{
private readonly Action<DbContextOptionsBuilder> _optionsAction;
public EFConfigurationSource(Action<DbContextOptionsBuilder> optionsAction)
{
_optionsAction = optionsAction;
}
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new EFConfigurationProvider(_optionsAction);
}
}
通過從 ConfigurationProvider
繼承來建立自定義配置提供程式。 當資料庫為空時,配置提供程式將對其進行初始化。
EFConfigurationProvider/EFConfigurationProvider.cs:
public class EFConfigurationProvider : ConfigurationProvider
{
public EFConfigurationProvider(Action<DbContextOptionsBuilder> optionsAction)
{
OptionsAction = optionsAction;
}
Action<DbContextOptionsBuilder> OptionsAction { get; }
// Load config data from EF DB.
public override void Load()
{
var builder = new DbContextOptionsBuilder<EFConfigurationContext>();
OptionsAction(builder);
using (var dbContext = new EFConfigurationContext(builder.Options))
{
dbContext.Database.EnsureCreated();
Data = !dbContext.Values.Any()
? CreateAndSaveDefaultValues(dbContext)
: dbContext.Values.ToDictionary(c => c.Id, c => c.Value);
}
}
private static IDictionary<string, string> CreateAndSaveDefaultValues(
EFConfigurationContext dbContext)
{
// Quotes (c)2005 Universal Pictures: Serenity
// https://www.uphe.com/movies/serenity
var configValues = new Dictionary<string, string>
{
{ "quote1", "I aim to misbehave." },
{ "quote2", "I swallowed a bug." },
{ "quote3", "You can't stop the signal, Mal." }
};
dbContext.Values.AddRange(configValues
.Select(kvp => new EFConfigurationValue
{
Id = kvp.Key,
Value = kvp.Value
})
.ToArray());
dbContext.SaveChanges();
return configValues;
}
}
可以使用 AddEFConfiguration
擴充套件方法將配置源新增到 ConfigurationBuilder
。
Extensions/EntityFrameworkExtensions.cs:
public class EFConfigurationSource : IConfigurationSource
{
private readonly Action<DbContextOptionsBuilder> _optionsAction;
public EFConfigurationSource(Action<DbContextOptionsBuilder> optionsAction)
{
_optionsAction = optionsAction;
}
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new EFConfigurationProvider(_optionsAction);
}
}
下面的程式碼演示如何在 Program.cs
中使用自定義的 EFConfigurationProvider
:
public class Program
{
public static Dictionary<string, string> arrayDict = new Dictionary<string, string>
{
{"array:entries:0", "value0"},
{"array:entries:1", "value1"},
{"array:entries:2", "value2"},
{"array:entries:4", "value4"},
{"array:entries:5", "value5"}
};
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(Directory.GetCurrentDirectory());
config.AddInMemoryCollection(arrayDict);
config.AddJsonFile("json_array.json", optional: false, reloadOnChange: false);
config.AddJsonFile("starship.json", optional: false, reloadOnChange: false);
config.AddXmlFile("tvshow.xml", optional: false, reloadOnChange: false);
config.AddEFConfiguration(options => options.UseInMemoryDatabase("InMemoryDb"));
config.AddCommandLine(args);
})
.UseStartup<Startup>();
}
在啟動期間訪問配置
將 IConfiguration
注入 Startup
建構函式以訪問 Startup.ConfigureServices
中的配置值。 若要訪問 Startup.Configure
中的配置,請將 IConfiguration
直接注入方法或使用建構函式中的例項:
public class Startup
{
private readonly IConfiguration _config;
public Startup(IConfiguration config)
{
_config = config;
}
public void ConfigureServices(IServiceCollection services)
{
var value = _config["key"];
}
public void Configure(IApplicationBuilder app, IConfiguration config)
{
var value = config["key"];
}
}
有關使用啟動便捷方法訪問配置的示例,請參閱應用啟動:便捷方法
。
在 Razor Pages 頁或 MVC 檢視中訪問配置
若要訪問 Razor Pages 頁或 MVC 檢視中的配置設定,請為Microsoft.Extensions.Configuration 名稱空間
新增using 指令
(C# 參考:using 指令
)並將 IConfiguration
注入頁面或檢視。
在 Razor 頁面頁中:
@page
@model IndexModel
@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration
<!DOCTYPE html>
<html lang="en">
<head>
<title>Index Page</title>
</head>
<body>
<h1>Access configuration in a Razor Pages page</h1>
<p>Configuration value for 'key': @Configuration["key"]</p>
</body>
</html>
在 MVC 檢視中:
@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration
<!DOCTYPE html>
<html lang="en">
<head>
<title>Index View</title>
</head>
<body>
<h1>Access configuration in an MVC view</h1>
<p>Configuration value for 'key': @Configuration["key"]</p>
</body>
</html>
從外部程式集新增配置
通過 IHostingStartup
實現,可在啟動時從應用 Startup
類之外的外部程式集嚮應用新增增強功能。 有關更多資訊,請參見在 ASP.NET Core 中使用承載啟動程式集
。
相關文章
- ASP.NET Core 2.2 基礎知識(七)【選項】ASP.NET
- ASP.NET Core 2.2 基礎知識(十)【中介軟體】ASP.NET
- ASP.NET Core 2.2 基礎知識(十三)【伺服器】ASP.NET伺服器
- ASP.NET Core 2.2 基礎知識(八)【日誌記錄】ASP.NET
- ASP.NET Core 2.2 基礎知識(九)【處理錯誤】ASP.NET
- ASP.NET Core基礎知識(四)【路由】ASP.NET路由
- ASP.NET Core基礎知識(一)【概述】ASP.NET
- ASP.NET Core基礎知識(二)【應用啟動】ASP.NET
- 翻譯 - ASP.NET Core 基本知識 - 配置(Configuration)ASP.NET
- ASP.NET Core基礎知識(十一)【Host之Web 主機】ASP.NETWeb
- ASP.NET Core基礎知識(十四)【發出 HTTP 請求】ASP.NETHTTP
- ASP.NET Core 基礎知識(十二)【Host之通用主機】ASP.NET
- JavaSE基礎知識分享(六)Java
- WiFi基礎(六):天線基礎知識WiFi
- 六西格瑪的基礎知識
- ASP.NET Core基礎知識(三)【依賴關係注入(服務)】ASP.NET
- Java EE 基礎知識學習(六)Java
- ASP.NET程式安全的基礎知識ASP.NET
- ASP.NET Core基礎知識(五)【環境(開發、分階段、生產)】ASP.NET
- ASP.NET core 2.2 截圖ASP.NET
- Django基礎之六(模型理論知識)Django模型
- Java基礎知識回顧之六 —– IO流Java
- Java基礎知識回顧之六 ----- IO流Java
- 小范筆記:ASP.NET Core API 基礎知識與Axios前端提交資料筆記ASP.NETAPIiOS前端
- 基礎知識
- PyQt5 基礎知識(六):展示控制元件QT控制元件
- SAP SD 基礎知識之定價配置(Pricing Configuration)
- 一文了解.Net Core 3.1 Web API基礎知識WebAPI
- AI 基礎知識AI
- Webpack 基礎知識Web
- Dart基礎知識Dart
- RabbitMQ基礎知識MQ
- webpack基礎知識Web
- javascript基礎知識JavaScript
- ThinkPHP基礎知識PHP
- Laravel基礎知識Laravel
- Redis基礎知識Redis
- Docker基礎知識Docker