ASP.NET Core 1.0 基礎之配置


來源https://docs.asp.net/en/latest/fundamentals/configuration.html

ASP.NET Core 1.0支持不同的配置選項。應用配置數據可以是來自Json,XML,INI等格式,這些格式都是內建支持。當然配置數據也可以來自環境變量。你也可以寫自己的環境provider

你可以從Github下載樣例代碼

獲取和設置環境配置##

ASP.NET Core 1.0的環境系統是經過重新設計的,不像之前的是依賴於System.Configuration和類似web.config之類的xml文件的。新的配置模型中,配置可以從不同的provider中獲取,並且這些設置是支持streamlined鍵值對獲取的。使用新的options pattern,應用和框架可以獲取配置。

為了處理配置問題,推薦的做法是在Startup類中,實例化一個Configuration對象,然后使用options pattern來接入不同的配置。

簡單來說,Configuration是一系列配置provider的集合,提供讀取和寫入鍵對值的功能。為了Configuration能正常工作,至少要配置一個provider。下例展示了怎樣測試作為鍵對值存儲的Configuration。

// assumes using Microsoft.Framework.ConfigurationModel is specified
var builder = new ConfigurationBuilder();
builder.Add(new MemoryConfigurationProvider());
var config = builder.Build();
config.Set("somekey", "somevalue");

// do some other work

string setting2 = config["somekey"]; // also returns "somevalue"

Note:你必須設置至少一個provider

通常情況下,配置數據是分層結構存儲的,尤其使用外部文件時,如Json,XML,INI等。在這種情況下,配置數據可以通過分隔符:來獲取。考慮如下配置文件

{
  "Data": {
    "DefaultConnection": {
      "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=aspnet5-WebApplication1-8479b9ce-7b8f-4402-9616-0843bc642f09;Trusted_Connection=True;MultipleActiveResultSets=true"
    }
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Verbose",
      "System": "Information",
      "Microsoft": "Information"
    }
  }
}

應用使用配置文件來配置連接字符串,獲取該值可以使用這樣的鍵Data:DefaultConnection:ConnectionString。
使用options pattern可以解耦應用所需的配置和獲取指定配置的機制。為了使用options pattern,你需要創建自己的設置類(或許是幾個不同的類,對應幾個不同的內聚的設置組),這樣你可以使用options 服務將他們注入你的應用。然后你可以使用configuration或者任何你選擇的機制來指定settings。
Note: 你可以將Configuration實例作為服務存儲起來,但是這會不必要地將你的應用和單一配置系統以及特定的配置keys耦合起來。你應該使用Options pattern來避免該問題。

使用內建的provider##

配置框架有內置的對JSON,XML和INI配置文件的支持,同樣的支持內存中的配置(直接在代碼中設置值),以及從環境配置和命令行參數中取得配置。開發者並不局限於一種provider。事實上,若干個provider可以一起使用,這樣的話默認的配置會被其他provider提供的配置所覆蓋(如果存在的話)。
通過擴展方法,可以實現對其他配置文件provider的支持。這些方法由ConfigurationBuilder單獨調用或者作為fluent API調用,如下

var config = builder.Build();

builder.AddEntityFramework(options => options.UseSqlServer(config["Data:DefaultConnection:ConnectionString"]));
config = builder.Build();

configuration providers的順序是很重要的,因為這決定了如果配置在多個位置的話,哪個配置將會被應用。如上例,如果同樣的值存在appsettings.json和環境變量中,環境變量中的配置將會被應用。如果配置存在多個位置,最后一個provider指定的值將會覆蓋之前的值。ASP.NET團隊推薦將環境變量的配置放在最后,這樣本地環境變量將會覆蓋任何被部署的配置文件。
Note: 在shell中通過環境變量覆蓋嵌套的值,並不支持“:”,而是使用“__”(double undercore)。

使用基於環境的配置文件是很有用的,如下

public Startup(IHostingEnvironment env)
{
    // Set up configuration providers.
    var builder = new ConfigurationBuilder()
        .AddJsonFile("appsettings.json")
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

    if (env.IsDevelopment())
    {
        // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
        builder.AddUserSecrets();
    }

    builder.AddEnvironmentVariables();
    Configuration = builder.Build();
}

IHostingEnvironment 服務用來獲取當前環境,如果在Development環境,第6行代碼將會查找appsettings.Development.json文件,如果存在的話,並使用其中的配置項來重寫其他的值,詳見Working with Multiple Environments

Warning:你絕對不應存儲密碼或其他敏感信息在provider代碼中或者配置文件中。你也不應該在開發和測試環境中使用生產環境密碼。事實上,這些信息應該在項目樹之外指定,這樣能避免偶然情況下將其提交到provider倉儲中。詳見Multiple Environments和管理Safe Storage of Application Secrets

一種可以利用Configuration優先級順序的方式是使用默認值,默認值可被覆蓋。在如下控制台程序中,username的默認值是在MemoryConfigurationProvider中指定的,如果命令行參數中提供了username的值,那么該值會被重寫。你可以查看多個Configuration provider在不同階段時,程序的輸出。

using System;
using System.Linq;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Memory;

namespace ConfigConsole
{
    public class Program
    {
        public void Main(string[] args)
        {
            var builder = new ConfigurationBuilder();
            Console.WriteLine("Initial Config Providers: " + builder.Providers.Count());

            var defaultSettings = new MemoryConfigurationProvider();
            defaultSettings.Set("username", "Guest");
            builder.Add(defaultSettings);
            Console.WriteLine("Added Memory Provider. Providers: " + builder.Providers.Count());

            builder.AddCommandLine(args);
            Console.WriteLine("Added Command Line Provider. Providers: " + builder.Providers.Count());

            var config = builder.Build();
            string username = config["username"];

            Console.WriteLine($"Hello, {username}!");
        }
    }
}

但程序運行時,除非命令行參數覆蓋,程序將會輸出默認值
default

使用Options和配置對象##

使用Options你可以輕易的將任何POCO類轉換成設置類。推薦的做法是,在應用中對應某種feature,創建一個良好解耦的配置對象。遵循接口隔離原則(ISP)的同時也滿足關注點分離(不同部分的配置是分開管理的,因此減少相互不利影響)。
如下一個簡單的MyOptions的例子

public class MyOptions
{
    public string Option1 { get; set; }
    public int Option2 { get; set; }
}

通過IOptions 服務可以將Options注入應用。例如,MVC controller利用IOptions 來獲取填充index視圖所需的配置。

public class HomeController : Controller
{
    public HomeController(IOptions<MyOptions> optionsAccessor)
    {
        Options = optionsAccessor.Value;
    }

    MyOptions Options { get; }

    // GET: /<controller>/
    public IActionResult Index()
    {
        return View(Options);
    }
}

更多詳見依賴注入
為了啟動IOpitons 服務,你需要在Startup類中ConfigureServices中調用擴展方法AddOptions()。

public void ConfigureServices(IServiceCollection services)
{
    // Setup options with DI
    services.AddOptions();
}

Index視圖顯示如下
index
通過擴展方法Configure 來配置選項。可以通過使用delegate或者綁定options到Configuration。

