ASP.NET Core配置教程之读取配置信息

提到“配置”二字,我想绝大部分.NET开发人员脑海中会立马浮现出两个特殊文件的身影,那就是我们再熟悉不过的app.config和web.config,多年以来我们已经习惯了将结构化的配置信息定义在这两个文件之中。到了.NET Core的时候,很多我们习以为常的东西都发生了改变,其中也包括定义配置的方式。总的来说,新的配置系统显得更加轻量级,并且具有更好的扩展性,其最大的特点就是支持多样化的数据源。我们可以采用内存的变量作为配置的数据源,也可以直接配置定义在持久化的文件甚至数据库中。

由于很多人都不曾接触过这个采用全新设计的配置系统,为了让大家对此有一个感官的认识,我们先从编程的角度对它作一个初体验。针对配置的API涉及三个对象,它们分别是Configuration、ConfigurationBuilder和ConfigurationProvider,配置模型中具有相应的接口来表示它们。这三个对象之间的关系很清晰,Configuration对象承载着在编程过程中使用的配置信息,ConfigurationProvider则是配置信息原始数据源的提供者,两者之间沟通由ConfigurationBuilder来完成,它利用ConfigurationProvider提取源数据将其转换为Configuration对象。

一、以键-值对的形式读取配置
虽然在大部分情况下的配置信息从整体来说都具有一个结构化的层次关系,但是“原子”配置项都以最简单的“键-值对”的形式来体现,并且键和值都是字符串,接下来我们会通过一个简单的实例来演示如何以键值对的形式来读取配置。我们创建一个针对ASP.NET Core的控制台应用,并在project.json中按照如下的方式添加针对“Microsoft.Extensions.Configuration”这个NuGet包的依赖,配置模型就实现在这个包中。

{
  ...
   "dependencies": {
   "Microsoft.Extensions.Configuration": "1.0.0-rc1-final"
  },
 }

假设我们的应用需要通过配置来设定日期/时间的显示格式,为此我们定义了如下一个DateTimeFormatSettings类,它的四个属性体现了DateTime对象的四种显示格式(分别为长日期/时间和短日期/时间)。

public class DateTimeFormatSettings
 {
    public string LongDatePattern { get; set; }
    public string LongTimePattern { get; set; }
    public string ShortDatePattern { get; set; }
   public string ShortTimePattern { get; set; }
   //其他成员
 }

我们希望通过配置的形式来控制由DateTimeFormatSettings的四个属性体现的日期/时间显示格式,所以我们为它定义了一个构造函数。如下面的代码片段所示,该构造函数具有一个IConfiguration接口类型的参数,它正式承载相关配置信息的Configuration对象。我们调用Configuration对象的索引并指定相应配置项的Key来得到其Value。

public class DateTimeFormatSettings
  {
   //其他成员
   public DateTimeFormatSettings (IConfiguration configuration)
    {
      this.LongDatePattern   = configuration["LongDatePattern"];
     this.LongTimePattern   = configuration["LongTimePattern"];
     this.ShortDatePattern  = configuration["ShortDatePattern"];
      this.ShortTimePattern  = configuration["ShortTimePattern"];
   }
 }

要创建一个体现当前配置的DateTimeFormatSettings对象,我们必须向得到这个承载相关配置信息的Configuration对象。正如我们上面所说,Configuration对象是由ConfigurationBuilder创建的,而原始的配置信息则是通过相应的ConfigurationProvider来读取的,所以创建一个Configuration对象的正确编程方式是先创建一个ConfigurationBuilder对象,然后为之添加一个或者多个ConfigurationProvider对象,最后利用ConfigurationBuilder来创建我们需要的Configuration对象。

按照上述的编程模式,我们在一个控制台应用中编写了如下的程序。我们创建了一个类型为ConfigurationBuilder的对象,调用其Add方法添加的ConfigurationProvider是一个类型为MemoryConfigurationProvider的对象。顾名思义,MemoryConfigurationProvider利用内存中的对象来提供原始的配置信息,具体来说这些原始的配置信息保存在一个元素类型为KeyValuePair<string, string>的集合之中。我们最终调用ConfigurationBuilder的Build方法获取用于创建DateTimeFormatSettings对象所需的Configuration。

