ASP.NET Core 中文文档 第三章 原理(7)配置

小分享:我有几张阿里云优惠券,用券购买或者升级阿里云相应产品最多可以优惠五折!领券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03



原文:Configuration
作者:Steve SmithDaniel Roth
翻译:刘怡(AlexLEWIS)
校对:孟帅洋(书缘)

ASP.NET Core 支持多种配置选项。应用程序配置数据内建支持读取 JSON、XML 和 INI 格式的配置文件和环境变量。你也可以编写自己的自定义配置提供程序

章节:

  • 获取和设置配置
  • 使用内建提供程序
  • 使用选项和配置对象
  • 编写自定义提供程序
  • 总结

访问或下载样例代码

获取和设置配置

ASP.NET Core 配置系统针对以前的 ASP.NET 版本(依赖于 System.Configuration 和 XML 配置文件(如 Web.config))进行了重新架构。新的配置模型提供了精简高效的通过检索多样化提供程序的获取基于键/值对配置的能力。应用程序和框架可以通过新的选择模式访问配置。

在 ASP.NET 应用程序中,建议你在应用程序的 Startup 类中只实例化一个 Configuration 实例。然后使用选择模式来访问各自的设置。

简单来说,Configuration 类只是一个提供了读写名/值对能力的 Providers 集合。你至少需要配置一个提供程序,使得 Configuration 能正常工作。下例演示了如何测试把 Configuration 作为一个键/值对存储来处理。

var builder = new ConfigurationBuilder();
builder.AddInMemoryCollection();
var config = builder.Build();
config["somekey"] = "somevalue";

// do some other work

var setting = config["somekey"]; // also returns "somevalue"

注意
你必须至少设置一个配置提供程序。

一般不会把配置值存储在一个有层次的结构中,尤其是使用外部文件(如 JSON、XML、INI)时。在此情况下,可以使用以 : 符号分隔(从层次结构的根开始)的键来取回配置值。以下面的 appsettings.json 文件为例:

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-WebApplication1-26e8893e-d7c0-4fc6-8aab-29b59971d622;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  }
}

应用程序使用 configuration 配置正确的连接字符串。可以通过键 Data:DefaultConnection:ConnectionString 来访问 ConnectionString 的设置。

应用程序所需要的设置和指定配置的机制(configuration 便是一例)都可通过使用选择模式解耦。创建自己的配置类(可以是几个不同的类,分别对应不同的配置组),而后通过选项服务注入到应用程序中。然后你就可以通过配置或其它你所选择的机制来设置了。

注意
你可将 Configuration 实例设计为一个服务,但这会导致不必要地把应用程序和配置系统与指定配置键耦合在一起。相反可通过选择模式来避免这一问题。

使用内建提供程序

配置框架已内建支持 JSON、XML 和 INI 配置文件,内存配置(直接通过代码设置值),从环境变量和命令行参数中拉取配置。开发者并不受限于必须使用单个配置提供程序。事实上可以把多个配置提供程序组合在一起,就像是用从当前存在的另一个配置提供程序中获取配置值覆盖默认配置一样。

扩展方法支持为配置添加额外的配置文件提供程序。这些方法能被独立的或链式的(如 fluent API)调用在 ConfigurationBuilder 实例之上,如下所示:

// work with with a builder using multiple calls
var builder = new ConfigurationBuilder();
builder.SetBasePath(Directory.GetCurrentDirectory());
builder.AddJsonFile("appsettings.json");
var connectionStringConfig = builder.Build();

// chain calls together as a fluent API
var config = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json")
    .AddEntityFrameworkConfig(options =>
        options.UseSqlServer(connectionStringConfig.GetConnectionString("DefaultConnection"))
    )
    .Build();

指定配置提供程序的顺序非常重要,这将影响它们的设置被应用的优先级(如果存在于多个位置)。上例中,如果相同的配置同时存在于 appsettings.json 和环境变量,则环境变量的设置将被最终使用。最后指定的配置提供程序将“获胜”(如果该设置存在于至少两处位置)。ASP.NET 团队建议最后指定环境变量,如此一来本地环境可以覆盖任何部署在配置文件中的设置。

注意
如果通过环境变量重写嵌套键,请把变量中键名的 : 替换为 __ (两个下划线)。

这对于指定环境的配置文件非常有用,这能通过以下代码来实现:

