前言
配置在我们开发过程中必不可少,asp.net中的配置在 web.config
中。也可配置在如:json、xml、数据库等(但asp.net并没提供相应的模块和方法)。
在asp.net core中web.config已经不存在了(但如果托管到 iis 的时候可以使用 web.config 配置 iis),
而是用appsettings.json和appsettings.(development、staging、production).json配置文件
(可以理解为asp.net中的web.config和web.release.config的关系)。
下面我们一起看下asp.net core 中的配置
基础用法
homecontroller.cs
:
[apicontroller] public class homecontroller : controllerbase { private readonly iconfiguration _configuration; public homecontroller(iconfiguration configuration) { _configuration = configuration; } [httpget("/")] public dynamic index() { return jsonconvert.serializeobject(new { connectionstring = _configuration["connectionstring"], child1 = _configuration["parent:child1"], grandchildren = _configuration["parent:child2:grandchildren"] }); } }
返回结果:
{ "connectionstring": "data source=.;initial catalog=test;user id=sa", "child1": "child", "grandchildren": "grandchildren" }
对应appsettings.json
的值:
{ "connectionstring": "data source=.;initial catalog=test;user id=sa;password=123", "parent": { "child1": "child1", "child2": "child2" } }
如果键名相同(包含所有加载的配置文件),以最后一个值为准。
所以appsettings.(development、staging、production).json
会覆盖appsettings.json
的配置信息。
:
来分割,但如果是环境变量则存在跨平台问题 appsettings.json
修改后,获取的值会立即改变绑定到对象 ioptions<testoptions>
_configuration["parent:child2:grandchildren"]
的写法对程序员来说肯定很反感,下面我们看下把配置文件绑定到对象中。首先把 json 对象转换成对象
public class testoptions { public string connectionstring { get; set; } public parent parent { get; set; } } public class parent { public string child1 { get; set; } public child2 child2 { get; set; } } public class child2 { public string grandchildren { get; set; } }
在startup.cs
的configureservices
方法添加代码:
services.configure<testoptions>(configuration);
homecontroller.cs
:
[apicontroller] public class homecontroller : controllerbase { private readonly ioptions<testoptions> _options; public homecontroller(ioptions<testoptions> options) { _options = options; } [httpget("options")] public string options() { return jsonconvert.serializeobject(_options); } }
返回的结果如下:
{ "value": { "connectionstring": "data source=.;initial catalog=test;user id=sa", "parent": { "child1": "child", "child2": { "grandchildren": "grandchildren" } } } }
appsettings.json
,然后刷新页面,会发现值并没用变我们发现根节点是value
根据上面 2 个问题我们去看源代码:
首先找到这句:
services.tryadd(servicedescriptor.singleton(typeof(ioptions<>), typeof(optionsmanager<>)));
我们去看optionsmanager
方法:
public class optionsmanager<toptions> : ioptions<toptions>, ioptionssnapshot<toptions> where toptions : class, new() { private readonly ioptionsfactory<toptions> _factory; // 注解: _cache 为 concurrentdictionary<string, lazy<toptions>>() // 不知道注意到上面注入方法没,用的是 singleton 单例,所以更新配置文件后没及时更新 private readonly optionscache<toptions> _cache = new optionscache<toptions>(); public optionsmanager(ioptionsfactory<toptions> factory) { _factory = factory; } /// <summary> /// toptions的默认配置实例 /// 这里就是为什么根节点为value /// </summary> public toptions value { get { return get(options.defaultname); } } /// <summary> /// 该方法在 ioptionssnapshot 接口中 /// </summary> public virtual toptions get(string name) { name = name ?? options.defaultname; // store the options in our instance cache return _cache.getoradd(name, () => _factory.create(name)); } }
绑定到对象 ioptionssnapshot<testoptions>
与 ioptions<testoptions>
的用法一样,区别就是依赖注入的生命周期为scoped,所以没缓存,直接看代码:
services.tryadd(servicedescriptor.scoped(typeof(ioptionssnapshot<>), typeof(optionsmanager<>)));
ioptionssnapshot<toptions> 比 ioptions<toptions> 多了个方法toptions get(string name);
value
属性其实就是调用了该方法,只是name
为options.defaultname
ioptionssnapshot<toptions> 继承了 ioptions<toptions> (这里有个疑问,上面的optionsmanager<toptions>
继承了ioptions<toptions>, ioptionssnapshot<toptions>
2 个接口,也许是为了清晰吧)。
自定义配置文件(json)
有的时候配置信息很多,想在单独的文件中配置,asp.net core 提供了ini、xml、json文件系统加载配置的方法。
首先在 program.cs的createwebhostbuilder
方法中添加如下代码:
public static iwebhostbuilder createwebhostbuilder(string[] args) { return webhost.createdefaultbuilder(args) .configureappconfiguration((hostingcontext, config) => { //设置根目录,我们放在 /config 文件夹下 // 此种写法不会加载 `appsettings.json` // config.setbasepath(path.combine(directory.getcurrentdirectory(), "config")); config.setbasepath(directory.getcurrentdirectory()); //添加 setting.json 配置文件 //optional: 文件是否可选,当为false时 如果文件不存在 程序启动不起来 //reloadonchange:文件改变后是否重新加载 config.addjsonfile("config/setting.json", optional: false, reloadonchange: false); }) .usestartup<startup>(); }
if (source.reloadonchange && source.fileprovider != null) { changetoken.onchange( //监视文件 如果改变就执行 load(true) 方法 () => source.fileprovider.watch(source.path), () => { thread.sleep(source.reloaddelay); load(reload: true); }); }
创建setting.json:
{ "rookie": { "name": "ddd", "age": 12, "sex": "男" } }
在 controller 中:
[route("api/[controller]")] [apicontroller] public class optionscontroller : controllerbase { private readonly iconfiguration _configuration; public optionscontroller(iconfiguration configuration) { _configuration = configuration; } [httpget] public string index() { return jsonconvert.serializeobject(new { name = _configuration["rookie:name"], age = _configuration["rookie:age"], sex = _configuration["rookie:sex"] }); } }
自定义配置文件(json)绑定到对象
_configuration["name"]
方式,下面我们绑定到对象上定义配置对象 setting 类
在startup.cs的configureservices
方法添加代码:
services.configure<setting>(configuration.getsection("rookie"));
getsection
方法:获得指定键的配置子部分
用法和上面一样
首先删除 program.cs中createwebhostbuilder
方法的代码:
config.addjsonfile("config/setting.json", optional: false, reloadonchange: true);
修改配置文件setting.json:
{ "name": "ddd", "age": 12, "sex": "男" }
在中startup.cs的configureservices
方法中添加:
var config = new configurationbuilder() .setbasepath(directory.getcurrentdirectory()) .addjsonfile("config/setting.json", optional: false, reloadonchange: true) .build(); services.configure<setting>(config);
其他方式
我们看下下面 2 个方式:
[route("[controller]")] [apicontroller] public class homecontroller : controllerbase { private readonly iconfiguration _configuration; private readonly testoptions _bindoptions = new testoptions(); private readonly parent _parent = new parent(); public homecontroller(iconfiguration configuration) { //全部绑定 _configuration.bind(_bindoptions); //部分绑定 _configuration.getsection("parent").bind(_parent); } [httpget("options")] public string options() { return jsonconvert.serializeobject(new { bindoptions = _bindoptions, parent = _parent }); } }
个人感觉这种方式有点多余 ( ╯□╰ )
ioptionsmonitor、ioptionsfactory、ioptionsmonitorcache 方式:
我们看如下代码
services.tryadd(servicedescriptor.singleton(typeof(ioptions<>), typeof(optionsmanager<>))); services.tryadd(servicedescriptor.scoped(typeof(ioptionssnapshot<>), typeof(optionsmanager<>))); services.tryadd(servicedescriptor.singleton(typeof(ioptionsmonitor<>), typeof(optionsmonitor<>))); services.tryadd(servicedescriptor.transient(typeof(ioptionsfactory<>), typeof(optionsfactory<>))); services.tryadd(servicedescriptor.singleton(typeof(ioptionsmonitorcache<>), typeof(optionscache<>)));
这里只说下 ioptionsmonitor<>
:
[route("[controller]")] [apicontroller] public class homecontroller : controllerbase { private readonly ioptionsmonitor<testoptions> _optionsmonitor; public homecontroller(ioptionsmonitor<testoptions> optionsmonitor , ilogger<homecontroller> logger) { _optionsmonitor = optionsmonitor; _logger = logger; } [httpget("options")] public string options() { //这里有个变更委托 _optionsmonitor.onchange((options, name) => { var info = jsonconvert.serializeobject(new { options = options, name = name }); _logger.loginformation($"配置信息已更改:{info}"); }); return jsonconvert.serializeobject(new { optionsmoitor = _optionsmonitor }); }
当我们修改配置文件后会看到日志信息:
info: webapisample.controllers.homecontroller[0]
配置信息已更改:{"options":{"connectionstring":"data source=.;initial catalog=test;user id=sa","parent":{"child1":"child","child2":{"grandchildren":"grandchildren"}}},"name":"testoptions"}
info: webapisample.controllers.homecontroller[0]
配置信息已更改:{"options":{"connectionstring":"data source=.;initial catalog=test;user id=sa","parent":{"child1":"child","child2":{"grandchildren":"grandchildren"}}},"name":"testoptions"}
info: webapisample.controllers.homecontroller[0]
配置信息已更改:{"options":{"connectionstring":"data source=.;initial catalog=test;user id=sa","parent":{"child1":"child","child2":{"grandchildren":"grandchildren"}}},"name":"testoptions"}
info: webapisample.controllers.homecontroller[0]
配置信息已更改:{"options":{"connectionstring":"data source=.;initial catalog=test;user id=sa","parent":{"child1":"child","child2":{"grandchildren":"grandchildren"}}},"name":"testoptions"}
不知道为什么会有这么多日志...
还有一点不管我们修改哪个日志文件,只要是执行了addjsonfile
的文件,都会触发该事件
写在最后
写的有点乱希望不要见怪,本以为一个配置模块应该不会复杂,但看了源代码后发现里面的东西好多... 本来还想写下是如何实现的,但感觉太长了就算了。 最后还是希望大家以批判的角度来看,有任何问题可在留言区留言!
如对本文有疑问, 点击进行留言回复!!
Mobilenetv3-ssd训练VOC格式数据集loss出现nan:数据本身出现问题
Android PackageManagerService(二)下载安装详解
Asp.Net Core 3.1 Web Api 返回数据字段被转换为小驼峰格式的解决办法
已知两点经纬度,计算偏移角(正北为0,顺时针为正,逆时针为负)
解决问题“Could not load file or assembly xxxxxxx or one of its dependencies”
网友评论