public class Program
 {
    public static void Main(string[] args)
    {
      Dictionary<string, string> source = new Dictionary<string, string>
      {
        ["LongDatePattern"]   = "dddd, MMMM d, yyyy",
        ["LongTimePattern"]   = "h:mm:ss tt",
        ["ShortDatePattern"]  = "M/d/yyyy",
        ["ShortTimePattern"]  = "h:mm tt"
      };
      IConfiguration configuration = new ConfigurationBuilder()
          .Add(new MemoryConfigurationProvider(source))
          .Build();

      DateTimeFormatSettings settings = new DateTimeFormatSettings(configuration);
      Console.WriteLine("{0,-16}: {1}", "LongDatePattern", settings.LongDatePattern);
      Console.WriteLine("{0,-16}: {1}", "LongTimePattern", settings.LongTimePattern);
      Console.WriteLine("{0,-16}: {1}", "ShortDatePattern", settings.ShortDatePattern);
      Console.WriteLine("{0,-16}: {1}", "ShortTimePattern", settings.ShortTimePattern);
   }
 }

为了验证根据配置创建的DateTimeFormatSettings对象与配置原始数据之间的关系,我们将它的四个属性输出于控制台上。当这个程序执行之后将在控制台上产生如下所示的输出,可以看出它正是我们提供的配置的真实反映。
 LongDatePattern : dddd, MMMM d, yyyy
 LongTimePattern : h:mm:ss tt
 ShortDatePattern: M/d/yyyy
 ShortTimePattern: h:mm tt

二、 读取结构化的配置
真实项目中涉及的配置大都具有一个结构化的层次结构,所以在配置模型中的Configuration对象同样具有这样的结构。结构化的配置具有一个树形层次结构,而一个Configuration对象表示的是组成这棵配置树的某个节点,这棵配置树则可以通过作为根节点的Configuration对象来体现。体现为键值对的原子配置项一般至存在于作为叶子节点的Configuration对象中,非叶子节点的Configuration包含一组子节点,而每个子节点同样是一个Configuration对象。

接下来我们同样以实例的方式来演示如何定义并读取具有层次化结构的配置。我们依然沿用上一节的应用场景,现在我们不仅仅需要设置日期/时间的格式,还需要设置其他数据类型的格式,比如表示货币的Decimal类型。为此我们定义了如下一个CurrencyDecimalFormatSettings类,它的属性Digits和Symbol分别表示小数位数和货币符号,一个CurrencyDecimalFormatSettings对象依然是利用一个表示配置的Configuration对象来创建的。

 {
    public int   Digits { get; set; }
  public string Symbol { get; set; }

    public CurrencyDecimalFormatSettings(IConfiguration configuration)
   {
     this.Digits = int.Parse(configuration["Digits"]);
      this.Symbol = configuration["Symbol"];
   }
 }

我们定义了另一个名为FormatSettings的类型来表示针对不同数据类型的格式设置。如下面的代码片段所示,它的两个属性DateTime和CurrencyDecimal分别表示针对日期/时间和货币数字的格式设置。FormatSettings依然具有一个参数类型为IConfiguration接口的构造函数,它的两个属性均在此构造函数中被初始化。值得注意的是初始化这两个属性采用的是当前Configuration的“子配置节”,通过指定配置节名称调用GetSection方法获得。

public class FormatSettings
{
  public DateTimeFormatSettings      DateTime { get; set; }
   public CurrencyDecimalFormatSettings   CurrencyDecimal { get; set; }

   public FormatSettings(IConfiguration configuration)
    {
      this.DateTime = new DateTimeFormatSettings(configuration.GetSection("DateTime"));
      this.CurrencyDecimal = new CurrencyDecimalFormatSettings(configuration.GetSection("CurrencyDecimal"));
    }
}

在我们上面演示的实例中,我们通过以一个MemoryConfigurationProvider对象来提供原始的配置信息。由于承载原始配置信息的是一个元素类型为KeyValuePair<string, string>的集合,所以原始配置在物理存储上并不具有树形化的层次结构,那么它如何能够最终提供一个结构化的Configuration对象呢?其实很简单,虽然MemoryConfigurationProvider对象只能将配置信息存储为简单的“数据字典”,但是如果将Configuration对象在配置树中体现的路径作为Key,这个数据字典在逻辑上实际上就具有了一棵树的结构。实际上MemoryConfigurationProvider就是这么做的,这体现在我们如下所示的程序之中。

