前言

配置,对我们的程序来说是十分重要的一部分。或多或少都会写一部分内容到配置文件中去。

由其是在配置中心(Apollo等)做起来之前,配置文件一定会是我们的首选。

在.NET Core中,习惯的是用json文件当配置文件。读取的方法是不少,这里主要介绍的是用基于Options的方法来读,可以认为这是一种强类型的形式。

本文会介绍一些常见的用法,简单的单元测试示例,如果想探讨内部实现,请移步至雨夜朦胧的博客

先来看看IOptions。

IOptions

先写好配置文件

{
"Demo": {
"Age": 18,
"Name": "catcher"
},
//others ...
}

然后定义对应的实体类

public class DemoOptions
{
public int Age { get; set; } public string Name { get; set; }
}

然后只需要在ConfigureServices方法添加一行代码就可以正常使用了。

public void ConfigureServices(IServiceCollection services)
{
services.Configure<DemoOptions>(Configuration.GetSection("Demo")); //others..
}

最后就是在想要读配置内容的地方使用IOptions去注入就好了。

private readonly DemoOptions _normal;

public ValuesController(IOptions<DemoOptions> normalAcc)
{
this._normal = normalAcc.Value;
} // GET api/values
[HttpGet]
public string Get()
{
var age = $"normal-[{_normal.Age}];";
var name = $"normal-[{_normal.Name}];"; return $"age:{age} \nname:{name}";
}

这个时候的结果,就会大致如下了:

这个时候可能会冒出这样的一个想法,如果某天,要修改某个配置项的值,它能及时生效吗?

口说无凭,来个动图见证一下。

事实证明,使用IOptions的时候,修改配置文件的值,并不会立刻生效!!

既然IOptions不行,那么我们就换一个!

下面来看看IOptionsSnapshot。

IOptionsSnapshot

对于Options家族,在Startup注册的时候都是一个样的,区别在于使用它们的时候。

private readonly DemoOptions _normal;
private readonly DemoOptions _snapshot; public ValuesController(IOptions<DemoOptions> normalAcc,
IOptionsSnapshot<DemoOptions> snapshotAcc)
{
this._normal = normalAcc.Value;
this._snapshot = snapshotAcc.Value;
} // GET api/values
[HttpGet]
public string Get()
{
var age = $"normal-[{_normal.Age}];snapshot-[{_snapshot.Age}];";
var name = $"normal-[{_normal.Name}];snapshot-[{_snapshot.Name}];"; return $"age:{age} \nname:{name}";
}

这个时候修改配置项的值之后,就会立马更新了。

本质上,IOptions和IOptionsSnapshot是一样的,只是他们注册的生命周期不一样,从而就有不同的表现结果。

当然,还有一个更强大的Options的存在,IOptionsMonitor。

它的用法和IOptionsSnapshot没有区别,不同的时,它多了一个配置文件发生改变之后事件处理。

下面来看看。

IOptionsMonitor

private readonly DemoOptions _normal;
private readonly DemoOptions _snapshot;
private readonly DemoOptions _monitor; public ValuesController(IOptions<DemoOptions> normalAcc, IOptionsSnapshot<DemoOptions> snapshotAcc, IOptionsMonitor<DemoOptions> monitorAcc)
{
this._normal = normalAcc.Value;
this._snapshot = snapshotAcc.Value;
this._monitor = monitorAcc.CurrentValue;
monitorAcc.OnChange(ChangeListener);
} private void ChangeListener(DemoOptions options, string name)
{
Console.WriteLine(name);
} // GET api/values
[HttpGet]
public string Get()
{
var age = $"normal-[{_normal.Age}];snapshot-[{_snapshot.Age}];monitor-[{_monitor.Age}];";
var name = $"normal-[{_normal.Name}];snapshot-[{_snapshot.Name}];monitor-[{_monitor.Name}];"; return $"age:{age} \nname:{name}";
}

效果和上面一样的,不同的是,当保存appsettings.json的时候,会触发一次ChangeListener

虽说Snapshot和Monitor可以让我们及时获取到最新的配置项。

但是我们也可以通过PostConfigurePostConfigureAll来进行调整。

PostConfigure/PostConfigureAll

public void ConfigureServices(IServiceCollection services)
{
services.Configure<DemoOptions>(Configuration.GetSection("Demo")); services.PostConfigureAll<DemoOptions>(x =>
{
x.Age = 100;
}); services.AddMvc();
}

如果我们的代码是这样写的,那么,最终的结果就会是,无论我们怎么修改配置文件,最终展示的Age会一直是100。

大家也可以思考一下这个可以用在什么场景。

随便给大家看一段Steeltoe服务发现客户端的代码

private static void AddDiscoveryServices(IServiceCollection services, IConfiguration config, IDiscoveryLifecycle lifecycle)
{
var clientConfigsection = config.GetSection(EUREKA_PREFIX);
int childCount = clientConfigsection.GetChildren().Count();
if (childCount > 0)
{
var clientSection = config.GetSection(EurekaClientOptions.EUREKA_CLIENT_CONFIGURATION_PREFIX);
services.Configure<EurekaClientOptions>(clientSection); var instSection = config.GetSection(EurekaInstanceOptions.EUREKA_INSTANCE_CONFIGURATION_PREFIX);
services.Configure<EurekaInstanceOptions>(instSection);
services.PostConfigure<EurekaInstanceOptions>((options) =>
{
EurekaPostConfigurer.UpdateConfiguration(config, options);
});
AddEurekaServices(services, lifecycle);
}
else
{
throw new ArgumentException("Discovery client type UNKNOWN, check configuration");
}
}

最后就是单元测试遇到Options要怎么处理的问题了。

单元测试

单元测试,这里用了NSubstitute来作示例。

先简单定义一些类

public class MyClass
{
private readonly MyOptions _options; public MyClass(IOptions<MyOptions> optionsAcc)
{
this._options = optionsAcc.Value;
} public string Greet()
{
return $"Hello,{_options.Name}";
}
} public class MyOptions
{
public string Name { get; set; }
}

编写测试类

public class MyClassTest
{
private readonly MyClass myClass; public MyClassTest()
{
var options = new MyOptions { Name = "catcher"}; var fake = Substitute.For<IOptions<MyOptions>>(); fake.Value.Returns(options); myClass = new MyClass(fake);
} [Fact]
public void GreetTest()
{
var res = myClass.Greet(); Assert.Equal("Hello,catcher", res);
}
}

重点在于fake了一下Options(这里只以IOptions为例),然后是告诉测试,如果有用到Value属性的时候,就用返回定义好的Options。

也是比较简单的做法,测试的结果自然也是符合预期的。

总结

这几个Options使用起来还是比较顺手的,至少何时采用那种Options,就得根据场景来定了。

