ASP.NET Core 源码学习之 Options[1]:Configure

ASP.NET Core 配置系统

在ASP.NET 4.X中,通常将配置存储在 web.config 中,使用静态帮助类来获取这些配置,而对 web.cofng 中进行任何修改时,则会导致应用程序池的回收,这种实现方式并不是很友好。

因此,在ASP.NET Core中,对配置系统进行了重写,仍然使用的是基本的键值对,但是它们可以从多种格式的配置源中来获取,比如:命令行、环境变量、XML文件、JSON文件等等,你也可以编写自定义的配置源提供程序。

通常在Stratup类的构造函数中对配置源进行设置:

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).AddEnvironmentVariables();Configuration = builder.Build(); }
 public IConfigurationRoot Configuration { get; }  

首先创建了一个ConfigurationBuilder,然后设置配置源,最终生成的Configuration是所有配置源中的键值对组合。

你可以直接在程序中使用IConfigurationRoot来读取配置,但是建议你使用强类型的Options,这样在你想获取某个配置时,只需要注入对应的Options,而不是获取整个配置。

强类型的 Options

Options is a framework for accessing and configuring POCO settings.

简单来说,Options 就是将一个 POCO 的配置类,通过在Startup类中注册到容器中,在后续使用的时候使用构造函数注入来获取到POCO对象。我们将这种编程模式称为Options模式

首先定义一个 Options

public class MyOptions{   
 public string DefaultValue { get; set; } }

然后我们在对应的appsettings.json中添加如下片段:

{"MyOptions": {"DefaultValue" : "first"}}

Startup中的ConfigureServices方法中,进行服务的注册:

public void ConfigureServices(IServiceCollection services)  {services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
}

最后,便在控制器中注入IOptions<MyOptions>,通过其Value属性对MyOptions进行访问:

[Route("api/[controller]")]
public class ValuesController : Controller  {  
 private readonly MyOptions _options;  
 public ValuesController(IOptions<MyOptions> options)    {_options = options.Value;}[HttpGet]    public string Get()    {  
      return _options.DefaultValue;} }

Configure 方法

Options框架为我们提供了一系统的IServiceCollection的扩展方法,方便我们的使用。

直接使用Action配置

// 最简单的注册方式services.Configure<MyOptions>(o => o.DefaultValue = true);// 指定具体名称services.Configure<MyOptions>("my", o => o.DefaultValue = true);// 配置所有实例services.ConfigureAll<MyOptions>(o => o.DefaultValue = true);

通过配置文件进行配置

// 使用配置文件来注册实例services.Configure<MyOptions>(Configuration.GetSection("Sign"));// 指定具体名称services.Configure<MyOptions>("my", Configuration.GetSection("Sign"));// 配置所有实例services.ConfigureAll<MyOptions>(Configuration.GetSection("Sign"));

PostConfigure方法

PostConfigure 方法在 Configure 方法之后执行,是2.0中新增加的。

services.PostConfigure<MyOptions>(o => o.DefaultValue = true);
services.PostConfigure<MyOptions>("smyign", o => o.DefaultValue = true);
services.PostConfigureAll<MyOptions>(o => o.DefaultValue = true);

源码解析

首先看一下IConfigureOptions接口:

public interface IConfigureOptions<in TOptions> where TOptions : class{    void Configure(TOptions options);
}

Configure扩展方法中便是为IConfigureOptions<>注册了一个单例ConfigureNamedOptions<>

public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string name, Action<TOptions> configureOptions) 
   where TOptions : class{  
   
     if (services == null){      
      throw new ArgumentNullException(nameof(services));}  
    if (configureOptions == null){    
       throw new ArgumentNullException(nameof(configureOptions));}services.AddSingleton<IConfigureOptions<TOptions>>(new ConfigureNamedOptions<TOptions>(name, configureOptions));    return services; }

而不指定nameConfigureConfigureAll方法,都只是一种简写形式,使用默认的name

public static class Options{   
 public static readonly string DefaultName = string.Empty; }
 public static IServiceCollection Configure<TOptions>(this IServiceCollection services, Action<TOptions> configureOptions)
 where TOptions : class => services.Configure(Options.Options.DefaultName, configureOptions);
 
 public static IServiceCollection ConfigureAll<TOptions>(this IServiceCollection services, Action<TOptions> configureOptions) where TOptions : class=> services.Configure(name: null, configureOptions: configureOptions);

Configure方法其实就是为IConfigureOptions<>注册了一个单例ConfigureNamedOptions<>

再看一下使用IConfiguration进行配置的扩展方法:

public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string name, IConfiguration config)  
 where TOptions : class{  
   if (services == null){  
      throw new ArgumentNullException(nameof(services));}  
  if (config == null){        throw new ArgumentNullException(nameof(config));}services.AddSingleton<IOptionsChangeTokenSource<TOptions>>(new ConfigurationChangeTokenSource<TOptions>(name, config));    return services.AddSingleton<IConfigureOptions<TOptions>>(new NamedConfigureFromConfigurationOptions<TOptions>(name, config)); }

可以看到,注册的实例变成了NamedConfigureFromConfigurationOptions,而其本质依然是调用ConfigureNamedOptions,只不过Action的方法体变成了ConfigurationBinder.Bind()

public class NamedConfigureFromConfigurationOptions<TOptions> : ConfigureNamedOptions<TOptions>    
where TOptions : class{  
 public NamedConfigureFromConfigurationOptions(string name, IConfiguration config)        : base(name, options => ConfigurationBinder.Bind(config, options))    {      
        if (config == null){        
           throw new ArgumentNullException(nameof(config));}} }

大家或许会有点疑问:“ IConfigureOptions 中的 Configure 方法是在什么时候调用的呢 ”,这个且看下章分解。

ConfigureNamedOptions

ConfigureNamedOptions 实现了 IConfigureNamedOptions,而 IConfigureNamedOptions 则是对 IConfigureOptions 的一个扩展,添加了Name参数,这样,我们便可以为同一个 Options 类型注册多个独立的实例,在某些场景下则是非常有用的。有关Name的使用,则会在 第三章 来讲。

public interface IConfigureNamedOptions<in TOptions> : IConfigureOptions<TOptions> where TOptions : class{  
 void Configure(string name, TOptions options); }

再看一下 ConfigureNamedOptions 的源码:

public class ConfigureNamedOptions<TOptions> : IConfigureNamedOptions<TOptions>, IConfigureOptions<TOptions> where TOptions : class{   

 public ConfigureNamedOptions(string name, Action<TOptions> action)    {Name = name;Action = action;}    
 
   public string Name { get; }  
 
   public Action<TOptions> Action { get; }     
   
   public virtual void Configure(string name, TOptions options)    {        if (options == null){        
      throw new ArgumentNullException(nameof(options));}      
       if (Name == null || name == Name){Action?.Invoke(options);}}  
 public void Configure(TOptions options) => Configure(Options.DefaultName, options); }

ConfigureNamedOptions 本质上就是把我们注册的Action包装成统一的Configure方法,以方便后续创建Options实例时,进行初始化。

总结

本文描述了在 .NET Core 配置系统中Options的配置及原理,在 下一章 来讲一下IOptions


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/324266.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBootAdmin客户端接入

只有网关微服务有方框中的内容&#xff0c;其他微服务没有

ssl初一组周六模拟赛【2018.5.12】(期中)

前言 这周竟然没有奶死自己&#xff0c;成为模拟赛第一个AK的&#xff08;然而第一题数据错了所以这次放加上第一题的分&#xff09; 先说一下成绩&#xff1a; 姓名成绩wyc400xjq290xxy255lrz225hzb205zyc190hjq180lw140 期中总结 正题 题目1&#xff1a;ssl2413 排名【…

Java自动化邮件中发送图表(一)

一、邮件需求 邮件中需要展示柱状图、折线图和饼图等图表数据。如图&#xff1a; 二、解决方案 将图表转成图片&#xff0c;采用html邮件文本&#xff0c;使用base64编码图片发送邮件。 将图表导出成图片有三种方式&#xff1a; &#xff08;1&#xff09;JFreeChart 优点…

springboot+mybatis-plus实例demo

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号【雄雄的小课堂】。前言故事还得从一次微信通话说起……一个夜深人静的晚上&#xff0c;正在电脑前看书&#xff0c;突然&#xff0c;放在旁边的手机响了起来&#xff0c;原来是一个朋友打的微信电话。“你在干嘛呢&a…

分布式事务,EventBus 解决方案:CAP【中文文档】

前言 很多同学想对CAP的机制以及用法等想有一个详细的了解&#xff0c;所以花了将近两周时间写了这份中文的CAP文档&#xff0c;对 CAP 还不知道的同学可以先看一下 .NET Core 事件总线,分布式事务解决方案&#xff1a;CAP。 本文档为 CAP 文献&#xff08;Wiki&#xff09;&…

POJ1330-Nearest Common Ancestors【tarjan,LCA】