class Program
 {
   static void Main(string[] args)
   {
     Dictionary<string, string> source = new Dictionary<string, string>
     {
       ["Format:DateTime:LongDatePattern"]   = "dddd, MMMM d, yyyy",
       ["Format:DateTime:LongTimePattern"]   = "h:mm:ss tt",
       ["Format:DateTime:ShortDatePattern"]   = "M/d/yyyy",
       ["Format:DateTime:ShortTimePattern"]   = "h:mm tt",

       ["Format:CurrencyDecimal:Digits"]   = "2",
       ["Format:CurrencyDecimal:Symbol"]   = "$",
     };
     IConfiguration configuration = new ConfigurationBuilder()
         .Add(new MemoryConfigurationProvider(source))
         .Build();

     FormatSettings settings = new FormatSettings(configuration.GetSection("Format"));
     Console.WriteLine("DateTime:");
     Console.WriteLine("\t{0,-16}: {1}", "LongDatePattern", settings.DateTime.LongDatePattern);
     Console.WriteLine("\t{0,-16}: {1}", "LongTimePattern", settings.DateTime.LongTimePattern);
     Console.WriteLine("\t{0,-16}: {1}", "ShortDatePattern", settings.DateTime.ShortDatePattern);
     Console.WriteLine("\t{0,-16}: {1}\n", "ShortTimePattern", settings.DateTime.ShortTimePattern);

     Console.WriteLine("CurrencyDecimal:");
     Console.WriteLine("\t{0,-16}: {1}", "Digits", settings.CurrencyDecimal.Digits);
     Console.WriteLine("\t{0,-16}: {1}", "Symbol", settings.CurrencyDecimal.Symbol);
   }
}

如上面的代码片段所示,创建MemoryConfigurationProvider对象采用的字典对象包含6个基本的配置项,为了让它们在逻辑上具有一个树形化层次结构,所以的Key实际上体现了每个配置项所在配置节在配置树中的路径,路径采用冒号(“:”)进行分割。改程序执行之后会在控制台上呈现如下所示的输出结果。

DateTime:
    LongDatePattern : dddd, MMMM d, yyyy
    LongTimePattern : h:mm:ss tt
     ShortDatePattern: M/d/yyyy
    ShortTimePattern: h:mm tt

 CurrencyDecimal:
    Digits     : 2
    Symbol     : $

三、将结构化配置直接绑定为对象
在真正的项目开发过程中,我们都不会直接使用直接读取的配置,而都倾向于像我们演示的两个实例一样通过创建相应的类型(比如DateTimeFormatSettings、CurrencyDecimalSettings和FormatSettings)来定义一组相关的配置选项(Option),我们将定义配置选项(Option)的这些类型称为Option类型。在上面演示的实例中,为了创建这些封装配置的对象,我们都是采用手工读取配置的形式,如果定义的配置项太多的话,逐条读取配置项其实是一项非常繁琐的工作。

对于一个对象来说,如果我们将它的属性视为它的子节点,一个对象同样具有类似于Configuration对象的树形层次化结构。如果我们根据某个Option类型的结构来定义配置,或者反过来根据配置的结构来定义这个Option类型,那么Option类型的属性成员将与某个配置节具有一一对应的关系,那么原则上我们可以自动将配置信息绑定为一个具体的Option对象。

ASP.NET Core针对配置的Option模型(OptionModel)帮助我们实现了从配置到Option对象之间的绑定,接下来我们就对此做一个简单的演示。Option模型实现在“Microsoft.Extensions.OptionModel”这个NuGet包中,除此之外,我们需要采用依赖注入的方式来使用Option模型,所以我们需要按照如下的方式为应用添加针对相应的依赖。

 {
  ...
  "dependencies": {
  "Microsoft.Extensions.OptionsModel"    : "1.0.0-rc1-final",
  "Microsoft.Extensions.DependencyInjection"  : "1.0.0-rc1-final"
  },
 }

借助于Option模型的自动绑定机制,我们无需再手工地读取配置信息,所以我们将FormatSettings、DateTimeFormatSettings和CurrencyDecimalSettings的构造函数删除,只保留其属性成员。在作为程序入口的Main方法中,我们采用如下的方式创建这个表示格式设置的FormatSettings对象。

 class Program
{
   static void Main(string[] args)
   {
     Dictionary<string, string> source = new Dictionary<string, string>
     {
      ["Format:DateTime:LongDatePattern"] = "dddd, MMMM d, yyyy",
      ["Format:DateTime:LongTimePattern"] = "h:mm:ss tt",
      ["Format:DateTime:ShortDatePattern"] = "M/d/yyyy",
       ["Format:DateTime:ShortTimePattern"] = "h:mm tt",

       ["Format:CurrencyDecimal:Digits"] = "2",
       ["Format:CurrencyDecimal:Symbol"] = "$",
    };
    IConfiguration configuration = new ConfigurationBuilder()
         .Add(new MemoryConfigurationProvider(source))
         .Build()
         .GetSection("Format"));

     IOptions<FormatSettings> optionsAccessor = new ServiceCollection()
       .AddOptions()
       .Configure<FormatSettings>(configuration)
      .BuildServiceProvider()
      .GetService<IOptions<FormatSettings>>();

    FormatSettings settings = optionsAccessor.Value;

     Console.WriteLine("DateTime:");
     Console.WriteLine("\t{0,-16}: {1}", "LongDatePattern",settings.DateTime.LongDatePattern);
     Console.WriteLine("\t{0,-16}: {1}", "LongTimePattern",settings.DateTime.LongTimePattern);
     Console.WriteLine("\t{0,-16}: {1}", "ShortDatePattern",settings.DateTime.ShortDatePattern);
     Console.WriteLine("\t{0,-16}: {1}\n", "ShortTimePattern",settings.DateTime.ShortTimePattern);

     Console.WriteLine("CurrencyDecimal:");
     Console.WriteLine("\t{0,-16}: {1}", "Digits",settings.CurrencyDecimal.Digits);
     Console.WriteLine("\t{0,-16}: {1}", "Symbol",settings.CurrencyDecimal.Symbol);
   }
 }

如上面的代码片段所示,我们创建一个ServiceCollection对象并调用扩展方法AddOptions注册于针对Option模型的服务。接下来我们调用Configure方法将FormatSettings这个Option类型与对应的Configuration对象进行映射。我们最后利用这个ServiceCollection对象生成一个ServiceProvider,并调用其GetService方法得到一个类型为IOptions<FormatSettings>的对象,后者的Value属性返回的就是绑定了相关配置的FormatSettings对象。

以上就是本文的全部内容,希望对大家的学习有所帮助。

(0)

