1. 选项

前面讲完了.NET Core 下的配置系统,我们可以通过 IConfiguration 服务从各种来源的配置中读取到配置信息,但是每次要用的时候都通过 Iconfiguration 读取配置文件会比较不方便,而且效率低。.NET Core 体系下提供了一个选项系统,该功能用于实现以强类型的方式对程序配置信息进行访问,并且可以将选项类注入到依赖注入容器中进行管理和使用。

在进行配置信息的强类型选项绑定的时候,需要一个相应的选项类,该类推荐按 {Object}Options 命名规则进行命名,有以下特点:

  • 必须非抽象类
  • 必须包含公共无参的构造函数
  • 类中需要与配置项进行绑定的属性必须拥有 public 的 get、set 访问器,并且属性的命名必须与配置键一直,不区分大小写
  • 要确保配置项能够转换到其绑定的属性类型
  • 该类的字段不会被绑定

2. 选项配置方式

2.1 手动绑定

IConfiguration 服务通过 ConfigurationBinder 类扩展了 Get 和 Bind 两个方法,这两个方法可以将配置信息绑定到选项类上。这种方式在之前的 ASP.NET Core - 配置系统之配置读取 一章有讲到过,这里再做一下演示:

首先在配置文件中添加以下节点:

"Blog": {
"Title": "ASP.NET Core Options",
"Content": "This is a blog about Options System in ASP.NET Core Framework.",
"CreateTime": "2022-12-06"
}

之后定义一个选项类:

public class BlogOptions
{
public const string Blog = "Blog"; public string Title { get; set; } public string Content { get; set; } public DateTime CreateTime { get; set; }
}

然后,在任何可以获取到 IConfiguration 服务的地方都可以通过 IConfiguration 服务进行绑定:

using OptionsSample.Options;
using System.Text.Json; var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); var blog1 = new BlogOptions();
app.Configuration.GetSection(BlogOptions.Blog).Bind(blog1);
var blog2 = app.Configuration.GetSection(BlogOptions.Blog).Get<BlogOptions>(); Console.WriteLine(JsonSerializer.Serialize(blog1));
Console.WriteLine(JsonSerializer.Serialize(blog2)); app.Run();

这种方式依旧有些不方便,虽然也有好处,能够监测到配置的修改,在应用运行中同步改变(如果相应的配置处理程序支持变更重载的化),但每次都要指定相应的节点,每次都要实时构建新的选项对象,并且选项系统也能做到配置更改时更新选项。

2.2 依赖注入配置

2.2.1 配置文件节点转换选项

除了手动绑定的方式外,我们还可以在应用启动的时候读取相应的配置节点,配置成Options并同时注册到依赖注入容器中,由依赖注入容器管理其生命周期,并且多次使用。我们可以像注册其他的依赖注入关系一样,在入口文件中通过 IServiceCollection 的 Configure 扩展方法进行配置。

// 通过配置文件读取某一配置节点
//builder.Services.Configure<BlogOptions>(builder.Configuration.GetSection(BlogOptions.Blog));

这里通过获取特定的配置节点,并将其配置为选项,之后就可以在任何能够进行依赖注入的地方使用注入的 BlogOptions 选项类了。

var blogOption = app.Services.GetRequiredService<IOptions<BlogOptions>>().Value;
Console.WriteLine(JsonSerializer.Serialize(blogOption));

这里使用到的 Configure 方法是 OptionsConfigurationServiceCollectionExtensions 类中的扩展方法,选项系统中有好几个同名的 Configure 方法,但是这些是并不是同一个方法的重载,下面会详细讲到。

2.2.2 硬编码配置选项

除了从配置文件中读取配置节点转换为选项之外,我们也可以直接在代码中硬编码指定选项内容,并注入到容器之中。

//硬编码的方式设置配置信息,也可以在这里读取数据库信息
builder.Services.Configure<BlogOptions>(option =>
{
option.Title = "test";
option.Content = "test hard code option";
option.CreateTime = DateTime.Now;
});

这种情况用得不多,在这种情况下我们可以进行额外的一些逻辑,例如从数据库中获取一些信息。这里的 Configure 方法是 OptionsServiceCollectionExtensions 扩展类中的方法。值得注意的是,在同时使用上面两个方法配置同一个选项类的情况下,硬编码配置的方式优先。

2.2.3 使用DI服务配置选项

在某些场景下,选项的配置需要比较复杂的逻辑,会依赖容器中的其他服务,我们还可以使用以下方式:

builder.Services.AddOptions<BlogOptions>()
// 这里可以通过 Configure 方法指定需要的服务, IServiceProvider 只是一个示例
.Configure<IServiceProvider>((option, service) => // 接收的的第一个参数选项类对象,后面依次是所注入的服务
{
// 通过注入的服务执行相应的逻辑
option.Title = "test DI Configure";
option.Content = "test DI Configure";
option.CreateTime = DateTime.Now;
});

这里的 Configure 方法,与上面的不一样,不再是 IServiceCollection 的扩展方法,而是 OptionsBuilder 类中的方法,AddOptions 扩展方法在 OptionsServiceCollectionExtensions 中,返回一个 OptionsBuilder 对象。该方法有多个重载,最多支持5个服务来配置选项:

当使用这种方式和上面的硬编码的方式同时配置同一个选项类的情况下,哪部分代码后执行,最后选项类的内容就以哪部分为准。

2.2.4 命名选项

在一些情况下,应用中是存在多份配置结构相同,但具体配置值不同的配置信息的,例如以下的情况:

"FirstBlog": {
"Title": "ASP.NET Core Options",
"Content": "This is a blog about Options System in ASP.NET Core Framework.",
"CreateTime": "2022-12-06"
},
"SecondBlog": {
"Title": "ASP.NET Core Configuration",
"Content": "This is a blog about Configuration System in ASP.NET Core Framework.",
"CreateTime": "2022-12-08"
}

这种情况下,两个配置节点其实可以用同一个选项类接收,它们的结构是一样的。而命名选项就是为了应对这种情况,选项系统中允许为当前配置的选项命名,而选项系统区分同一个类型的不同选项也是根据名字进行区分的。事实上,.NET Core 中所有 Options 都是命名选项,当没有显式指定名字时(如上面讲到的默认配置方式),使用的名字默认是Options.DefaultName,即string.Empty。

builder.Services.Configure<BlogOptions>("First", builder.Configuration.GetSection("FirstBlog"));
builder.Services.Configure<BlogOptions>("Second", builder.Configuration.GetSection("SecondBlog"));

这里要说明的是,上面我们从依赖注入容器中解析 IOptions 接口,从而获取我们需要的选项值,但是使用命名选项的情况下是无法通过 IOptions 接口解析相应的选项的,必须通过 IOptionsMonitor 或者 IOptionsSnapshot 接口来解析。这三个接口的区别下面会重点讲。

var blog = app.Services.GetRequiredService<IOptions<BlogOptions>>().Value;
Console.WriteLine(JsonSerializer.Serialize(blog));
var firstBlog = app.Services.GetRequiredService<IOptionsMonitor<BlogOptions>>().Get("First");
Console.WriteLine(JsonSerializer.Serialize(firstBlog));
var secondBlog = app.Services.GetRequiredService<IOptionsMonitor<BlogOptions>>().Get("Second");
Console.WriteLine(JsonSerializer.Serialize(secondBlog));

2.2.4 后期配置

后期配置是指当我们通过前面的方法对一个选项类进行配置之后,可能还会因为其他业务逻辑需要对其中的配置信息进行修改,这时候我们可以通过后期配置对选项系统中已配置的选项内容进行替换。后期配置在所有的OptionsServiceCollectionExtensions.Configure 执行完成之后执行,即配置系统不管代码顺序,会先完成所有选项的配置,再执行后期配置。

builder.Services.Configure<BlogOptions>("First", builder.Configuration.GetSection("FirstBlog"));
builder.Services.PostConfigure<BlogOptions>("First", options =>
{
options.Title = "Post Config";
}); var firstBlog = app.Services.GetRequiredService<IOptionsMonitor<BlogOptions>>().Get("First");
Console.WriteLine(JsonSerializer.Serialize(firstBlog));

除了 PostConfigure 方法外,还有 PostConfigureAll 方法,前者对单一选项类单一命名的选项对象进行后期配置,如果没有指定名称则是默认名称,后者会对统一选项类下的不同命名选项统一进行配置。

builder.Services.Configure<BlogOptions>("First", builder.Configuration.GetSection("FirstBlog"));
builder.Services.Configure<BlogOptions>("Second", builder.Configuration.GetSection("SecondBlog"));
builder.Services.PostConfigureAll<BlogOptions>(options =>
{
options.Title = "Post Config";
}); var firstBlog = app.Services.GetRequiredService<IOptionsMonitor<BlogOptions>>().Get("First");
Console.WriteLine(JsonSerializer.Serialize(firstBlog));
var secondBlog = app.Services.GetRequiredService<IOptionsMonitor<BlogOptions>>().Get("Second");
Console.WriteLine(JsonSerializer.Serialize(secondBlog));

通过 IOptionsMonitor 或者 IOptionsSnapshot 接口解析选项,在配置来源更改的情况下,相应的选项内容也会随之变化(两者的适用场景不同), 后期配置逻辑在选项的每一次更改之后都会执行。

参考文章:

ASP.NET Core 中的选项模式 | Microsoft Learn

选项模式 - .NET | Microsoft Learn

面向 .NET 库创建者的选项模式指南 - .NET | Microsoft Learn

理解ASP.NET Core - 选项(Options)

ASP.NET Core 系列:

目录:ASP.NET Core 系列总结

上一篇:ASP.NET Core - 配置系统之自定义配置提供程序

