Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/cmake/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在IValidateOptions内部触发模型验证<;T>;实施_C#_Asp.net Web Api_.net Core_Asp.net Core Webapi_.net 5 - Fatal编程技术网

C# 如何在IValidateOptions内部触发模型验证<;T>;实施

C# 如何在IValidateOptions内部触发模型验证<;T>;实施,c#,asp.net-web-api,.net-core,asp.net-core-webapi,.net-5,C#,Asp.net Web Api,.net Core,Asp.net Core Webapi,.net 5,我有一个.Net 5应用程序,希望为我的配置添加验证程序。给定此示例选项 public sealed class DatabaseOptions { public string ConnectionString { get; set; } } 我目前用这个实现来验证它 public sealed class DatabaseOptionsValidator : IValidateOptions<DatabaseOptions> { public ValidateOp

我有一个.Net 5应用程序,希望为我的配置添加验证程序。给定此示例选项

public sealed class DatabaseOptions
{
    public string ConnectionString { get; set; }
}
我目前用这个实现来验证它

public sealed class DatabaseOptionsValidator : IValidateOptions<DatabaseOptions>
{
    public ValidateOptionsResult Validate(string name, DatabaseOptions databaseOptions)
    {
        List<string> validationFailures = new List<string>();

        if (string.IsNullOrEmpty(databaseOptions.ConnectionString))
            validationFailures.Add($"{nameof(databaseOptions.ConnectionString)} is required.");

        // ...

        if (validationFailures.Any())
        {
            return ValidateOptionsResult.Fail(validationFailures);
        }

        return ValidateOptionsResult.Success;
    }
}
并希望找到一种方法来触发模型验证

public sealed class DatabaseOptionsValidator : IValidateOptions<DatabaseOptions>
{
    public ValidateOptionsResult Validate(string name, DatabaseOptions databaseOptions)
    {
        List<string> validationFailures = new List<string>();

        // trigger the model validation and add every error to the validationFailures list

        if (validationFailures.Any())
        {
            return ValidateOptionsResult.Fail(validationFailures);
        }

        return ValidateOptionsResult.Success;
    }
}
公共密封类数据库选项验证器:IValidateOptions
{
公共ValidateOptions结果验证(字符串名称、数据库选项DatabaseOptions)
{
列表验证失败=新建列表();
//触发模型验证并将每个错误添加到validationFailures列表
if(validationFailures.Any())
{
返回ValidateOptions结果失败(validationFailures);
}
返回ValidateOptionsResult.Success;
}
}

但不幸的是我没能做到。调试器命中了验证器,但如何在验证方法内触发验证?

我使用一种技术来验证netcore应用程序中的数据批注,不是使用
IValidateOptions
,而是实现自定义验证器,并将其注册为
PostConfigure

您可以在命名空间
System.ComponentModel.DataAnnotations
中找到有价值的资产

大概是这样的:

    // Custom validator for data annotations
    public static class Validation {
        public static void ValidateDataAnotations<TOptions>(TOptions options) {
            var context = new ValidationContext(options);
            var results = new List<ValidationResult>();
            Validator.TryValidateObject(options, context, results, validateAllProperties: true);
            if (results.Any()) {
                var aggrErrors = string.Join(' ', results.Select(x => x.ErrorMessage));
                var count = results.Count;
                var configType = typeof(TOptions).Name;
                throw new ApplicationException($"Found {count} configuration error(s) in {configType}: {aggrErrors}");
            }
        }
    }

请查看评论,因为我的解决方案已经可用


基于,我基于数据注释创建了自己的选项验证器

public sealed class OptionsValidator<TOptions> : IValidateOptions<TOptions> where TOptions : class
{
    public ValidateOptionsResult Validate(string name, TOptions options)
    {
        ValidationContext validationContext = new ValidationContext(options);
        List<ValidationResult> validationResults = new List<ValidationResult>();
        bool noValidationErrorsOccured = Validator.TryValidateObject(options, validationContext, validationResults, true);
        
        if (noValidationErrorsOccured) {
            return ValidateOptionsResult.Success;
        }
        
        IEnumerable<string> validationFailures = validationResults.Select(validationResult => validationResult.ErrorMessage);
        
        return ValidateOptionsResult.Fail(validationFailures);
    }
}
公共密封类选项Validator:IValidateOptions其中TopOptions:class
{
公共验证选项结果验证(字符串名称、选项)
{
ValidationContext ValidationContext=新的ValidationContext(选项);
列表验证结果=新列表();
bool noValidationErrorsOccured=Validator.TryValidateObject(选项、validationContext、validationResults、true);
如果(noValidationErrorsOccured){
返回ValidateOptionsResult.Success;
}
IEnumerable validationFailures=validationResults.Select(validationResult=>validationResult.ErrorMessage);
返回ValidateOptions结果失败(validationFailures);
}
}
因此,每当我想向DI容器添加验证器时,我都可以使用这个扩展方法

public static IServiceCollection AddOptionsValidator<TOptions>(this IServiceCollection serviceCollection) where TOptions : class
    => serviceCollection.AddSingleton<IValidateOptions<TOptions>, OptionsValidator<TOptions>>();
公共静态IServiceCollection AddOptionsValidator(此IServiceCollection服务集合),其中TopOptions:class
=>serviceCollection.AddSingleton();

您是否可以通过
ValidateDataAnnotations
使用DataAnnotations验证程序?看这里。不是完全重复,但问题本身显示了一个示例,答案显示了data annotations validator实际上是如何在内部工作的,因此您可以在必要时复制该实现。它实际上相当基本这真的很好,我发布了另一个解决方案:)请注意,这本质上就是ValidateDataAnnotations所做的。为什么要重新发明轮子?@pinkfloydx33对不起,我以为这是一个定制的实现。我该如何在我的验证器中使用它?我有一个.NET5应用程序,但找不到类似的东西,我该在哪里调用它?我在DI服务注册中查找了它,但也将其作为静态方法从静态帮助中查找。您需要DataAnnotations包,并在OptionBuilder上调用它。我在你的专栏文章中链接的答案的链接中有一些例子。但是如果你查看官方文档,标题“选项验证”大约在中间,它们会准确地显示如何使用DataAnnotations包。你不需要你自己的验证器,你只需要使用他们的。啊,很酷。所以一切都保持不变,但我可以调用
serviceCollection.AddSingleton()
,而不是调用
serviceCollection.AddOptions().ValidateDataAnnotations()
public sealed class OptionsValidator<TOptions> : IValidateOptions<TOptions> where TOptions : class
{
    public ValidateOptionsResult Validate(string name, TOptions options)
    {
        ValidationContext validationContext = new ValidationContext(options);
        List<ValidationResult> validationResults = new List<ValidationResult>();
        bool noValidationErrorsOccured = Validator.TryValidateObject(options, validationContext, validationResults, true);
        
        if (noValidationErrorsOccured) {
            return ValidateOptionsResult.Success;
        }
        
        IEnumerable<string> validationFailures = validationResults.Select(validationResult => validationResult.ErrorMessage);
        
        return ValidateOptionsResult.Fail(validationFailures);
    }
}
public static IServiceCollection AddOptionsValidator<TOptions>(this IServiceCollection serviceCollection) where TOptions : class
    => serviceCollection.AddSingleton<IValidateOptions<TOptions>, OptionsValidator<TOptions>>();