看看.NET Core几个Options的简单使用的更多相关文章

  1. 一个基于 .NET Core 2.0 开发的简单易用的快速开发框架 - LinFx

    LinFx 一个基于 .NET Core 2.0 开发的简单易用的快速开发框架,遵循领域驱动设计(DDD)规范约束,提供实现事件驱动.事件回溯.响应式等特性的基础设施.让开发者享受到正真意义的面向对象 ...

  2. .net core使用ocelot---第一篇 简单使用

    简介原文地址 接下来你会学习,基于asp.net core 用Ocelot实现一个简单的API网关.或许你会疑问什么是API网关,我们先看下面的截图 API网关是访问你系统的入口,它包括很多东西,比如 ...

  3. .Net Core应用RabbitMQ,及简单封装

    首先,还是万分感谢大家能够抽空来阅读我的文章,万分感谢.今天我带来的是.Net Core中应用RabbitMQ,和简单封装.因为昨天的文章里说了今天要写,所以今天一定要写出来.小编翻阅了很多资料,想要 ...

  4. .net Core学习笔记1 创建简单的 .net core项目

    1.打开vs2017>Web 1:创建实体类: namespace ProductMvc.Models { //商品类型 public class ProductType { public in ...

  5. .net core中的Options重新加载机制

    Options是.net core提出的一种辅助配置机制,即选项. 目前,我们可以使用的Options有五种(源码): IOptionsFactory<>:Options的创建工厂(Sin ...

  6. 在Asp.Net Core中添加区域的简单实现

    使用区域,可以有效的对业务进行隔离,各种业务及分工可以更灵活.在Asp.Net Core中启用区域也是极简单的. 使用步骤: 1.在 Startup.cs 中添加区域的路由: app.UseMvc(r ...

  7. .NET Core中Object Pool的简单使用

    前言 复用,是一个重要的话题,也是我们日常开发中经常遇到的,不可避免的问题. 举个最为简单,大家最为熟悉的例子,数据库连接池,就是复用数据库连接. 那么复用的意义在那里呢? 简单来说就是减少不必要的资 ...

  8. ASP.NET Core WebAPI帮助页--Swagger简单使用1.0

    1.什么是Swagger? Swagger是一个规范且完整的框架,提供描述.生产.消费和可视化RESTful API,它是为了解决Web API生成有用文档和帮助页的问题.   2.为啥选用swagg ...

  9. ASP.NET Core Blazor WebAssembly实现一个简单的TODO List

    基于blazor实现的一个简单的TODO List 最近看到一些大佬都开始关注blazor,我也想学习一下.做了一个小的demo,todolist,仅是一个小示例,参考此vue项目的实现http:// ...

随机推荐

  1. [POJ1961]Period (KMP)

    题意 求字符串s的最小循环元长度和循环次数 思路 s[1~i]满足循环元要len能整除i并且s[len+1~i]=s[1~i-len] 代码 #include<cstdio> #inclu ...

  2. git教程——安装配置

    Git(读音为/gɪt/.)是一个开源的分布式版本控制系统,可以有效.高速的处理从很小到非常大的项目版本管理. Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个 ...

  3. 201771010118 马昕璐 《面向对象设计 java》第十七周实验总结

    1.实验目的与要求 (1) 掌握线程同步的概念及实现技术: (2) 线程综合编程练习 2.实验内容和步骤 实验1:测试程序并进行代码注释. 测试程序1: l 在Elipse环境下调试教材651页程序1 ...

  4. codeforces 13 D

    给你500个红点和蓝点,让你找多少点红点构成的三角形里没有蓝点. 巧妙啊!我们考虑一个很远位置的点,不妨设这个为O,然后n^2枚举红点,考虑Oij里面蓝点的个数, 然后 对于 ijk这个三角形,我们可 ...

  5. PHP实现微信模板消息发送给指定用户

    使用公众号的模板消息功能,必须是认证过的服务号,需要发送微信号的openid,同一微信号在不同公众号下的openid是不同的,在公众号下是唯一的,获取不到微信号 进入公众平台  功能->模板消息 ...

  6. this全解js

    转(掘金) this关键字是JavaScript中最复杂的机制之一,是一个特别的关键字,被自动定义在所有函数的作用域中,但是相信很多JavaScript开发者并不是非常清楚它究竟指向的是什么.听说你很 ...

  7. 无需sendmail:巧用LD_PRELOAD突破disable_functions

    *本文原创作者:yangyangwithgnu,本文属FreeBuf原创奖励计划,未经许可禁止转载 摘要:千辛万苦拿到的 webshell 居然无法执行系统命令,怀疑服务端 disable_funct ...

  8. layui 表格内容显示更改

    在cole 中使用temple 属性进行修改 例: table.render({ elem: '#messageTable' ,id: 'search_table_mId' ,height: 500 ...

  9. python 中间件

    中间件一.什么是中间件 中间件是一个用来处理Django的请求和响应的框架级别的钩子.它是一个轻量.低级别的插件系统,用于在全局范围内改变Django 的输入和输出.每个中间件组件都负责做一些特定的功 ...

  10. 限制oracle某用户仅能从某IP登录

    system用户创建触发器,登录后触发检查 CREATE OR REPLACE TRIGGER system.check_ip_addresses_test AFTER logon ON DATABA ...