正题 题目链接&#xff1a; http://poj.org/problem?id1330 题目大意 就是给出一棵树&#xff0c;求LCA&#xff08;最近公共祖先&#xff09; 解题思路 用tarjan求LCA&#xff0c;这里给出tarjan算法 代码 #include<cstdio> #include<iostream> using nam…

Java自动化邮件中发送图表(二)之JFreeChart

一、JFreeChart库 JFreeChart是JAVA平台上的一个开放的图表绘制类库。 JFreeChart可生成饼图&#xff08;pie charts&#xff09;、柱状图&#xff08;bar charts&#xff09;、散点图&#xff08;scatter plots&#xff09;、时序图&#xff08;time series&#xff09;、甘…

springboot点击运行没反应,什么都不显示的解决方式

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号【雄雄的小课堂】。最近这段时间一直在看开源框架&#xff0c;自己慢慢的琢磨&#xff0c;终于将jeecgboot环境搭建起来&#xff0c;并且成功的跑起来了demo&#xff0c;在此过程中&#xff0c;很明显的能感觉到自己进…

C#和NewSQL更配 —— CockroachDB入门

一、CockroachDB是什么 CockroachDB&#xff08;https://www.cockroachlabs.com&#xff09;是Google备受瞩目的Spanner的开源模仿&#xff0c;承诺提供一种高存活性、强一致性&#xff0c;可横向扩展的SQL数据库。主要的设计目标是全球一致性和可靠性&#xff0c;从蟑螂&#…

ssl1746-商务旅行【tarjan,LCA】

正题 题目大意 一个n-1个点的有向无环图&#xff0c;给出若干个点&#xff0c;要求依次到达的最少时间。 解题思路 有向无环图我们可以把其看做一颗树&#xff0c;然后每次用LCA求两个点之间的距离&#xff0c;然后把所有距离统计一下就是结果。 代码 #include<cstdio>…

springboot+layui从控制器请求至页面时js失效的解决方法

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注公众号【雄雄的小课堂】。 昨天遇到了个很棘手的问题&#xff0c;其实也怪自己大意了&#xff0c;然后翻来覆去一个类一个类的去看&#xff0c;看完之后挨个技术点怀疑&#xff0c;然后分别从各个技术点入手解决&#xff0c;但…

JfreeChart(八)之甘特图

转载自 JfreeChart实现甘特图 一、甘特图简介 甘特图(Gantt chart)又称为横道图、条状图(Bar chart)。以提出者亨利L甘特先生的名字命名。 甘特图内在思想简单&#xff0c;即以图示的方式通过活动列表和时间刻度形象地表示出任何特定项目的活动顺序与持续时间。基本是一条…

springboot从控制器请求至页面时js失效的解决方法

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注公众号【雄雄的小课堂】。昨天遇到了个很棘手的问题&#xff0c;其实也怪自己大意了&#xff0c;然后翻来覆去一个类一个类的去看&#xff0c;看完之后挨个技术点怀疑&#xff0c;然后分别从各个技术点入手解决&#xff0c;但都…

ASP.NET Core 源码学习之 Options[2]:IOptions

在 上一篇 中&#xff0c;介绍了一下Options的注册&#xff0c;而使用时只需要注入 IOption 即可&#xff1a; public ValuesController(IOptions<MyOptions> options){ var opt options.Value; } IOptions IOptions 定义非常简单&#xff0c;只有一个Value属性&a…

Java自动化邮件中发送图表(三)之Highchart

一、Highchart &#xff08;1&#xff09;Highchart.js Highcharts 是一个用纯JavaScript编写的一个图表库。能够很简单便捷的在web网站或是web应用程序添加有交互性的图表。 &#xff08;2&#xff09;highcharts-serverside-export Highcharts Serverside Export框架&…

【2018.5.19】模拟赛之一-ssl2432 面积最大【数学】

正题 大意 解题思路 沟谷定理可以用半径求出高度&#xff0c;然后暴力枚举就好了 公式&#xff1a; ahr2−(a/2)2−−−−−−−−−√∗2ahr2−(a/2)2∗2bhr2−(b/2)2−−−−−−−−−√∗2bhr2−(b/2)2∗2然后计算两个的面积去掉重复的 Sa∗ahb∗bh−a∗bSa∗ahb∗bh−a…

thymeleaf如何迭代遍历,如何判断

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注公众号【雄雄的小课堂】。最近&#xff0c;换了个桌面手机的也同步换了下&#xff1a;哈哈哈&#xff0c;自己看着舒服就行~这几天在业余时间搞一个电商项目&#xff0c;可以说是边学边做&#xff0c;效率比较低&#xff0c;但是…