淺析.netcore中的Configuration具體使用

不管是.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");
}

到此這篇關於淺析.netcore中的Configuration具體使用的文章就介紹到這瞭,更多相關.net core Configuration內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: