• [译]ASP.NET 5 Configuration


    原文: https://docs.asp.net/en/latest/fundamentals/configuration.html

    ASP.NET 5支持多种配置选项。 应用的配置文件可以是JSON,XML,INI格式,也可以是来自系统环境变量。而且你还可以写自己的自定义configuration provider

    下载本文示例代码

    获取设置configuration

    ASP.NET 5的重构了之前依赖于System.Configuration和xml格式的配置文件(如web.config)。

    如果你在ASP.NET应用中使用setting的话,建议你只在你应用的Startup类中实例化Configuration。然后使用Option pattern进入独立的settings。

    最简单的说,Configuration就是一个source的集合,提供了读写键值对的功能。你最起码得给Configuration配置一个source。下面的代码展示如何使用Configuration做为一个键值对存储:

    // assumes using Microsoft.Framework.ConfigurationModel is specified
    var builder = new ConfigurationBuilder();
    builder.Add(new MemoryConfigurationSource());
    var config = builder.Build();
    config.Set("somekey", "somevalue");
    
    // do some other work
    
    string setting = config.Get("somekey"); // returns "somevalue"
    // or
    string setting2 = config["somekey"]; // also returns "somevalue"

    注意:

    你至少要设置一个source。

    通常我们的configuration键存在一个层级关系。ASP.NET5通过使用:号分隔来实现。例如,有如下的appsettings.json文件:

    {
      "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来获取ConnectionString的值。

    使用options pattern可以创建你自己的配置类,通过使用options service注入到你的应用中。

    注意:

    你可以将你的Configuration实例做为一个服务存储起来,但是这样以来你的系统依赖一个单一的configuration,而且所有的配置都在这个单一的configuration里面。可以使用过Options pattern 来避免这个问题。

    使用built-in providers

    configuration framework的built-it支持JSON, XML, 和INI配置文件,同样还支持内存configuraiton,环境变量configuratin和命令行参数的configuration。可以同时使用多种configuration source。

    使用ConfigurationBuilder类来添加configuration source。支持链式写法。

    var builder = new ConfigurationBuilder(".");
    builder.AddJsonFile("appsettings.json");
    builder.AddEnvironmentVariables();
    var config = builder.Build();

    上面configuration source的顺序非常重要,他决定了优先级。越后添加的configuration source优先级越高。在上面的例子中,如果appsetting.json和环境变量都设置了同一个键,环境变量这个source的优先级会高,会使用环境变量中对应的键值覆盖appsettings.json中的键值。

    注意:

    环境变量不支持:,我们使用__(两个下划线)来代替。

    针对不同的环境(debug,release,test)使用不同的配置文件非常有用。可以通过下面的例子来实现。

    public Startup(IHostingEnvironment env)
    {
        // Set up configuration sources.
        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();
    }

    IHostingEnviroment被用来获取当前的环境。在Development环境中,上面的高亮的代码会是appsettings.Development.json,会使用这个文件的值来覆盖其他的文件的值。更多请见Working with Multiple Environments

    警告:

    你不应该在源代码或者配置文件中存储如密码一样的敏感数据。这样的敏感数据不应该在项目里面,这样你也不会意外的把他们提交到源代码仓储中去了。更多请见:Working with Multiple Environments and managing Safe Storage of Application Secrets

    下面的例子中在MemoryConfigurationSource中设置了username,但是被命令行参数的username覆盖了:

    using System;
    using System.Linq;
    using Microsoft.Framework.Configuration;
    
    namespace ConfigConsole
    {
        public class Program
        {
            public void Main(string[] args)
            {
                var builder = new ConfigurationBuilder();
                Console.WriteLine("Initial Config Sources: " + builder.Sources.Count());
    
                var defaultSettings = new MemoryConfigurationSource();
                defaultSettings.Set("username", "Guest");
                builder.Add(defaultSettings);
                Console.WriteLine("Added Memory Source. Sources: " + builder.Sources.Count());
    
                builder.AddCommandLine(args);
                Console.WriteLine("Added Command Line Source. Sources: " + builder.Sources.Count());
    
                var config = builder.Build();
                string username = config.Get("username");
    
                Console.WriteLine($"Hello, {username}!");
            }
        }
    }

    运行结果如下:

     

    使用Options和configuration对象

    使用Options 可以很方便的把任何类转换成一个配置类。 推荐你为不同的应用模块创建对应的配置对象,不要是整个应用只有一个配置对象。

    下面是一个简单的MyOptions类:

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

    Options可以通过使用IOptions<TOptions>注入到你的应用。如下:

    public class HomeController : Controller
    {
        public HomeController(IOptions<MyOptions> optionsAccessor)
        {
            Options = optionsAccessor.Options;
        }
    
        MyOptions Options { get; }
    
        public IActionResult Index()
        {
            return View(Options);
        }
    }

    关于依赖注入的信息见,Dependency Injection

    为了使用IOptions<TOption>,你需要在在startup类中有如下设置:

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

    index视图显示option的值:

     使用Configure<TOption>来配置你的Options。可以使用委托来配置你的options或者绑定你的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";
        });
    
        services.AddMvc();
    }

    当你绑定options到configuration,你options的每一个属性绑定成了configuration的键(property:subproperty:....)。例如,MyOptions.Option1属性绑定到了Options1这个键,读取appsettings.json文件的options1。注意了configuration的键是大小写不敏感的。


    每次调用Configuration<TOptions>都会添加一个IConfigureOptions<TOption>服务到服务容器。

    对同一个option类可以有多个IConfigureOptions<TOption>,他们的优先级同样依赖于add的顺序。上面的例子中appsettings.json有Option1和Option2,但是Option1的值被下面使用委托的覆盖了。

    写自定义providers

    除了使用the built-in configuration source providers,我们可以自己写一个自定义的provider。需要继承自ConfigurationSource。

    例子: Entity Framework Settings

    你可能希望将你的配置存储在数据库里面,通过使用Entity Framework来获取他们。下面的例子,我们创建一个简单的configuration source使用EF来读取来自数据库的键值对。

    首先定义ConfigurationValue实体。用来在数据库中存储配置:

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

    现在需要一个ConfigurationContext来做为DbContext:

    public class ConfigurationContext : DbContext
    {
        public ConfigurationContext(DbContextOptions options) : base(options)
        {
        }
    
        public DbSet<ConfigurationValue> Values { get; set; }
    }

    接下来,创建见一个继承自ConfigurationSource的configuration source。覆盖Load方法来加载配置:

    public class EntityFrameworkConfigurationSource : ConfigurationSource
    {
        public EntityFrameworkConfigurationSource(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;
        }
    }

    接下来,我们创建一个EntityFrameworkExtensions在里面添加IConfigurationBuilder的一个扩展方法,用于添加configuration source:

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

    使用自定义provider:

    public class Program
    {
        public 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.Get("key1"));
            Console.WriteLine("key2={0}", config.Get("key2"));
            Console.WriteLine("key3={0}", config.Get("key3"));
    
        }
    }

    结果如下:

  • 相关阅读:
    大组合取模之:1<=n<=m<=1e6,1<=p<=1e9
    大组合数取模之lucas定理模板,1<=n<=m<=1e9,1<p<=1e6,p必须为素数
    fzu2020( c(n,m)%p,其中n, m, p (1 <= m <= n <= 10^9, m <= 10^4, m < p < 10^9, p是素数) )
    lucas定理证明
    各类小公式
    x^a=b(mod c)求解x在[0,c-1]上解的个数模板+原根求法
    快速幂+乘模 模板
    hdu1695(容斥 or 莫比乌斯反演)
    poj1845(二分快速求等比数列模M和)
    2018JAVA面试题附答案
  • 原文地址:https://www.cnblogs.com/irocker/p/aspnet5-configuration.html
Copyright © 2020-2023  润新知