Eti*_*and 6 c# asp.net-mvc asp.net-core
我已经阅读了Options和Configuration基础知识的 Microsoft 文档,但仍然找不到在验证数据注释时将配置提取到对象中的正确方法。
我尝试过的一种方法 Startup.ConfigureServices
services.AddOptions<EmailConfig>().Bind(Configuration.GetSection("Email")).ValidateDataAnnotations();
Run Code Online (Sandbox Code Playgroud)
这“应该”允许通过在类构造函数中添加它来访问配置: (IOptions<EmailConfig> emailConfig)
但是它不起作用。
另一种方法是添加(IConfiguration configuration)到构造函数中,但这不允许我调用ValidateDataAnnotations.
configuration.GetSection("Email").Get<EmailConfig>();
Run Code Online (Sandbox Code Playgroud)
第一个问题:绑定和验证配置的责任属于 Startup 类还是使用它的类?如果它被多个类使用,我会说它属于 Startup;并且该类可以在具有不同配置布局的另一个项目中使用。
第二个问题:绑定和验证配置以便可以从类访问它的正确语法是什么?
第三个问题:如果我在 Startup 中通过数据注释进行验证,那么使用该配置的类会简单地假设配置是有效的,并且我不进行任何重新验证?
更新:在获得更多经验并查看我所有代码的结构后,我改变了我的方法以遵循标准模式。
以下代码确实有效...但仅在使用时对其进行验证。这可以在类库中注册,并且在使用特定服务之前不会抛出任何错误。
services.AddOptions<EmailConfig>()
.Bind(configuration.GetSection("Email"))
.ValidateDataAnnotations();
Run Code Online (Sandbox Code Playgroud)
然后,在配置中,我添加它以在启动时强制验证所需的配置值(CheckNotNull 是一个自定义扩展方法,重要的是您调用 IOptions.Value
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app?.ApplicationServices.GetService<IOptions<EmailConfig>>().Value.CheckNotNull("Config: Email");
app?.ApplicationServices.GetService<IOptions<OntraportConfig>>().Value.CheckNotNull("Config: Ontraport");
...
Run Code Online (Sandbox Code Playgroud)
然后在课堂上使用它
public class EmailService(IOptions<EmailConfig> config)
Run Code Online (Sandbox Code Playgroud)
较新版本的 .NET 添加了更多扩展方法来简化此过程。
注意:从技术上讲,这些都来自Microsoft.Extensions.XYZ与 .NET 一起发布的包。这些包也可能与早期版本的 .NET 兼容,但我尚未验证向后兼容性。
services.AddOptions<EmailConfig>()
.Bind(configuration.GetSection("Email"))
.ValidateDataAnnotations();
Run Code Online (Sandbox Code Playgroud)
现在可以简化为:
// Requires .NET 5 extensions or greater
services.AddOptions<EmailConfig>()
.BindConfiguration("Email")
.ValidateDataAnnotations();
Run Code Online (Sandbox Code Playgroud)
...并且为了在启动时(而不是使用选项时)进行急切验证,我们可以添加一行:
// Requires .NET 6 extensions or greater
services.AddOptions<EmailConfig>()
.BindConfiguration("Email")
.ValidateDataAnnotations()
.ValidateOnStart();
Run Code Online (Sandbox Code Playgroud)
我从 Andrew Lock 的博客文章中了解了这些更新。信任和感谢归于他:Addingvalidationtostrongtypedconfigurationobjectsin.NET6
在将它添加到服务集合之前,您可以尝试在启动时自己验证该类。
启动
var settings = Configuration.GetSection("Email").Get<EmailConfig>();
//validate
var validationResults = new List<ValidationResult>();
var validationContext = new ValidationContext(settings, serviceProvider: null, items: null);
if (!Validator.TryValidateObject(settings, validationContext, validationResults,
validateAllProperties: true)) {
//...Fail early
//will have the validation results in the list
}
services.AddSingleton(settings);
Run Code Online (Sandbox Code Playgroud)
这样你就不会被耦合,IOptions并且你也允许你的代码提前失败,你可以在需要的地方显式注入依赖项。
您可以将验证打包到您自己的扩展方法中,例如
public static T GetValid<T>(this IConfiguration configuration) {
var obj = configuration.Get<T>();
//validate
Validator.ValidateObject(obj, new ValidationContext(obj), true);
return obj;
}
Run Code Online (Sandbox Code Playgroud)
对于像这样的电话
EmailConfig emailSection = Configuration.GetSection("Email").GetValid<EmailConfig>();
services.AddSingleton(emailSection);
Run Code Online (Sandbox Code Playgroud)
在内部,ValidateDataAnnotations基本上是在做同样的事情。
/// <summary>
/// Validates a specific named options instance (or all when name is null).
/// </summary>
/// <param name="name">The name of the options instance being validated.</param>
/// <param name="options">The options instance.</param>
/// <returns>The <see cref="ValidateOptionsResult"/> result.</returns>
public ValidateOptionsResult Validate(string name, TOptions options)
{
// Null name is used to configure all named options.
if (Name == null || name == Name)
{
var validationResults = new List<ValidationResult>();
if (Validator.TryValidateObject(options,
new ValidationContext(options, serviceProvider: null, items: null),
validationResults,
validateAllProperties: true))
{
return ValidateOptionsResult.Success;
}
return ValidateOptionsResult.Fail(String.Join(Environment.NewLine,
validationResults.Select(r => "DataAnnotation validation failed for members " +
String.Join(", ", r.MemberNames) +
" with the error '" + r.ErrorMessage + "'.")));
}
// Ignored if not validating this instance.
return ValidateOptionsResult.Skip;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2808 次 |
| 最近记录: |