public void ConfigureServices(IServiceCollection services)
{
    // Setup options with DI
    services.AddOptions();

    // Configure MyOptions using config
    services.Configure<MyOptions>(Configuration);

    // Configure MyOptions using code
    services.Configure<MyOptions>(myOptions =>
    {
        myOptions.Option1 = "value1_from_action";
    });

    // Add framework services.
    services.AddMvc();

當綁定options到configuration時,配置類中的屬性綁定的key具有property:subproperty:...的形式。例如,MyOptions.Option1所綁定key就是Option1,它是從appsettings.json的option1鍵中讀取的。注意配置鍵是大小寫不敏感的。

每次調用Configure 都添加一個IConfigurations 到服務容器中,然后有IOptions 來將配置選項提供給應用或框架。如果你想使用別的方式直接配置選項(如從數據庫讀取設置),你可以直接使用ConfigureOptions<TOptions擴展方法來specify一個你自定義的IConfigureOptions 的服務。

對於同樣的配置選項,你可以使用多個IConfiguration 服務,他們會按順序起作用。在上例中Option1和Option2值都在appsettings.json中指定,但是option1的值會被configuration delegate所覆蓋。

寫自定義provider##

除了使用內建的configuration provider,你也可以編寫自己的。你只需要繼承ConfigurationProvider類,然后populate the Data property with the settings from your configuration provider。

例子:EF設置###

你可能希望存儲一些應用設置選項到數據庫中,使用EF來獲取它們。你可以有很多方式存儲設置,在本例中,我們創建一個簡單的configuration provider,來使用EF讀取數據庫中的name-value對。
首先我們定義ConfigurationValue,來存儲數據到數據庫中。

public class ConfigurationValue
{
    public string Id { get; set; }
    public string Value { get; set; }
}

我們還需要一個ConfigurationContext來使用EF存儲或獲取配置選項值。

public class ConfigurationContext : DbContext
{
    public ConfigurationContext(DbContextOptions options) : base(options)
    {
    }

    public DbSet<ConfigurationValue> Values { get; set; }

}

然后創建configuration provider。配置數據通過重寫Load方法來載入,它從數據庫中讀取所有的配置數據。為了演示的目的,如果數據庫沒有存在和populate,configuration provider會首先創建並初始化數據庫。

public class EntityFrameworkConfigurationProvider : ConfigurationProvider
{
    public EntityFrameworkConfigurationProvider(Action<DbContextOptionsBuilder> optionsAction)
    {
        OptionsAction = optionsAction;
    }

    Action<DbContextOptionsBuilder> OptionsAction { get; }

    public override void Load()
    {
        var builder = new DbContextOptionsBuilder<ConfigurationContext>();
        OptionsAction(builder);

        using (var dbContext = new ConfigurationContext(builder.Options))
        {
            dbContext.Database.EnsureCreated();
            Data = !dbContext.Values.Any()
                ? CreateAndSaveDefaultValues(dbContext)
                : dbContext.Values.ToDictionary(c => c.Id, c => c.Value);
        }
    }

    private IDictionary<string, string> CreateAndSaveDefaultValues(ConfigurationContext dbContext)
    {
        var configValues = new Dictionary<string, string>
            {
                { "key1", "value_from_ef_1" },
                { "key2", "value_from_ef_2" }
            };
        dbContext.Values.AddRange(configValues
            .Select(kvp => new ConfigurationValue() { Id = kvp.Key, Value = kvp.Value })
            .ToArray());
        dbContext.SaveChanges();
        return configValues;
    }
}

同時,我們還需要添加AddEntityFramework擴展方法來添加configuration provider

public static class EntityFrameworkExtensions
{
    public static IConfigurationBuilder AddEntityFramework(this IConfigurationBuilder builder, Action<DbContextOptionsBuilder> setup)
    {
        return builder.Add(new EntityFrameworkConfigurationProvider(setup));
    }
}

在下例中,你可以看到如何在應用中使用自定義configuration provider。創建ConfigurationBuilder 來setup你的configuration provders。添加EntityFrameworkConfigurationProvider來指定data provider和連接字符串。怎樣配置連接字符串呢?當然是使用配置,添加appsettings.json文件作為configuration provider來啟動EntityFrameworkConfigurationProvider。通過復用ConfigurationBuilder,數據中任何配置數據都能夠重寫appsettings.json中數據。

public class Program
{
    public static void Main(string[] args)
    {
        var builder = new ConfigurationBuilder();
        builder.AddJsonFile("appsettings.json");
        builder.AddEnvironmentVariables();
        var config = builder.Build();

        builder.AddEntityFramework(options => options.UseSqlServer(config["Data:DefaultConnection:ConnectionString"]));
        config = builder.Build();

        Console.WriteLine("key1={0}", config["key1"]);
        Console.WriteLine("key2={0}", config["key2"]);
        Console.WriteLine("key3={0}", config["key3"]);

    }
}

運行程序,可以看到如下結果
config

總結##

ASP.NET Core 1.0提供很大靈活性的配置模型,可以支持不同文件類型配置,以及命令行,內存和環境變量等配置。他可以與options無縫連接,所以你可以注入強類型的配置到應用或框架中。同時你也可以創建自己的configuration provider,來和內嵌的provider配合,或者取代它們。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM