ASP.NET Core 学习笔记 第五篇 ASP.NET Core 中的选项
前言
还记得上一篇文章中所说的配置吗?本篇文章算是上一篇的延续吧。在 .NET Core 中读取配置文件大多数会为配置选项绑定一个POCO(Plain Old CLR Object)对象,并通过依赖注入使用它。而这种使用方式称之为选项模式。而选项模式使是用类来提供对相关设置组的强类型访问,同时选项还提供验证配置数据的机制,是不是很强大,让我们一点点揭开它的神秘面纱。
ASP.NET Core 6.0 Web API简要说明
首先开发工具上需要VS2022了,这里非常推荐大家下载使用,在编码上真的越来越符合我们开发者的使用了,提示也更加智能化,VS2022详细说明,下载以及注册码可以参考我的上一篇博客,这里就不做详细说明了VS2022传送门(含注册码)。
.NET 6.0 已经出来有一段时间了,为了跟进技术的进步,笔者后续的系列笔记也将使用.NET 6.0作为目标框架,那么.NET 6.0 ASP.NET Core Web API 中带了了哪些变化呢?这里我做下简要说明。
- 打开Visual Studio 2022,创建新项目,选择“ASP.NET Core Web API”项目模板:
这里可以看见Use controllers选项默认选中的,取消该选项,则会创建最小Web API。 - 结构变化
这里可以看下Program.cs文件的变化
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
可以发现我们熟知的Startup.cs不见了,现在,全部都在Program.cs中实现:
- 在WebApplicationBuilder实例上使用Addxxx方法向DI容器注册特定服务,类似Startup类的ConfigureServices方法实现。
- 在WebApplication实例上使用Usexxx方法将一系列中间件加入到HTTP管道,类似Startup类的Configure方法实现。
- DTO使用record定义,而且也放在同一个Program.cs文件中。
说明: Visual Studio 2022默认使用 Kestrel Web服务器,而不是IIS Express。
配置绑定
首先创建一个json格式的配置文件
{
"JsonConfig": {
"Title": "MyTitle",
"Name": "Tom"
}
}
创建选项类
public class MyOptions
{
public const string JsonConfig = "JsonConfig";
public string? Title { get; set; }
public string? Name { get; set; }
}
选项类说明:
- 必须是包含公共无参数构造函数的非抽象类。
- 类型的所有公共读写属性都已绑定。
- 不会绑定字段。 在上面的代码中,Position 未绑定。 由于使用了 Position 属性,因此在将类绑定到配置提供程序时,不需要在应用中对字符串 "Position" 进行硬编码。
使用 ConfigurationBinder 绑定
新建一个控制器来读取配置文件。
[Route("api/[controller]/[action]")]
[ApiController]
public class OptionsController : ControllerBase
{
private readonly IConfiguration _configuration;
public OptionsController(IConfiguration configuration)
{
_configuration=configuration;
}
public ContentResult GetOptions()
{
var options = new MyOptions();
//方式1
_configuration.GetSection(MyOptions.JsonConfig).Bind(options);
//方式2
_configuration.GetSection(MyOptions.JsonConfig).Get<MyOptions>();
return Content($"Title:{options.Title}\n Name:{options.Name}");
}
}
说明:
这里的类型绑定有两种方式分别为ConfigurationBinder.Bind
和 ConfigurationBinder.Get
,
前者相对于后者更方便一些,在开发过程当中比较推荐使用后者做类型绑定。
依赖注入绑定
服务容器中绑定配置。
using OptionsTest.Model;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Configuration.AddJsonFile("MyJsonConfig.json", optional: true, reloadOnChange: true);
//注入绑定
builder.Services.Configure<MyOptions>(builder.Configuration.GetSection(MyOptions.JsonConfig));
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseAuthorization();
app.MapControllers();
app.Run();
新建一个控制器来读取配置文件。
[Route("api/[controller]/[action]")]
[ApiController]
public class Options2Controller : ControllerBase
{
private readonly MyOptions _options;
public Options2Controller(IOptions<MyOptions> options)
{
_options = options.Value;
}
public ContentResult GetOptions()
{
return Content($"Title:{_options.Title}\n Name:{_options.Name}");
}
}
选项接口
IOptions:
- 不支持:
- 在应用启动后读取配置数据。
- 命名选项
- 注册为单一实例且可以注入到任何服务生存期。
IOptionsSnapshot:
- 在每次请求时应重新计算选项的方案中有用。 有关详细信息,请参阅使用 IOptionsSnapshot 读取已更新的数据。
- 注册为范围内,因此无法注入到单一实例服务。
- 支持命名选项
IOptionsMonitor:
- 用于检索选项并管理 TOptions 实例的选项通知。
- 注册为单一实例且可以注入到任何服务生存期。
- 支持:
- 更改通知
- 命名选项
- 可重载配置
- 选择性选项失效 (IOptionsMonitorCache)
IOptionsSnapshot
在项目中如何在改变配置文件后,在不重启项目的前提下自动加载配置文件呢?IOptionsSnapshot
就支持读取已更新的配置值。
在前面项目的基础上略做改变就能做到,MyOptions.cs、MyJsonConfig.json、Program.cs不需要改变。在OptionsController中改用IOptionsSnapshot注入就可以了,代码如下:
[Route("api/[controller]/[action]")]
[ApiController]
public class Options2Controller : ControllerBase
{
private readonly MyOptions _options;
public Options2Controller(IOptionsSnapshot<MyOptions> options)
{
_options = options.Value;
}
public ContentResult GetOptions()
{
return Content($"Title:{_options.Title}\n Name:{_options.Name}");
}
}
是不是很简单,这样每次改完配置文件就不需要重启程序了。
IOptionsMonitor
MyOptions.cs、MyJsonConfig.json、Program.cs不需要改变。在OptionsController中改用IOptionsMonitor注入就可以了,代码如下:
[Route("api/[controller]/[action]")]
[ApiController]
public class OptionsController : ControllerBase
{
private readonly MyOptions _options;
public Options2Controller(IOptionsMonitor<MyOptions> options)
{
_options = options.Value;
}
public ContentResult GetOptions()
{
return Content($"Title:{_options.Title}\n Name:{_options.Name}");
}
}
说明:
IOptionsMonitor
是一种单一示例服务,可随时检索当前选项值,这在单一实例依赖项中尤其有用。IOptionsSnapshot
是一种作用域服务,并在构造IOptionsSnapshot
对象时提供选项的快照。 选项快照旨在用于暂时性和有作用域的依赖项。
命名选项
命名选项:
- 当多个配置节绑定到同一属性时有用。
- 区分大小写。
新建json配置文件
{
"JsonConfig": {
"Title": "MyTitle",
"Name": "Tom"
},
"JsonConfig2": {
"Title": "MyTitle2",
"Name": "Jerry"
}
}
在属性相同的情况下,不需要创建两个类,我们增加一个字段就可以了。
public class MyOptions
{
public const string JsonConfig = "JsonConfig";
public const string JsonConfig2 = "JsonConfig2";
public string? Title { get; set; }
public string? Name { get; set; }
}
Program.cs中配置命名选项。
using OptionsTest3.Model;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Configuration.AddJsonFile("MyJsonConfig.json", optional: true, reloadOnChange: true);
//注入绑定
builder.Services.Configure<MyOptions>(MyOptions.JsonConfig,builder.Configuration.GetSection(MyOptions.JsonConfig));
builder.Services.Configure<MyOptions>(MyOptions.JsonConfig2, builder.Configuration.GetSection(MyOptions.JsonConfig2));
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseAuthorization();
app.MapControllers();
app.Run();
在Controller中读取配置。
[Route("api/[controller]/[action]")]
[ApiController]
public class Options3Controller : ControllerBase
{
private readonly MyOptions _options;
private readonly MyOptions _options2;
public Options3Controller(IOptionsSnapshot<MyOptions> options)
{
_options = options.Get(MyOptions.JsonConfig);
_options2 = options.Get(MyOptions.JsonConfig2);
}
public ContentResult GetOptions()
{
return Content($"Title:{_options.Title}\n Name:{_options.Name}\n" +
$"Title:{_options2.Title}\n Name:{_options2.Name}");
}
}
选项验证
在配置文件中对于配置项的验证是必不可少的。这样可以保证程序配置的正确性。具体如何实现呢,且听笔者慢慢道来。
首先创建一个简单的Json配置文件。
{
"JsonConfig": {
"ID": 10000000,
"Title": "MyTitle",
"Name": "Tom"
}
}
创建我们配置项的验证Model。
public class MyOptions
{
public const string JsonConfig = "JsonConfig";
[Range(0, 1000,
ErrorMessage = "值 {0}必须在 {1} 和 {2}之间。")]
public int ID { get; set; }
[RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$")]
public string? Title { get; set; }
public string? Name { get; set; }
}
在Program.cs中配置我们的选项和验证。
using OptionValidtate.Model;
using System.Configuration;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Configuration.AddJsonFile("MyJsonConfig.json", optional: true, reloadOnChange: true);
builder.Services.AddOptions<MyOptions>().Bind(builder.Configuration.GetSection(MyOptions.JsonConfig)).ValidateDataAnnotations();
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseAuthorization();
app.MapControllers();
app.Run();
说明:注意到和之前的代码有什么不同了吗?在我们正是通过调用ValidateDataAnnotations
以使用 DataAnnotations 来完成验证。
在我们的Controller中读取我们的配置。这里用到了ILogger,可以先不用关心,在后续笔者会详细讲解。
[Route("api/[controller]/[action]")]
[ApiController]
public class OptionsController : ControllerBase
{
private readonly ILogger<OptionsController> _logger;
private readonly IOptions<MyOptions> _options;
public OptionsController(IOptions<MyOptions> options, ILogger<OptionsController> logger)
{
_options = options;
_logger = logger;
try
{
var optionsValue = _options.Value;
}
catch (OptionsValidationException e)
{
foreach (var failure in e.Failures)
{
_logger.LogError(failure);
}
}
}
public ContentResult GetOptions()
{
string msg;
try
{
msg=$"ID:{_options.Value.ID}\nTitle:{_options.Value.Title}\nName:{_options.Value.Name}\n";
}
catch (OptionsValidationException e)
{
return Content(e.Message);
}
return Content(msg);
}
}
还记得咱们配置的ID验证规则吗?启动程序看下我们的验证已经生效了。
IValidateOptions复杂验证的实现
如果上面的验证还不满足要求的话,没关系我对上面的代码略作修改,通过IValidateOptions
就可以实现更加的复杂验证。
新建MyValidateOptions类继承IValidateOptions接口并实现。
public class MyValidateOptions : IValidateOptions<MyOptions>
{
public MyOptions _options { get; private set; }
public MyValidateOptions(IConfiguration config)
{
_options = config.GetSection(MyOptions.JsonConfig).Get<MyOptions>();
}
public ValidateOptionsResult Validate(string name, MyOptions options)
{
string msg = null;
var rxValidate = new Regex(@"^[a-zA-Z''-'\s]{1,40}$");
if (options.ID<0||options.ID>1000)
{
msg = $"{options.ID}必须在0-1000之间。";
}
if (string.IsNullOrEmpty(options.Title))
{
msg = $"{options.Title}必须符合正则要求。";
}
if (msg !=null)
{
return ValidateOptionsResult.Fail(msg);
}
return ValidateOptionsResult.Success;
}
}
在Program.cs中配置我们的选项和验证。
using Microsoft.Extensions.Options;
using OptionValidtate.Model;
using System.Configuration;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Configuration.AddJsonFile("MyJsonConfig.json", optional: true, reloadOnChange: true);
builder.Services.AddOptions<MyOptions>().Bind(builder.Configuration.GetSection(MyOptions.JsonConfig));
builder.Services.AddSingleton<IValidateOptions<MyOptions>,MyValidateOptions>();
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseAuthorization();
app.MapControllers();
app.Run();
好了配置完毕,运行程序可以看到我们配置的验证已经生效了。
ASP.NET Core 学习笔记 第五篇 ASP.NET Core 中的选项的更多相关文章
- ASP.NET Core 学习笔记 第四篇 ASP.NET Core 中的配置
前言 说道配置文件,基本大多数软件为了扩展性.灵活性都会涉及到配置文件,比如之前常见的app.config和web.config.然后再说.NET Core,很多都发生了变化.总体的来说技术在进步,新 ...
- 路由其实也可以很简单-------Asp.net WebAPI学习笔记(一) ASP.NET WebApi技术从入门到实战演练 C#面向服务WebService从入门到精通 DataTable与List<T>相互转换
路由其实也可以很简单-------Asp.net WebAPI学习笔记(一) MVC也好,WebAPI也好,据我所知,有部分人是因为复杂的路由,而不想去学的.曾经见过一位程序猿,在他MVC程序中, ...
- ASP.NET MVC 学习笔记-7.自定义配置信息 ASP.NET MVC 学习笔记-6.异步控制器 ASP.NET MVC 学习笔记-5.Controller与View的数据传递 ASP.NET MVC 学习笔记-4.ASP.NET MVC中Ajax的应用 ASP.NET MVC 学习笔记-3.面向对象设计原则
ASP.NET MVC 学习笔记-7.自定义配置信息 ASP.NET程序中的web.config文件中,在appSettings这个配置节中能够保存一些配置,比如, 1 <appSettin ...
- ASP.NET MVC 学习笔记-2.Razor语法 ASP.NET MVC 学习笔记-1.ASP.NET MVC 基础 反射的具体应用 策略模式的具体应用 责任链模式的具体应用 ServiceStack.Redis订阅发布服务的调用 C#读取XML文件的基类实现
ASP.NET MVC 学习笔记-2.Razor语法 1. 表达式 表达式必须跟在“@”符号之后, 2. 代码块 代码块必须位于“@{}”中,并且每行代码必须以“: ...
- Asp.Net Core学习笔记:入门篇
Asp.Net Core 学习 基于.Net Core 2.2版本的学习笔记. 常识 像Django那样自动检查代码更新,自动重载服务器(太方便了) dotnet watch run 托管设置 设置项 ...
- .net core学习笔记,组件篇:服务的注册与发现(Consul)初篇
1.什么是服务注册中心? 在学习服务注册与发现时,我们要先搞明白到底什么是服务注册与发现. 在这里我举一个生活中非常普遍的例子——网购来简单说明,网购在我们日常生活中已经是非常普遍了,其实网购中的(商 ...
- Asp.net core Identity + identity server + angular 学习笔记 (第五篇)
ABAC (Attribute Based Access Control) 基于属性得权限管理. 属性就是 key and value 表达力非常得强. 我们可以用 key = role value ...
- ASP.NET Core 学习笔记 第三篇 依赖注入框架的使用
前言 首先感谢小可爱门的支持,写了这个系列的第二篇后,得到了好多人的鼓励,也更加坚定我把这个系列写完的决心,也能更好的督促自己的学习,分享自己的学习成果.还记得上篇文章中最后提及到,假如服务越来越多怎 ...
- R学习笔记 第五篇:数据变换和清理
在使用R的分组操作之前,首先要了解R语言包,包实质上是实现特定功能的,预先写好的代码库(library),R拥有大量的软件包,许多包都是由某一领域的专家编写的,但并不是所有的包都有很高的质量的,在使用 ...
随机推荐
- NOIP 模拟 七十一
最后一场多校模拟赛,好像是信心赛??不过考的不行..最近难题比较多,对题目的难度把握不够好,经常出现简单题跳过的现象. 100+100+20+40 T1 签到题(qiandao) 如果一个点的度数不是 ...
- NOIP 模拟六 考试总结
T1辣鸡 T1就搞得这莫不愉快.. 大致题意是给你几个矩形,矩形覆盖的点都标记上,每个矩形无重复部分,求满足(x,y) (x+1,y+1)都标记过的点对数,范围1e9. 看起来很牛的样子,我确实也被1 ...
- Http Only Cookie保护AccessToken
前言 JWT认证方式目前已被广泛使用,一直以来我们将token放在请求头中的Authorization中,若通过此种方式,一旦token被恶意窃取,攻击者可肆意对用户可访问资源进行任意索取,我们大多都 ...
- Java秘诀!零基础怎样快速学习Java?
对于零基础想学Java的朋友,其实一开始最应该做的就是定好学习目标和端正学习态度,切记不要三天打鱼两天晒网! 首先你是零基础,现在急需把Java学好,在保证学习质量的同时,用最短的时间学好Java应该 ...
- Filter防火墙
实验简介 实验属于防火墙系列 实验目的 了解个人防火墙的基本工作原理: 掌握Filter防火墙的配置. 实验环境 一台安装了win7操作系统的主机. 预备知识 防火墙 防火墙(Firewall)是一项 ...
- linux下nginx编译安装、版本信息修改
环境 centos 7 安装依赖包 yum install -y gcc gcc-c++ glibc glibc-devel pcre pcre-devel zlib zlib-devel opens ...
- 使用CSS选择器(第二部分)
伪类跟伪元素一样,并不是直接针对文档元素的,而是为你基于某些共同特征选择元素提供方便. 使用结构性伪类选择器 使用结构性伪类选择器能够根据元素在文档中的位置选择元素.这类选择器都有一个冒号字符前缀(: ...
- SpringBoot入门03-转发到Thymeleaf
前言 Spring Boot不提倡使用jsp和用View层,而是使用Thymeleaf代替jsp,因为性能可以得到提升. 使用Thymeleaf要加入依赖 Thymeleaf不能直接被访问,它严格遵守 ...
- NX CAM 区域轮廓铣的切削步长
从NX3.0到NX9.0,默认都是5%.可是实际计算的精确度是不一样的.到NX8.0上发现计算速度特别慢,后来东找西找,设置这个参数可以解决.PS:请慎用!请后后面的官方解释. 官方的解释是: &qu ...
- Mybatis 二级缓存应用 (21)
[MyBatis 二级缓存] 概述:一级缓存作用域为同一个SqlSession对象,而二级缓存用来解决一级缓存不能夸会话共享,作用范围是namespace级,可以被多个SqlSession共享(只要是 ...