背景/原因
- 项目中基本上都会用到配置文件写一些数据实现可配置无需发布代码的操作。比较常见的也是我个人用的比较多的是在逻辑处理部分直接注入配置文件进行指定获取某个属性值,还有一种是我最近才只晓的,就是使用强类型的方式,也是我个人使用后觉得值得推广的方式。
直接在逻辑代码中使用IConfiguration的方式
// appsettings.json
"Jwt": {
"Issuer": "qtoss",
"Audience": "qtoss",
"Key": "31ba6052aa6f4569901facc3a41fcb4a"
},
// 会员等级价格(单位:元)
"MemberPrices": {
"IsDebug": false,
// 月
"Month": {
"Standard": 1999,
"Advanced": 5999,
"AdvancedLevel": 36999
}
}
public class XXX{
private readonly IConfiguration _configuration;
public XXX(IConfiguration configuration)
{
_configuration = configuration;
}
public async Task Test(){
var isDebug = _configuration.GetValue<bool>("MemberPrices:IsDebug");
}
}
使用IOptions方式(推荐)
区别
- 强类型化:使用 IOptions
可以强类型化配置值,这意味着你可以使用特定的类型(如 JwtSettings)来访问配置值,而不是使用 IConfiguration 的字符串键值对。 - 配置值的封装:使用 IOptions
可以封装配置值,使其不直接暴露在代码中,这可以提高代码的安全性和可维护性。 - 依赖注入:使用 IOptions
可以通过依赖注入来提供配置值,这可以使代码更加松耦合和可测试。
好处
- 更好的代码组织:使用 IOptions
可以使代码更加组织化和结构化,因为配置值被封装在特定的类型中。 - 更好的可维护性:使用 IOptions
可以使代码更加可维护,因为配置值的变化不直接影响代码的逻辑。 - 更好的可测试性:使用 IOptions
可以使代码更加可测试,因为配置值可以被轻松地 mock 或 stub。 - 更好的安全性:使用 IOptions
可以提高代码的安全性,因为配置值不直接暴露在代码中。
何时使用 IConfiguration?
- 简单的配置值:如果你只需要访问简单的配置值(如字符串或整数),使用 IConfiguration 可能更方便。
- 动态配置值:如果你需要访问动态配置值(如从数据库或文件中加载的配置值),使用 IConfiguration 可能更合适。
何时使用 IOptions?
- 复杂的配置值:如果你需要访问复杂的配置值(如对象或集合),使用 IOptions
可能更合适。 - 封装配置值:如果你需要封装配置值使其不直接暴露在代码中,使用 IOptions
可能更合适。 - 依赖注入:如果你需要通过依赖注入来提供配置值,使用 IOptions
可能更合适。
使用 IOptions 必须要将所有对象属性都设置吗?
- 不一定。使用 IOptions
时,你可以选择只设置需要的属性,而不是所有。 - 如果你只设置了部分属性,其他属性将会使用其默认值。
使用 IOptions 步骤
- 创建一个类来封装配置值(如 Jwt,当然也可以将所有都新增一个类封装json中的所有配置数据)。
- 在 Startup.cs 中添加 IOptions
服务。 例1,只使用指定的配置内容。 builder.Services.Configure<JwtDto>(builder.Configuration.GetSection("Jwt"));
例2,使用所有的配置内容。
builder.Services.Configure<JwtDto>(builder.Configuration);
- 但是只是在Program.cs中如上两个例子中的代码,在执行到第三步骤后,请求接口时就会报错,大致意思是:无法解析XXX项目类型服务。尝试激活XXX项目时出现XXX对象(新建的封装类)。 结论:就是系统无法解析 封装的类 服务的实例,而这个服务是 XXX Controller 控制器所依赖的。虽然注册了服务,但是没有指定其生命周期。默认情况下,.NET Core 会将服务注册为单例(Singleton),但是如果你的服务需要在每次请求中重新创建实例,你需要注册为瞬态(Transient)或者作用域(Scoped)服务。这取决于你的服务需要什么样的生命周期。
builder.Services.AddScoped<Qtoss.Platform.Abstraction.Utilities.JsonSettings>(provider => { var configuration = provider.GetService<IConfiguration>(); var jsonSettings = new JsonSettings(); configuration.Bind(jsonSettings); //configuration?.GetSection("MemberPrices").Bind(jsonSettings);// 注入.json文件指定模块 return jsonSettings; }); // 如果需要注入多个模块(不是整个Json文件内容),那么需要再此写一个如上代码的方式进行注入即可。 ···
-
在需要使用配置值的类中注入 IOptions
服务。 // 可以直接不用 IOptions,我实际就是不用,直接写的封装实体类 public class XXXXController{ private readonly IOptions<JwtDto> _jwtDto; public XXXXController(IOptions<JwtDto> jwtDto){ _jwtDto = jwtDto; } public asyn Task TestA(){ var jwt = _jwtDto.Value;// 直接点指定需要的属性。 } }