先上一段代碼,了解一下 .NET Core 配置資料的結構.
建立一個 控制台項目,添加一個檔案 json.json ,檔案内容如下:
{"country": "cn","person": {"id": 1,"address": {"addName": "chengdu"}
}
}
控制台代碼:
private static void Main(string[] args)
{
ConfigurationBuilder builder= newConfigurationBuilder();
builder.AddJsonFile(path:@"E:\xxx\my\core\VS2017\MyConfig\Demo2\json.json", optional: false, reloadOnChange: true);
IConfigurationRoot config=builder.Build();
Console.WriteLine(config["country"]);//cn
Console.WriteLine(config["person:id"]);//1
Console.WriteLine(config["person:address:addname"]);//chengdu
Console.ReadKey();//修改 json.json 檔案中 "id":2
Console.WriteLine(config["person:id"]);//2
Console.ReadKey();
}
AddJsonFile 方法有多個重載,上面隻給出了其中一個,3個參數分别表示:
path:檔案的實體路徑;
optional: xml 文檔是這樣寫的:Whether the file is optional. 該檔案是否可選.true 表示可選,即如果該檔案不存在,不會抛出異常,下面的所有顯示都為空;false 表示不可選,即如果該檔案不存在,會抛出異常.
reloadOnChange:如果檔案修改了,是否重新加載.
配置提供程式
ASP.NET Core 常用的共有6種配置提供程式 :
指令行配置提供程式
環境變量配置提供程式
檔案配置提供程式
Key-per-file配置提供程式
記憶體配置提供程式
自定義配置提供程式
一.指令行配置提供程式 :AddCommandLine
1.建立一個 WebAPI 項目,建立一個 TestController
[Route("api/[controller]")]
[ApiController]public classTestController : ControllerBase
{private readonlyIConfiguration _config;publicTestController(IConfiguration configuration)
{
_config=configuration;
}public stringGet()
{//讀取配置資料中 Key 為 CommandLineKey 的值,如果沒有這個 Key,則傳回預設值: defaultValue
//讀取配置檔案的方法後面會單獨講.
return _config.GetValue("CommandLineKey","defaultValue");
}
}
2.修改 CreateWebHostBuilder 方法
public classProgram
{public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{var config = newConfigurationBuilder().AddCommandLine(args).Build();var hostBuilder =WebHost.CreateDefaultBuilder(args);return hostBuilder.UseConfiguration(config).UseStartup();
}
}
3.測試:
1)不傳參數
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5yYkRWM1QzY0kjY4YDMmJWNjFmZjZGOxE2M4QDNyADOi9CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
2)傳入參數
傳參的格式有多種:
dotnet run CommandLineKey1=Value1
dotnet run --CommandLineKey2=Value2
dotnet run --CommandLineKey3 Value3
dotnet run /CommandLineKey4=Value4
dotnet run /CommandLineKey5 Value5
此外,傳入的以單橫杠"-"或者雙橫杠"--"作為字首的 Key 支援替換:
public classProgram
{public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
Dictionary switchMapping = new Dictionary{
{"-key", "CommandLineKey"},
{"--key", "CommandLineKey"},
};
IConfigurationRoot config= newConfigurationBuilder().AddCommandLine(args, switchMapping).Build();return WebHost.CreateDefaultBuilder().UseConfiguration(config).UseStartup();
}
}
測試圖:
兩種情況都會顯示
實際上,在 2.X 版本,CreateDefaultBuilder(args) 方法内部已經調用了 AddCommandLine(args) 方法,我們不需要再調一次了.源碼(部分)如下:
二.環境變量配置提供程式 : AddEnvironmentVariables
在 2.X 版本,CreateDefaultBuilder(args) 方法内部已經調用了 AddEnvironmentVariables() 方法,我們不需要再調一次了.源碼(部分)如下:
其實,紅框框起來的方法都是配置提供程式.
那麼,環境變量到底有哪些呢?哪裡可以看呢?
建立如下控制器:
[Route("api/[controller]/[action]")]
[ApiController]public classTestController : ControllerBase
{private readonlyIConfiguration _config;publicTestController(IConfiguration configuration)
{
_config=configuration;
}public IEnumerable>GetAll()
{return_config.AsEnumerable();
}public string Get(stringkey)
{return _config.GetValue(key, "defaultValue");
}
}
太多了,隻截了其中一小部分:
我們試試查詢紅框标注的環境變量:
三.檔案配置提供程式 : AddJsonFile , AddIniFile , AddXmlFile
以 AddJsonFile 為例講解,其他兩個都差不多.
從上面的源碼截圖中我們已經看到,在使用 CreateDefaultBuilder 方法初始化新的 WebHostBuilder 時,會自動調用 AddJsonFile 兩次,依次從下面兩個檔案加載配置:
appsettings.json : 首先讀取該檔案.
appsettings.{Environment}.json : 再讀取此檔案,該檔案中的配置會替代 appsettings.json 檔案中的值.
示例: (紅色部分是自己加的)
appsettings.json:
{"Logging": {"LogLevel": {"Default": "Warning"}
},"AllowedHosts": "*","FirstSection": {
"SecondSection": "hello world"}
}
appsettings.{Environment}.json:
{"Logging": {"LogLevel": {"Default": "Debug","System": "Information","Microsoft": "Information"}
},"FirstSection": {
"SecondSection": "fuck u"}
}
請求結果:
下面我們來建立自己的配置檔案:
在目前項目下建立一個 jsonconfig.json 檔案:
{"id": 1,"name": "wjire"}
CreateWebHostBuilder 方法修改如下:
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
IWebHostBuilder hostBuilder=WebHost.CreateDefaultBuilder(args);return hostBuilder.ConfigureAppConfiguration((context, builder) =>{
builder.AddJsonFile(Path.Combine(context.HostingEnvironment.ContentRootPath,"jsonconfig.json"),true, true);
}).UseStartup();
}
圖就不上了...
附:
AddIniFile 配置檔案:
[section0]
key0=value
key1=value
[section1]
subsection:key=value
[section2:subsection0]
key=value
[section2:subsection1]
key=value
AddXmlFile 配置檔案
value
value
value
value
四.Key-per-file 配置提供程式 AddKeyPerFile
這個提供程式有點特别,它是将檔案名(含擴充名)作為 Key,檔案内容作為 Value.
示例:
在目前項目下建立一個 filename.txt 檔案,檔案内容就一句話: hello world
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
IWebHostBuilder hostBuilder=WebHost.CreateDefaultBuilder(args);return hostBuilder.ConfigureAppConfiguration((context, builder) =>{//param1:檔案所在目錄的實體路徑//param2:該檔案是否可選
builder.AddKeyPerFile(context.HostingEnvironment.ContentRootPath, true);
}).UseStartup();
}
控制器如下:
[Route("api/[controller]/[action]")]
[ApiController]public classTestController : ControllerBase
{private readonlyIConfiguration _config;publicTestController(IConfiguration configuration)
{
_config=configuration;
}public string Get(stringkey)
{return _config.GetValue(key, "defaultValue");
}
}
五. 記憶體配置提供程式 AddInMemoryCollection
這個很簡單,直接上圖:
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
Dictionary memoryCollection = new Dictionary{
{"id","1"},
{"name","wjire"}
};
IWebHostBuilder hostBuilder=WebHost.CreateDefaultBuilder(args);return hostBuilder.ConfigureAppConfiguration((context, builder) =>{
builder.AddInMemoryCollection(memoryCollection);
}).UseStartup();
}
六.自定義配置提供程式
該示例示範了如果使用EF建立從資料庫(MySql)讀取配置的提供程式.
第一步:安裝 MySqlEF
第二步:建立資料庫表:
CREATE TABLE `myconfigs` (
`Id` varchar(20) NOT NULL DEFAULT '',
`value` varchar(20) NOT NULL DEFAULT '',
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
第三步:建立實體類
public classMyConfig
{public string Id { get; set; }public string Value { get; set; }
}
第四步:建立資料庫上下文
public classMyConfigContext : DbContext
{public MyConfigContext(DbContextOptions options) : base(options)
{
}public DbSet MyConfigs { get; set; }
}
第五步:建立配置資料源
public classMyConfigSource : IConfigurationSource
{private readonly Action_optionsAction;public MyConfigSource(ActionoptionsAction)
{
_optionsAction=optionsAction;
}publicIConfigurationProvider Build(IConfigurationBuilder builder)
{return newMyConfigProvider(_optionsAction);
}
}
第六步:建立配置資料源提供器
public classMyConfigProvider : ConfigurationProvider
{private Action OptionsAction { get; }public MyConfigProvider(ActionoptionsAction)
{
OptionsAction=optionsAction;
}//從資料庫讀取配置
public override voidLoad()
{
DbContextOptionsBuilder builder = new DbContextOptionsBuilder();
OptionsAction(builder);using (MyConfigContext dbContext = newMyConfigContext(builder.Options))
{//Data 是基類 ConfigurationProvider 的屬性,用來存儲配置資料源的.
Data = !dbContext.MyConfigs.Any()//判斷表是否有資料
? CreateAndSaveDefaultValues(dbContext)//如果沒有資料,則添加一些資料,存儲到配置資料源中.
: dbContext.MyConfigs.ToDictionary(c => c.Id, c => c.Value);//如果有資料,讀取出來,存儲到配置資料源中.
}
}private static IDictionaryCreateAndSaveDefaultValues(MyConfigContext dbContext)
{
Dictionary configValues = new Dictionary{
{"1", "refuge"},
{"2", "36"},
{"3", "chengdu"}
};
dbContext.MyConfigs.AddRange(configValues.Select(kvp=> newMyConfig
{
Id=kvp.Key,
Value=kvp.Value
}).ToArray());
dbContext.SaveChanges();returnconfigValues;
}
}
第七步:建立擴充方法,對外公開自定義的資料提供程式
public static classMyConfigExtension
{public static IConfigurationBuilder AddCustomConfigurationProviderApp(this IConfigurationBuilder builder, ActionoptionsAction)
{return builder.Add(newMyConfigSource(optionsAction));
}
}
第八步:建立測試用的控制器
[Route("api/[controller]/[action]")]
[ApiController]public classTestController : ControllerBase
{private readonlyIConfiguration _config;publicTestController(IConfiguration configuration)
{
_config=configuration;
}//查詢所有
public IEnumerable>GetAll()
{return_config.AsEnumerable();
}//查詢某個key
public string Get(stringkey)
{return _config.GetValue(key, "defaultValue");
}
}
第九步:調用自定義配置提供程式
public classProgram
{public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
IWebHostBuilder hostBuilder=WebHost.CreateDefaultBuilder(args);return hostBuilder.ConfigureAppConfiguration((context, builder) =>{
builder.AddCustomConfigurationProviderApp(options=> options.UseMySql("Server=localhost;Database=test;User=root"));
}).UseStartup();
}
}
測試結果:
1)查詢所有,可以看到,我們新增的配置資料已經加到系統中了;(看右邊的滾動條就知道總共有很多很多配置...)
2)查詢特定key
如果使用該方式提供配置資料,需要注意以下兩點:
1.提供程式在啟動時就将資料庫表讀入配置,不會基于每個key查詢資料庫;
2.應用啟動後,更新資料庫,配置不會更新.
上面講了如果提供配置資料,下面講擷取配置的幾種常用方法:
一.GetValue 上面已經示範過了,這裡不再重複.隻把常用的重載方法列出來
GetValue("key") 如果 key 不存在,則會抛異常;
GetValue("key",T default) 如果 key 不存在,則傳回預設值
二. T Get()
對于下面這個 json 檔案:
{"name": "refuge","age": 36,"address": {"city": "chengdu"}
}
定義一個實體:
public classPerson
{public string Name { get; set; }public int Age { get; set; }public Address Address { get; set; }
}public classAddress
{public string City { get; set; }
}
控制器:
[Route("api/[controller]/[action]")]
[ApiController]public classTestController : ControllerBase
{private readonlyIConfiguration _config;publicTestController(IConfiguration configuration)
{
_config=configuration;
}public stringGet()
{var person = _config.Get();returnJsonConvert.SerializeObject(person);
}
}
調用結果:
但是這種方式,個人持反對态度,因為存儲在系統中的配置資料有很多很多,上述方法相當于讀取所有配置資料來反序列化.
三.GetSection
講該方法之前,有必要再熟悉一下配置在系統中的存儲結構到底是怎麼樣的.
對于上面那個 json 檔案:name": "refuge",
"age": 36,"address": {"city": "chengdu"}
}
将其讀入配置後,存儲的結構如下:
{"key":"name","value":"refuge"}
{"key":"age","value":"36"}
{"key":"address","value":null} //通過查詢所有配置,确實有這一行,這意味着想通過 GetValue("address") 反序列化為對象是不可能的...
{"key":"address:city","value":"chengdu"}]
對于上面這些配置,"refuge" 和 "36" 是可以通過第一個方法 GetValue("name") , GetValue("age") 來擷取.
而 "chengdu" 隻能用 GetValue("address:city") 方法擷取了.
是以,要通過該方法把上述json檔案的内容轉成 Person 對象,則需要對 json 檔案進行修改,添加一個 "person" 節點:
{"person": {"name": "refuge","age": 36,"address": {"city": "chengdu"}
}
}
Action:
public stringGet()
{//方法一:
{
Person person= _config.GetSection("person").Get();returnJsonConvert.SerializeObject(person);
}//方法二:
{//Person person = new Person();//_config.GetSection("person").Bind(person);//return JsonConvert.SerializeObject(person);
}
}
方法一明顯要帥氣得多!
問題又來了,如果我隻想反序列化 "address" 節點的值,怎麼辦呢?下面這個方法可以完成.
四.GetChildren
Action:
public stringGet()
{
IConfigurationSection firstChildSection= _config.GetSection("person").GetChildren().First();
Address address= firstChildSection.Get
();returnJsonConvert.SerializeObject(address);
}
貌似完了.
2019年1月6日補充:
上面提到的全是從目前項目加載配置,ASP.NET Core 2.0 提供了從外部程式集加載配置的方法
需要實作該接口:
public interfaceIHostingStartup
{
voidConfigure(IWebHostBuilder builder);
}
示例:
建立類庫 : ExternalAssembly
namespaceExternalAssembly
{public classExternalConfig : IHostingStartup
{public voidConfigure(IWebHostBuilder builder)
{
Dictionary memoryCollection = new Dictionary{
{"id","1"},
{"name","refuge"}
};
builder.ConfigureAppConfiguration((context, configBuilder)=>{
configBuilder.AddInMemoryCollection(memoryCollection);
});
}
}
}
這裡要特别注意:
ConfigureAppConfiguration 方法需要安裝nuget包:
建立一個 WebAPI 項目,添加對上述類庫的引用,并在 Program 類中添加對該類庫的調用聲明(紅色标注):
usingMicrosoft.AspNetCore;usingMicrosoft.AspNetCore.Hosting;
[assembly: HostingStartup(typeof(ExternalAssembly.ExternalConfig))]namespaceDemo5
{public classProgram
{public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{return WebHost.CreateDefaultBuilder(args).UseStartup();
}
}
}
圖就不上了.