如何在.NET Core中实现自定义模型验证器

3

我需要在.NET Core项目中实现自定义模型验证器。由于需要进行复杂的验证,因此我避免使用属性验证。我使用了

IValidator

接口和

AbstractValidator

类来实现自定义验证。

public class UserModel : IValidatableObject {
    public int UserId { get; set; }
    public string UserName { get; set; }
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {

    }
}

但我需要将验证逻辑与模型分开。因此,我在ASP.NET MVC中找到了“最初的回答” -这里
public class ProjectModelValidatorProvider : ModelValidatorProvider {
    public override IEnumerable<ModelValidator> 
        GetValidators(ModelMetadata metadata, ControllerContext context) {
            if (metadata.ModelType == typeof(User))
                yield return new UserModelValidator(metadata, context);
    }
}

public class UserModelValidator : ModelValidator {
    public UserModelValidator(ModelMetadata metadata, ControllerContext controllerContext)
    : base(metadata, controllerContext) { }

    public override IEnumerable<ModelValidationResult> Validate(object container) {
    var model = (User)Metadata.Model;
    if (string.IsNullOrEmpty(model.Login))
        yield return new ModelValidationResult { 
            MemberName = "Login", 
            Message = "Please specify Login" 
        };


    }
}

// register your Provider
ModelValidatorProviders.Providers.Add(new ProjectModelValidatorProvider());

利用 ModelValidatorProviderModelValidator 的帮助,我实现了这一点。但在.NET Core中如何实现这一点,以便我可以使用 ModelState.IsValid 验证模型?"Original Answer"翻译成"最初的回答"
2个回答

4
在ASP.NET Core中,您可以自定义一个继承了IModelValidatorProvider接口的类,如下所示:
public class CustomModelValidatorProvider : IModelValidatorProvider
{
    public void CreateValidators(ModelValidatorProviderContext context)
    {
        if (context.ModelMetadata.ContainerType == typeof(User))
        {
            context.Results.Add(new ValidatorItem
            {
                Validator = new UserModelValidator(),
                IsReusable = true
            });
        }
    }
}

public class UserModelValidator : IModelValidator
{
    private static readonly object _emptyValidationContextInstance = new object();
    public IEnumerable<ModelValidationResult> Validate(ModelValidationContext validationContext)
    {
        var validationResults = new List<ModelValidationResult>();


        if (validationContext.ModelMetadata.Name == "FirstName" && validationContext.Model == null)
        {
            var validationResult = new ModelValidationResult("", "FirstName is required");

            validationResults.Add(validationResult);

        }
        return validationResults;
    }
}

您还可以在模型中添加partial关键字,以将验证逻辑与模型分开,参考以下代码:
public partial class User
{
    public int Id { get; set; }

    public string Gender { get; set; }

    [MaxLength(10)]
    public string FirstName { get; set; }

    [MaxLength(30)]
    public string LastName { get; set; }

    [EmailAddress]
    public string Email { get; set; }

    public List<UserGroups> UserGroups { get; set; }
    public List<Referal> Referals { get; set; }

}

public partial class User : IValidatableObject
{
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (string.IsNullOrEmpty(FirstName))
        {
            yield return new ValidationResult("FirstName is Required", new[] { "FirstName" });
        }
    }
}

我正在尝试实现第一个建议。有没有办法在ModelValidator内部注入repository?我在services.AddMvc(options => { options.ModelValidatorProviders.Add(new ModelValidatorProvider()); })中注册了modelvalidatorprovider。 - undefined
1
@artista_14 services.AddScoped<IModelValidatorProvider, ModelValidatorProvider>();services.AddMvc(options => { options.ModelValidatorProviders. Add(services.BuildServiceProvider().GetService<IModelValidatorProvider>() ); }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2); - undefined

0

我尝试使用了第一种方法。但是用户类的[MaxLength(10)]属性不再起作用。 我想要实现的效果是可以通过属性来控制。在通过验证后,可以进行自定义验证。


如果您使用自定义验证器,属性将不起作用。您必须明确编写所有验证。 - undefined
1
@artista_14 我尝试读取ValidationContext类的一些字段。发现了一个可以读取到属性的属性。我正在尝试手动触发模型验证。这似乎有效。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接