public Startup(IHostingEnvironment env)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
        .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 环境中,上例高亮行代码将寻找名为 appsettings.Development.json 的配置文件,并用其中的值覆盖当前存在的其它值。更多请参见 environments

警告
谨记,严禁把密码或其他敏感数据保存在代码或纯文本配置文件中,严谨在开发环境或测试环境中使用生产环境的机密数据(这些机密数据应当在项目树的外部被指定,这样就不会意外提交到仓库内)。移步了解更多 environments 和管理 Safe storage of app secrets during development

影响 Configuration 优先级顺序的一个因素是指定可被重写的默认值。在本控制台应用程序中,默认的 username 设置由 MemoryConfigurationProvider 指定,但如果命令行参数中有个 username 参数被传递给应用程序,它将被覆盖。在输出中可以看到程序的每一个步骤中有多少个配置提供程序在进行配置工作。

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Configuration;

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

            builder.AddInMemoryCollection(new Dictionary<string, string>
            {
                { "username", "Guest" }
            });

            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["username"];

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

当运行时,程序将显示默认值,除非使用命令行参数重写之。

使用选项和配置对象

通过使用选择模式(options pattern)你可将任何类或 POCO(Plain Old CLR Object)转换为设置类。推荐把你创建的配置根据应用程序的功能分解为多个配置对象,从而实现 ISP(Interface Segregation Principle,接口隔离原则,类只依赖于它们自己使用的配置设置)和 SoC(Separation of Concerns,关注分离,设置与应用程序相互隔离,减少彼此之间的干扰和影响)。

一个简单的 MyOptions 类如下所示:

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

通过 IOptions<TOptions> ,配置选项将被注入到应用程序中。比方说,如 controller 使用 IOptions<TOptions> 来访问需要在 Index 视图中渲染的配置:

public class HomeController : Controller
{
    private readonly IOptions<MyOptions> _optionsAccessor;      //手动高亮

    public HomeController(IOptions<MyOptions> optionsAccessor)  //手动高亮
    {
        _optionsAccessor = optionsAccessor;
    }                                                           //手动高亮

    // GET: /<controller>/
    public IActionResult Index() => View(_optionsAccessor.Value);
}

建议
更多请浏览 Dependency Injection

为设置 IOptions<TOption> 服务,你需在启动期间在 ConfigureServices 方法内调用 AddOptions() 扩展方法。

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

Index 视图将显示配置选项:

配置选项使用 Configure<TOption> 扩展方法。你可以通过委托或绑定配置选项的方式来进行配置:

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

    // Configure MyOptions using config by installing Microsoft.Extensions.Options.ConfigurationExtensions
    services.Configure<MyOptions>(Configuration);

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

    // Configure MySubOptions using a sub-section of the appsettings.json file
    services.Configure<MySubOptions>(Configuration.GetSection("subsection"));//手动高亮

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

当你通过绑定选项来配置选项类型的每一个属性,实际上是绑定到每一个配置键(比如 property:subproperty:...)。比方说,MyOptions.Option1 属性绑定到键 Option1,那么就会从 appsettings.json 中读取 option1 属性。注意,配置键是大小写不敏感的。

通过调用 Configure<TOption> 将一个 IConfigureOptions<TOption> 服务加入服务容器,是为了之后应用程序或框架能通过 IOptions<TOption> 服务来获取配置选项。若是想从其他途径(比如之前从数据库)获取配置,你可使用 ConfigureOptions<TOptions> 扩展方法直接指定经过定制的 IConfigureOptions<TOption> 服务。

同一个选项类型可以有多个 IConfigureOptions<TOption> 服务,届时将按顺序应用。在上中,Option1 和 Option2 都在 appsettings.json 中指定,但 Option1 的值最后被配置委托所覆盖。

编写自定义提供程序

除使用内建的配置提供程序,你也可自行定制。为此,你只需从 ConfigurationProvider 继承并使用来自你配置提供程序的配置来填充 Data 属性即可。

例子:Entity Framework 设置

你或许希望将应用程序的配置保存在数据库中,然后通过 EntityFramework(EF)来访问它们。保存这些配置值有很多办法可以选择,比方说一张简易表格,一列表示配置名、另一列表示配置的值。在本例中,我将创建一个简易的配置提供程序,通过 EF 从数据库中读取名值对(name-value pair)。

