不管是.net還是.netcore專案,我們都少不了要讀取組態檔,在.net中專案,配置一般就存放在web.config中,但是在.netcore中我們新建的專案根本就看不到web.config,取而代之的是appsetting.json,
新建一個webapi專案,可以在startup中看到一個IConfiguration,通過框架自帶的IOC使用建構式進行實體化,在IConfiguration中我們發現直接就可以讀取到appsetting.json中的配置項了,如果在控制器中需要讀取配置,也是直接通過構造
函式就可以實體化IConfiguration物件進行配置的讀取,下面我們試一下運行的效果,在appsetting.json添加一個配置項,在action中可以進行訪問,

添加其他組態檔
那我們的配置項是不是只能寫在appsetting.json中呢?當然不是,下面我們看看如何添加其他的檔案到配置項中,根據官網教程,我們可以使用ConfigureAppConfiguration實作,
首先我們在專案的根目錄新建一個config.json,然后在其中隨意添加幾個配置,然后在program.cs中添加高亮顯示的部分,這樣很簡單的就將我們新增的json檔案中的配置加進來了,然后在程式中就可以使用IConfiguration進行訪問config.json
中的配置項了,
public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration(configure => { configure.AddJsonFile("config.json"); //無法熱修改 }) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); }
但是這個無法在配置項修改后讀取到最新的資料,我們可以呼叫多載方法configure.AddJsonFile("config.json",true,reloadOnChange:true)實作熱更新,
除了添加json檔案外,我們還可以使用AddXmlFile添加xml檔案,使用AddInMemoryCollection添加記憶體配置
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration((context,configure) => { Dictionary<string, string> memoryConfig = new Dictionary<string, string>(); memoryConfig.Add("memoryKey1", "m1"); memoryConfig.Add("memoryKey2", "m2"); configure.AddInMemoryCollection(memoryConfig); }) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
原始碼解讀:
在自動生成的專案中,我們沒有配置過如何獲取組態檔,那.netcore框架是怎么知道要appsetting.json組態檔的呢?我們通過查看原始碼我們就可以明白其中的道理,
Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); //CreateDefaultBuilder原始碼 public static IHostBuilder CreateDefaultBuilder(string[] args) { var builder = new HostBuilder(); builder.UseContentRoot(Directory.GetCurrentDirectory()); builder.ConfigureHostConfiguration(config => { config.AddEnvironmentVariables(prefix: "DOTNET_"); if (args != null) { config.AddCommandLine(args); } }); 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); } }); .... return builder; }
怎么樣?是不是很有意思,在原始碼中我們看到在Program中構建host的時候就會呼叫ConfigureAppConfiguration對應用進行配置,會讀取appsetting.json檔案,并且會根據環境變數加載不同環境的appsetting,同時還可以看到應用不僅添加了
appsetting的配置,而且添加了從環境變數、命令列傳入引數的支持,對于AddUserSecrets支持讀取用戶機密檔案中的配置,這個在存盤用戶機密配置的時候會用到,
那為什么我們可以通過再次呼叫ConfigureAppConfiguration去追加配置資訊,而不是覆寫呢?我們同樣可以在原始碼里面找到答案,
public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); }
//以下為部分原始碼 private List<Action<HostBuilderContext, IConfigurationBuilder>> _configureAppConfigActions = new List<Action<HostBuilderContext, IConfigurationBuilder>>();
private IConfiguration _appConfiguration; public IHostBuilder ConfigureAppConfiguration(Action<HostBuilderContext, IConfigurationBuilder> configureDelegate) { _configureAppConfigActions.Add(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate))); return this; } public IHost Build() { ... BuildAppConfiguration(); ... } private void BuildAppConfiguration() { var configBuilder = new ConfigurationBuilder() .SetBasePath(_hostingEnvironment.ContentRootPath) .AddConfiguration(_hostConfiguration, shouldDisposeConfiguration: true); foreach (var buildAction in _configureAppConfigActions) { buildAction(_hostBuilderContext, configBuilder); } _appConfiguration = configBuilder.Build(); _hostBuilderContext.Configuration = _appConfiguration; }
框架宣告了一個List<Action<HostBuilderContext, IConfigurationBuilder>>,我們每次呼叫ConfigureAppConfiguration都是往這個集合中添加元素,等到Main函式呼叫Build的時候會觸發ConfigurationBuilder,將集合中的所有元素進行回圈追加
到ConfigurationBuilder,最后就形成了我們使用的IConfiguration,這樣一看對于.netcore中IConfiguration是怎么來的就很清楚了,
讀取層級配置項
如果需要讀取組態檔中某個層級的配置應該怎么做呢?也很簡單,使用IConfiguration["key:childKey..."]
比如有這樣一段配置:
"config_key2": { "config_key2_1": "config_key2_1", "config_key2_2": "config_key2_2" }
可以使用IConfiguration["config_key2:config_key2_1"]來獲取到config_key2_1的配置項,如果config_key2_1下還有子配置項childkey,依然可以繼續使用:childkey來獲取
選項模式獲取配置項
選項模式使用類來提供對相關配置節的強型別訪問,將組態檔中的配置項轉化為POCO模型,可為開發人員撰寫代碼提供更好的便利和易讀性
我們添加這樣一段配置:
"Student": { "Sno": "SNO", "Sname": "SNAME", "Sage": 18, "ID": "001" }
接下來我們定義一個Student的Model類
public class Student { private string _id; public const string Name = "Student"; private string ID { get; set; } public string Sno { get; set; } public string Sname { get; set; } public int Sage { get; set; } }
可以使用多種方式來進行系結:
1、使用Bind方式系結
Student student = new Student(); _configuration.GetSection(Student.Name).Bind(student);
2、使用Get方式系結
var student1 = _configuration.GetSection(Student.Name).Get<Student>(binderOptions=> {
binderOptions.BindNonPublicProperties = true;
});
Get方式和Bind方式都支持添加一個 Action<BinderOptions>的多載,通過這個我們配置系結時的一些配置,比如非公共屬性是否系結(默認是不系結的),但是Get比BInd使用稍微方便一些,如果需要系結集合也是一樣的道理,將Student
替換成List<Student>,
3、全域方式系結
前兩種方式只能在區域生效,要想做一次配置系結,任何地方都生效可用,我們可以使用全域系結的方式,全域系結在Startup.cs中定義
services.Configure<Student>(Configuration.GetSection(Student.Name));
此方式會使用選項模式進行配置系結,并且會注入到IOC中,在需要使用的地方可以在建構式中進行實體化
private readonly ILogger<WeatherForecastController> _logger; private readonly IConfiguration _configuration; private readonly Student _student; public WeatherForecastController(ILogger<WeatherForecastController> logger, IConfiguration configuration, IOptions<Student> student) { _logger = logger; _configuration = configuration; _student = student.Value; }
命名選項的使用
對于不同的配置節,包含的配置項一樣時,我們在使用選項系結的時候無需定義和注入兩個類,可以在系結時指定名稱,比如下面的配置:
"Root": { "child1": { "child_1": "child1_1", "child_2": "child1_2" }, "child2": { "child_1": "child2_1", "child_2": "child2_2" } }
public class Root
{
public string child_1{get;set;}
public string child_2{get;set;}
} services.Configure<Root>("Child1",Configuration.GetSection("Root:child1")); services.Configure<Root>("Child2", Configuration.GetSection("Root:child2")); private readonly ILogger<WeatherForecastController> _logger; private readonly IConfiguration _configuration; private readonly Student _student; private readonly Root _child1; private readonly Root _child2; public WeatherForecastController(ILogger<WeatherForecastController> logger, IConfiguration configuration, IOptions<Student> student,IOptionsSnapshot<Root> root) { _logger = logger; _configuration = configuration; _student = student.Value; _child1 = root.Get("Child1"); _child2 = root.Get("Child2"); }
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/393009.html
標籤:C#
上一篇:使用navArgs將Fragment轉換為DialogFragment,如何從Fragment類外部導航到DialogFragment
