博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
看看.NET Core几个Options的简单使用
阅读量:6435 次
发布时间:2019-06-23

本文共 5072 字,大约阅读时间需要 16 分钟。

前言

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

由其是在配置中心(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
(Configuration.GetSection("Demo")); //others..}

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

private readonly DemoOptions _normal;public ValuesController(IOptions
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}";}

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

558945-20180616174910175-1294310592.png

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

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

558945-20180616174829953-2093910015.gif

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

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

下面来看看IOptionsSnapshot。

IOptionsSnapshot

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

private readonly DemoOptions _normal;private readonly DemoOptions _snapshot;public ValuesController(IOptions
normalAcc, IOptionsSnapshot
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}";}

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

558945-20180616174805146-641383358.gif

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

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

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

下面来看看。

IOptionsMonitor

private readonly DemoOptions _normal;private readonly DemoOptions _snapshot;private readonly DemoOptions _monitor;public ValuesController(IOptions
normalAcc, IOptionsSnapshot
snapshotAcc, IOptionsMonitor
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
(Configuration.GetSection("Demo")); services.PostConfigureAll
(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
(clientSection); var instSection = config.GetSection(EurekaInstanceOptions.EUREKA_INSTANCE_CONFIGURATION_PREFIX); services.Configure
(instSection); services.PostConfigure
((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
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
>(); 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。

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

558945-20180616175615376-2088179189.png

总结

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

转载于:https://www.cnblogs.com/catcher1994/p/9190978.html

你可能感兴趣的文章
Mac_安装Homebrew以及Maven
查看>>
eclipse web开发Server配置
查看>>
曹政--互联网搜索老师傅
查看>>
MUI框架开发HTML5手机APP(一)--搭建第一个手机APP(转)
查看>>
linux下使用 du查看某个文件或目录占用磁盘空间的大小
查看>>
[wp7软件]wp7~~各种视频播放器下载大全
查看>>
Java工程师必知之事 —— 如何定义自己的职业路线?
查看>>
代码质量与规范,那些年你欠下的技术债
查看>>
计算机程序的思维逻辑 (19) - 接口的本质
查看>>
CVE-2014-4113漏洞利用过程分析
查看>>
解密MSSQL链接数据库的密码
查看>>
Glide-源码详解
查看>>
你敢在post和get上刁难我,就别怪我装逼了
查看>>
直播 3.0 时代,在线教育行业的裂变和重构
查看>>
SpringBoot使用Nacos服务发现
查看>>
2017双11技术揭秘—阿里巴巴数据库技术架构演进
查看>>
我的友情链接
查看>>
Spring框架 - AOP使用
查看>>
Ansible常用内置属性
查看>>
C#使用正则表达式校验邮箱
查看>>