ASP.NET Core - 选型系统之选型配置的更多相关文章

  1. Linux CentOS7部署ASP.NET Core应用程序,并配置Nginx反向代理服务器

    前言: 本篇文章主要讲解的是如何在Linux CentOS7操作系统搭建.NET Core运行环境并发布ASP.NET Core应用程序,以及配置Nginx反向代理服务器.因为公司的项目一直都是托管在 ...

  2. asp.net core 教程(五)-配置

    Asp.Net Core-配置 Asp.Net Core-配置 在这一章,我们将讨论 ASP.NET Core项目的相关的配置.在解决方案资源管理器中,您将看到 Startup.cs 文件.如果你有以 ...

  3. asp.net core重新加载应用配置

    asp.net core重新加载应用配置 Intro 我把配置放在了数据库或者是Redis里,配置需要修改的时候我要直接修改数据库,然后调用一个接口去重新加载应用配置,于是就尝试写一个运行时重新加载配 ...

  4. ASP.NET Core应用程序的参数配置及使用(转载)

    本文结构 提前准备 参数配置方式 appsettings.json 环境变量 命令行参数 在控制器中使用配置参数 注入IConfiguration对象 注入IOptions对象 总结 应用程序的开发不 ...

  5. .NET 黑魔法 - asp.net core 日志系统

    asp.net core 里如何记录日志呢? 这要从asp.net core的依赖注入说起,在asp.net core里的依赖注入真是无所不在,各种面向切面的接口与事件. 好吧,来点干货. 首先,我们 ...

  6. ASP.NET Core 1.0 基础之配置

    来源https://docs.asp.net/en/latest/fundamentals/configuration.html ASP.NET Core 1.0支持不同的配置选项.应用配置数据可以是 ...

  7. CZGL.Auth: ASP.NET Core Jwt角色授权快速配置库

    CZGL.Auth CZGL.Auth 是一个基于 Jwt 实现的快速角色授权库,ASP.Net Core 的 Identity 默认的授权是 Cookie.而 Jwt 授权只提供了基础实现和接口,需 ...

  8. ASP.NET Core 在 JSON 文件中配置依赖注入

    前言 在上一篇文章中写了如何在MVC中配置全局路由前缀,今天给大家介绍一下如何在在 json 文件中配置依赖注入. 在以前的 ASP.NET 4+ (MVC,Web Api,Owin,SingalR等 ...

  9. ASP.NET Core 注入和获取 AppSettings 配置

    ASP.NET Core 项目中有个appsettings.json配置文件,用于存放一些配置信息,比如数据库连接字符串等,但访问的话,只能在 ASP.NET Core 项目中获取,如果我们在其他项目 ...

  10. asp.net core 2.0中的配置(1)---Configuration

    配置就是一个装配数据字典的过程,一个字典也就是一个键值对,所以从配置就是键值对. 在asp.net core中关于配置是由四个基本的类型来支撑的,是①IConfigurationSource②ICon ...

随机推荐

  1. 数据脱敏java代码

    //前prefix后suffix脱敏 public static String idEncrypt(String number ,Integer prefix, Integer suffix) { i ...

  2. node.js请求css、js静态资源页面不生效

    产生原因:文件响应头内容类型错误 解决方案:设置对应的响应头内容类型 const http = require('http'); const fs = require('fs'); const pat ...

  3. Java执行cmd命令工具类

    工具类: public class CmdTask implements Runnable { private String command; private String dirPath; publ ...

  4. windows 和 linux 之间的文件传输操作

    参考:http://www.jb51.net/article/123378.htm 本文介绍,如何实现 windows 主机与 linux 虚拟机之间的文件传输. 一.获取虚拟机 IP 地址 要实现 ...

  5. ThreadPoolTaskExecutor线程池创建

    package com.xx.xx.config; import java.util.concurrent.ThreadPoolExecutor; import org.slf4j.Logger; i ...

  6. python机器学习——SVM支持向量机

    背景与原理: 支持向量机是一种用来解决分类问题的算法,其原理大致可理解为:对于所有$n$维的数据点,我们希望能够找到一个$n$维的直线(平面,超平面),使得在这个超平面一侧的点属于同一类,另一侧的点属 ...

  7. zynq 中断

    #include "stdio.h"#include "xparameters.h"#include "xgpiops.h"#include ...

  8. C#——》创建Windows服务,发布并调试Windows服务

    一,创建一个windows服务项目.  二,双击Service1.cs进入设计界面,在空白处右键单击选择添加安装程序,如下图所示. 三,添加安装程序后,会进入如下图界面,生成两个组件:serviceP ...

  9. DE 算法的变体python实现

    上演化计算课的时候老师讲了一种DE算法的改进算法CoDE,于是看了下CoDE的论文中的算法步骤: 算法中使用的三种交叉策略: 根据不同的交叉策略采取不同的变异策略: 超参数的三种不同组合(一一对应): ...

  10. SQL教程

    SQL教程 SQL简介 SQL (Structured Query Language:结构化查询语言) 是用于管理关系数据库管理系统(RDBMS). SQL 的范围包括数据插入.查询.更新和删除,数据 ...