相关推荐

  • .NET Core 2.0迁移小技巧之web.config 配置文件示例详解

    前言 相信大家应该都知道.NET Core现在不再支持原来的web.config配置文件了,取而代之的是json或xml配置文件.官方推荐的项目配置方式是使用appsettings.json配置文件,这对现有一些重度使用web.cofig配置的项目迁移可能是不可接受的. 但是好消息是,我们是可以直接在.NET Core 2.0项目种利用上现有的web.config的.本文将详细介绍.NET Core 2.0迁移之web.config 配置文件的相关内容,下面话不多说了,来一起看看详细的介绍吧.

  • asp.net core中灵活的配置方式详解

    前言 asp.net core支持外部文件和命令行参数方式来配置系统运行所需要的配置信息,我们从下面两个常用场景来具体说下具体使用方法. 一.监听地址及端口配置 1,命令行方式 asp.net core系统通过命令行方式启动,使用的命令如下: dotnet run 上面的命令直接在源代码目录下执行,便可以编译程序并运行.那对于已经发布好的程序,就不能使用上面的指令了,应该使用下面的指令: dotnet 程序集文件名(程序集文件名就是程序发布后生成的dll文件) 上面两个指令都能够启动应用程序.程

  • ASP.NET Core配置教程之读取配置信息

    提到"配置"二字,我想绝大部分.NET开发人员脑海中会立马浮现出两个特殊文件的身影,那就是我们再熟悉不过的app.config和web.config,多年以来我们已经习惯了将结构化的配置信息定义在这两个文件之中.到了.NET Core的时候,很多我们习以为常的东西都发生了改变,其中也包括定义配置的方式.总的来说,新的配置系统显得更加轻量级,并且具有更好的扩展性,其最大的特点就是支持多样化的数据源.我们可以采用内存的变量作为配置的数据源,也可以直接配置定义在持久化的文件甚至数据库中. 由

  • 详解ASP.NET Core实现强类型Configuration读取配置数据

    前言 实现读取JSON文件几种方式,在项目中采取老办法简单粗暴,结果老大过来一看,恩,这样不太可取,行吧那我就用.NET Core中最新的方式诺,切记,适合的才是最好的,切勿懒. .NET Core读取JSON文件通过读取文件方式 当我将VS2015项目用VS2017打开后再添加控制器,此时会报错如下: 此时我们应该在该项目中的.csproj中添加如下这一句才能解决此问题: <ItemGroup> <DotNetCliToolReference Include="Microso

  • ASP.NET Core 2.0 WebApi全局配置及日志实例

    最新在将原来写的一些webSerivce转换为WebApi,直接就用了ASP.Net Core 2.0的框架,在使用中,发现的与原有的asp.net不同的地方,通过搜索已经慢慢解决,记录下来备用. 一.全局配置 在asp.net中,全局变更配置写在web.config中,如下所示 <?xml version="1.0"?> <configuration> <connectionStrings> <add name="conn"

  • 详解asp.net core重新加载应用配置

    asp.net core重新加载应用配置Intro 我把配置放在了数据库或者是Redis里,配置需要修改的时候我要直接修改数据库,然后调用一个接口去重新加载应用配置,于是就尝试写一个运行时重新加载配置的接口. Configuration 重新加载实现 重新加载配置的接口其实很简单,经过看 Configuration 的源码可以知道,如果想要重新加载应用配置,需要一个 IConfigurationRoot 对象,而 IConfigurationRoot 其实可以直接拿注入服务中的 IConfigu

  • ASP.NET CORE基础教程

    目录 第一课 基本概念 第二课 控制器的介绍 第三课 视图与表单 第四课 数据验证 第五课 路由规则 第六课 应用发布与部署 源码地址 第一课 基本概念 基本概念 Asp.Net Core Mvc是.NET Core平台下的一种Web应用开发框架 符合Web应用特点 .NET Core跨平台解决方案 MVC设计模式的一种实现 环境准备 安装最新版Visual Studio 2017 安装最新版.NET Core Sdk 第二课 控制器的介绍 控制器定义方式: 命名以Controller结尾 使用

  • 解决springboot利用ConfigurationProperties注解配置数据源无法读取配置信息问题

    @ConfigurationProperties是springboot新加入的注解,主要用于配置文件中的指定键值对映射到一个java实体类上.那么它是怎么发挥作用的呢?下面我们将揭开@ConfigurationProperties的魔法. ConfigurationPropertiesBindingPostProcessor这个bean后置处理器,就是来处理bean属性的绑定的,这个bean后置处理器后文将称之为properties后置处理器.你需要知道以下几件事: ioc容器context的e

  • 详解ASP.NET Core 在 JSON 文件中配置依赖注入

    前言 在上一篇文章中写了如何在MVC中配置全局路由前缀,今天给大家介绍一下如何在在 json 文件中配置依赖注入. 在以前的 ASP.NET 4+ (MVC,Web Api,Owin,SingalR等)时候,都是提供了专有的接口以供使用第三方的依赖注入组件,比如我们常用的会使用 Autofac.Untiy.String.Net 等,这些第三放依赖注入组件基本上都提供了一套配置注入或者配置生命周期的方式,除了直接配置到类里面之外,还提供了要么使用 xml 文件,要么使用 json 等,那么在新的

  • 如何在ASP.NET Core类库项目中读取配置文件详解

    前言 最近有朋友问如何在.net core类库中读取配置文件,当时一下蒙了,这个提的多好,我居然不知道,于是这两天了解了相关内容才有此篇文章的出现,正常来讲我们在应用程序目录下有个appsettings.json文件对于相关配置都会放在这个json文件中,但是要是我建立一个类库项目,对于一些配置比如密钥或者其他需要硬编码的数据放在JSON文件中,在.net core之前配置文件为web.config并且有相关的类来读取节点上的数据,现如今在.net core中为json文件,那么我们该如何做?本

  • ASP.NET CORE学习教程之自定义异常处理详解

    为什么异常处理选择中间件? 传统的ASP.NET可以采用异常过滤器的方式处理异常,在ASP.NET CORE中,是以多个中间件连接而成的管道形式处理请求的,不过常用的五大过滤器得以保留,同样可以采用异常过滤器处理异常,但是异常过滤器不能处理MVC中间件以外的异常,为了全局统一考虑,采用中间件处理异常更为合适 为什么选择自定义异常中间件? 先来看看ASP.NET CORE 内置的三个异常处理中间件 DeveloperExceptionPageMiddleware, ExceptionHandler

  • ASP.NET Core自定义中间件如何读取Request.Body与Response.Body的内容详解

    背景# 最近在徒手造轮子,编写一个ASP.NET Core的日志监控器,其中用到了自定义中间件读取Request.Body和Response.Body的内容,但是编写过程,并不像想象中的一帆风顺,ASP.NET Core针对Request.Body和Response.Body的几个特殊设计,导致了完成以上功能需要绕一些弯路. 原始代码# 为了读取Request.Body和Response.Body的内容,我的实现思路如下: 创建一个LoggerMiddleware的中间件,将它放置在项目中间件管

随机推荐