同时Options模式也提供了一种数据验证的机制。
"Position": { "Title": "Editor", "Name": "Joe Smith" }接着在项目文件夹下创建PositionOptions类:
builder.Services.Configure<PositionOptions>( builder.Configuration.GetSection(PositionOptions.Position));有了上面的配置我们可以使用下面代码读取该配置:
using AspNetCore.OptionsPattern.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; namespace AspNetCore.OptionsPattern.Controllers { public class IOptionsInterfaceController : Controller { private IOptions<PositionOptions> _positionOptions; public IOptionsInterfaceController(IOptions<PositionOptions> options) { _positionOptions = options; } public IActionResult Index() { return View(_positionOptions.Value); } } }2.2 IOptionsSnapshot<TOptions>接口
using AspNetCore.OptionsPattern.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; namespace AspNetCore.OptionsPattern.Controllers { public class IOptionsSnapshotInterfaceController : Controller { private IOptionsSnapshot<PositionOptions> _optionsSnapshot; public IOptionsSnapshotInterfaceController(IOptionsSnapshot<PositionOptions> optionsSnapshot) { _optionsSnapshot = optionsSnapshot; } public IActionResult Index() { return View(_optionsSnapshot.Value); } } }2.3 IOptionsMonitor<TOptions>接口
using AspNetCore.OptionsPattern.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; namespace AspNetCore.OptionsPattern.Controllers { public class IOptionsMonitorInterfaceController : Controller { private IOptionsMonitor<PositionOptions> _positionOptions; public IOptionsMonitorInterfaceController(IOptionsMonitor<PositionOptions> optionsMonitor) { _positionOptions = optionsMonitor; } public IActionResult Index() { return View(_positionOptions.CurrentValue); } } }三. Options数据验证
"MyConfig": { "Key1": "My Key One", "Key2": 10, "Key3": 32 }我们在定义一个类来绑定上面节点:
namespace AspNetCore.OptionsPattern.Models { public class MyConfigOptions { public const string MyConfig = "MyConfig"; // 堆代码 duidaima.com [RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$")] public string Key1 { get; set; } [Range(0, 1000, ErrorMessage = "Value for {0} must be between {1} and {2}.")] public int Key2 { get; set; } public int Key3 { get; set; } } }在启动类中添加如下代码:
builder.Services.AddOptions<MyConfigOptions>() .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig)) .ValidateDataAnnotations();调用AddOptions方法来获取一个OptionsBuilder<TOptions>对象,绑定到MyConfigOptions类,ValidateDataAnnotations方法来启用DataAnnotations的验证
builder.Services.AddOptions<MyConfigOptions>() .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig)) .ValidateDataAnnotations() .Validate(config => { if (config.Key2 != 0) { return config.Key3 > config.Key2; } return true; }, "Key3 must be > than Key2.");我们也可以将验证逻辑放到单独的类中来实现。我们也可以自定义一个类来实现IValidateOptions<TOptions>实现我们的验证逻辑,接下来我们自定义一个验证逻辑类:
using Microsoft.Extensions.Options; using System.Text.RegularExpressions; namespace AspNetCore.OptionsPattern.Models { public class MyConfigValidation : IValidateOptions<MyConfigOptions> { public MyConfigOptions _config { get; private set; } public MyConfigValidation(IConfiguration config) { _config = config.GetSection(MyConfigOptions.MyConfig) .Get<MyConfigOptions>(); } public ValidateOptionsResult Validate(string name, MyConfigOptions options) { string? vor = null; var rx = new Regex(@"^[a-zA-Z''-'\s]{1,40}$"); var match = rx.Match(options.Key1!); if (string.IsNullOrEmpty(match.Value)) { vor = $"{options.Key1} doesn't match RegEx \n"; } if (options.Key2 < 0 || options.Key2 > 1000) { vor = $"{options.Key2} doesn't match Range 0 - 1000 \n"; } if (_config.Key2 != default) { if (_config.Key3 <= _config.Key2) { vor += "Key3 must be > than Key2."; } } if (vor != null) { return ValidateOptionsResult.Fail(vor); } return ValidateOptionsResult.Success; } } }修改启动类中的配置:
builder.Services.AddOptions<MyConfigOptions>() .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig)); builder.Services.AddSingleton<IValidateOptions <MyConfigOptions>, MyConfigValidation>();