【问题标题】:ASP.NET Core - Custom model validationASP.NET Core - 自定义模型验证
【发布时间】:2017-10-11 18:01:00
【问题描述】:

在 MVC 中,当我们将模型发布到操作时,我们会执行以下操作以根据该模型的数据注释验证模型:

if (ModelState.IsValid)

如果我们将属性标记为 [Required],则 ModelState.IsValid 将验证该属性是否包含值。

我的问题:如何手动构建和运行自定义验证器?

附:我说的只是后端验证器。

【问题讨论】:

    标签: c# asp.net-core asp.net-core-mvc


    【解决方案1】:

    在 .NET Core 中,您可以简单地创建一个继承自 ValidationAttribute 的类。您可以在 ASP.NET Core MVC Docs 中查看完整的详细信息。

    这是直接取自文档的示例:

    public class ClassicMovieAttribute : ValidationAttribute
    {
        private int _year;
    
        public ClassicMovieAttribute(int Year)
        {
            _year = Year;
        }
    
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            Movie movie = (Movie)validationContext.ObjectInstance;
    
            if (movie.Genre == Genre.Classic && movie.ReleaseDate.Year > _year)
            {
                return new ValidationResult(GetErrorMessage());
            }
    
            return ValidationResult.Success;
        }
    }
    

    根据您的问题,我已对该示例进行了调整,以排除客户端验证。

    为了使用这个新属性(同样,取自文档),您需要将其添加到相关字段:

    [ClassicMovie(1960)]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    

    这是另一个更简单的示例,用于确保值为 true

    public class EnforceTrueAttribute : ValidationAttribute
    {
        public EnforceTrueAttribute()
            : base("The {0} field must be true.") { }
    
        public override bool IsValid(object value) =>
            value is bool valueAsBool && valueAsBool;
    }
    

    这以相同的方式应用:

    [EnforceTrue]
    public bool ThisShouldBeTrue { get; set; }
    

    编辑:请求的前端代码:

    <div asp-validation-summary="All" class="text-danger"></div>
    

    选项是 All、ModelOnly 或 None。

    【讨论】:

    • 能否也添加前端代码?它会帮助我和我怀疑的其他读者。
    • 文档here中提供了客户端实现的完整示例。
    • 我有一个问题,因为我的做法和你一模一样,但是,在客户端从不验证我的海关事情
    • @sgrysoft 这个答案不包括客户端验证。我在上面链接到解释如何做到这一点的文档。如果您遇到问题,请提出新问题并随时在此处发布指向该问题的链接。
    【解决方案2】:

    要在.Net Core 中创建自定义验证属性,您需要从IModelValidator 继承并实现Validate 方法。

    自定义验证器

    public class ValidUrlAttribute : Attribute, IModelValidator
    {
        public string ErrorMessage { get; set; }
    
        public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)
        {
            var url = context.Model as string;
            if (url != null && Uri.IsWellFormedUriString(url, UriKind.Absolute))
            {
                return Enumerable.Empty<ModelValidationResult>();
            }
    
            return new List<ModelValidationResult>
            {
                new ModelValidationResult(context.ModelMetadata.PropertyName, ErrorMessage)
            };
        }
    }
    

    型号

    public class Product
    {
        public int ProductId { get; set; }
    
        [Required]
        public string ProductName { get; set; }
    
        [Required]
        [ValidUrl]
        public string ProductThumbnailUrl { get; set; }
    }
    

    这种方法是否会提供在控制器操作方法中使用“ModelState.IsValid”属性的机会?

    是的! ModelState 对象将正确反映错误。

    这种方法可以应用于模型类吗?还是只能与模型类属性一起使用?

    我不知道这是否可以应用于班级级别。我知道您可以从ModelValidationContext 获取有关课程的信息:

    • context.Model:返回要验证的属性值
    • context.Container:返回包含该属性的对象
    • context.ActionContext:提供上下文数据并描述处理请求的动作方法
    • context.ModelMetadata:详细描述正在验证的模型类

    注意事项:

    按照 OP 中的要求,此验证属性不适用于客户端验证。

    【讨论】:

    • 是否可以在此验证期间为属性值分配值?这是个好主意吗?
    • 我已经删除了这个示例代码,所以我无法访问正在运行的代码并证明您可以为属性赋值。由于单一责任原则,我认为这无论如何都不是一个好主意?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-24
    相关资源
    最近更新 更多