在开始之前我们先定义一个简单的 ConfigurationValue 实体模型用来表示存储在数据库中的配置值。

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

    public DbSet<ConfigurationValue> Values { get; set; } //手动高亮
}

然后需要一个 ConfigurationContext 用来通过 EF 存储和访问配置值

using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;

namespace CustomConfigurationProvider
{
    public class EntityFrameworkConfigurationSource : IConfigurationSource      //手动高亮
    {
        private readonly Action<DbContextOptionsBuilder> _optionsAction;

        public EntityFrameworkConfigurationSource(Action<DbContextOptionsBuilder> optionsAction)
        {
            _optionsAction = optionsAction;
        }

        public IConfigurationProvider Build(IConfigurationBuilder builder)      //手动高亮
        {                                                                       //手动高亮
            return new EntityFrameworkConfigurationProvider(_optionsAction);    //手动高亮
        }                                                                       //手动高亮
    }
}

接着,通过继承 ConfigurationProvider 创建一个定制的配置提供程序。配置数据由重写的 Load 方法(该方法将从配置数据库中读取所有配置数据)所提供。由于这是演示,所以配置提供程序需要自行初始化数据库(如果该数据库尚未创建并初始化)

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;

namespace CustomConfigurationProvider
{
    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 static 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 扩展方法来增加配置提供程序:

using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;

namespace CustomConfigurationProvider
{
    public static class EntityFrameworkExtensions
    {
        public static IConfigurationBuilder AddEntityFrameworkConfig(                   //手动高亮
            this IConfigurationBuilder builder, Action<DbContextOptionsBuilder> setup)
        {
            return builder.Add(new EntityFrameworkConfigurationSource(setup));
        }
    }
}

在下例中将演示如何在应用程序中使用此定制的 ConfigurationProvider。创建一个新的 [ConfigurationBuilder][ConfigurationBuilder1] 来设置配置提供程序。指定数据提供程序和连接字符串后,添加 EntityFrameworkConfigurationProvider 配置提供程序。那你如何配置连接字符串呢?当然也是使用配置了!添加 appsettings.json 作为配置提供者来引导建立 EntityFrameworkConfigurationProvider 。通过重用相同的 ConfigurationBuilder,在数据库中指定的任何配置都将覆盖 appsettings.json 中所指定的对应设置:

using System;
using System.IO;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;

namespace CustomConfigurationProvider
{
    public static class Program
    {
        public static void Main()
        {
            // work with with a builder using multiple calls
            var builder = new ConfigurationBuilder();
            builder.SetBasePath(Directory.GetCurrentDirectory());
            builder.AddJsonFile("appsettings.json");
            var connectionStringConfig = builder.Build();

            // chain calls together as a fluent API
            var config = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json")                //手动高亮
                .AddEntityFrameworkConfig(options =>            //手动高亮
                    options.UseSqlServer(connectionStringConfig.GetConnectionString("DefaultConnection"))                 //手动高亮
                )   //手动高亮
                .Build();

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

运行程序,看到所配置的值。

总结

ASP.NET Core 提供了非常灵活的配置模型,支持多种配置文件类型、命令行、内存和环境变量。它能与配置模型无缝协作,因此你可为你的应用程序或框架注入强类型配置。你也可以创建自己定制的配置提供程序,用于协同或取代内置提供程序,保证了最大程序的灵活性。

返回目录

参考页面:http://qingqingquege.cnblogs.com/p/5933752.html

时间: 2024-10-25 19:56:08

ASP.NET Core 中文文档 第三章 原理(7)配置的相关文章

ASP.NET Core 中文文档 第三章 原理(1)应用程序启动

原文:Application Startup 作者:Steve Smith 翻译:刘怡(AlexLEWIS) 校对:谢炀(kiler398).许登洋(Seay) ASP.NET Core 为你的应用程序提供了处理每个请求的完整控制.Startup 类是应用程序的入口(entry point),这个类可以设置配置(configuration)并且将应用程序将要使用的服务连接起来.开发人员可以在 Startup 类中配置请求管道,该管道将用于处理应用程序的所有请求. 章节: Startup 类 Co

ASP.NET Core 中文文档 第三章 原理(2)中间件

原文:Middleware 作者:Steve Smith.Rick Anderson 翻译:刘怡(AlexLEWIS) 校对:许登洋(Seay) 章节: 什么是中间件 用 IApplicationBuilder 创建中间件管道 内置中间件 编写中间件 扩展资源 查看或下载样例代码 什么是中间件 中间件是用于组成应用程序管道来处理请求和响应的组件.管道内的每一个组件都可以选择是否将请求交给下一个组件.并在管道中调用下一个组件之前和之后执行某些操作.请求委托被用来建立请求管道,请求委托处理每一个 H

ASP.NET Core 中文文档 第三章 原理(14)服务器

原文:Servers 作者:Steve Smith 翻译:谢炀(Kiler) 校对:许登洋(Seay).姚阿勇(Dr.Yao) ASP.NET Core 已完全从承载应用程序的 Web 服务器环境中分离.ASP.NET Core 可以承载于 IIS 和 IIS Express ,以及使用 Kestrel 和 WebListener HTTP Server 的自承载环境中.此外,开发人员和第三方软件供应商可以创建自定义的服务器来承载 ASP.NET Core 应用程序. 查看和下载示例代码 服务器

ASP.NET Core 中文文档 第三章 原理(5)错误处理

小分享:我有几张阿里云优惠券,用券购买或者升级阿里云相应产品最多可以优惠五折!领券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03 原文:Error Handling 作者:Steve Smith 翻译:谢炀(Kiler) 校对:高嵩(jack2gs).何镇汐 当你的ASP.NET应用发生错误的时候, 你可以采用本文所述的各种方法来处理这些问题. 章节: 配置错误处理页面

ASP.NET Core 中文文档 第四章 MVC(3.2)Razor 语法参考

原文:Razor Syntax Reference 作者:Taylor Mullen.Rick Anderson 翻译:刘怡(AlexLEWIS) 校对:何镇汐 什么是 Razor? Razor 是一种基于服务器端代码的可以转换为网页的标记语法.Razor 语法包括 Razor 标记.C# 和 HTML 组成.包含 Razor 的文件通常后缀名为 .cshtml . 渲染 HTML Razor 的默认语言是 HTML.从 Razor 渲染为 HTML 和直接一个 HTML 文件没啥区别,这种 R

[转]ASP.NET Core 中文文档 第四章 MVC(4.3)过滤器

本文转自:http://www.cnblogs.com/dotNETCoreSG/p/aspnetcore-4_4_3-filters.html 原文:Filters 作者:Steve Smith 翻译:刘怡(AlexLEWIS) 校对:何镇汐 ASP.NET MVC 过滤器 可在执行管道的前后特定阶段执行代码.过滤器可以配置为全局有效.仅对控制器有效或是仅对 Action 有效. 查看或下载演示代码. 过滤器如何工作? 不同的过滤器类型会在执行管道的不同阶段运行,因此它们各自有一套适用场景.根

ASP.NET Core中使用GraphQL - 第三章 依赖注入

ASP.NET Core中使用GraphQL ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间件 SOLID原则中的D表示依赖倒置原则.这个原则的内容是: 上层模块不应该直接依赖底层模块,而应该依赖其抽象 抽象不应该依赖于细节, 细节应该依赖抽象 来源:WIKIPEDIA 在一个模块中创建一个其他模块的实例会导致这个模块与其他模块之间的紧耦合. 为了让不同的模块解耦,我们需要遵循依赖倒置原则.按照这种

ASP.NET Core 中文文档 第二章 指南(3)用 Visual Studio 发布一个 Azure

小分享:我有几张阿里云优惠券,用券购买或者升级阿里云相应产品最多可以优惠五折!领券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03 原文:Getting Started 作者:Rick Anderson 翻译:谢炀(Kiler) 校对:孟帅洋(书缘).刘怡(AlexLEWIS).何镇汐 设置开发环境 安装最新版本的 Azure SDK for Visual Studio 2

ASP.NET Core 中文文档 第二章 指南(4.1)ASP.NET Core MVC 与 Visua

参考页面: http://www.yuanjiaocheng.net/ASPNET-CORE/projectjson.html http://www.yuanjiaocheng.net/ASPNET-CORE/core-configuration.html http://www.yuanjiaocheng.net/ASPNET-CORE/core-middleware.html http://www.yuanjiaocheng.net/ASPNET-CORE/core-exception.htm