【问题标题】:ASP.NET Core validation: switch off server validation for some properties dynamicallyASP.NET Core 验证:动态关闭某些属性的服务器验证
【发布时间】:2020-11-19 21:45:38
【问题描述】:

有没有办法根据绑定的模型值关闭某些模型属性的验证。 示例:

public class ContactModel
{
    public string Name { get; set; }
    public string ContactType { get; set; }
    [Required]
    public string Phone { get; set; }
    [Required]
    public string Email { get; set; }
}

这是一些视图模型,它应该检索人的姓名,以及他的电话或电子邮件。如果用户选择其中之一,它应该只验证所选的一个。但选择电话时,Email为空,ModelState.IsValid == false,反之亦然。

我尝试加入验证过程(自定义 ValidationAttributeIValidatableObject)但没有成功,因为 ValidationContext 没有提供任何有用的上下文 - 我需要在验证 @ 时访问 ContactType 值987654327@。我什至尝试创建自定义活页夹,但在该阶段抑制验证并不能提供预期的结果,因为它只会将验证状态设置为未验证,即 ModelState.IsValid

目前我发现的唯一解决方案是创建ActionFilter/PageFilter,它将查找是否存在ContactModel 类型的任何模型,并从ModelState 中删除未使用字段的验证错误。但我对这种解决方案感到不舒服(对我来说似乎不合适)。 有什么想法吗?

【问题讨论】:

  • 有什么更新吗?我的回复对你有帮助吗?

标签: c# asp.net-core model-validation


【解决方案1】:

根据你的描述,我建议你可以考虑使用自定义的CustomModelValidator和自定义的ModelValidator来实现你的需求。

通过使用它,我们可以通过使用它的容器值来获取整个模型。

更多细节,您可以参考以下代码:

CustomModelValidatorProvider 类:

    public void CreateValidators(ModelValidatorProviderContext context)
    {
        if (context.ModelMetadata.ContainerType == typeof(ContactModel))
        {
            context.Results.Add(new ValidatorItem
            {
                Validator = new ContactModelValidator(),
                IsReusable = true
            });
        }
    }

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


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

                validationResults.Add(validationResult);

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

                validationResults.Add(validationResult);
            }


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

                validationResults.Add(validationResult);
            }

            if (validationContext.ModelMetadata.Name == "Phone" || validationContext.ModelMetadata.Name == "Email")
            {
                if (((ContactModel)validationContext.Container).Phone == null && ((ContactModel)validationContext.Container).Email == null)
                {
                    var validationResult = new ModelValidationResult("", "Phone or Email is required");

                    validationResults.Add(validationResult);
                }
            }

       



            return validationResults;
        }
    }

然后将其添加到startup.cs的ConfigureServices方法中:

        services.AddControllers(options=> {
            options.ModelValidatorProviders.Add(new CustomModelValidatorProvider()); 
        });

结果:

【讨论】:

  • 虽然它有效,但我不能接受它作为答案。通过在ContactModel 中实现IValidatableObject 并检查模型的实际值,可以更轻松地完成您所描述的相同操作。但这是我的错——为了尽可能简单,我选择了简单的例子。事实上,我的模型有一些列表和通用参数,这使得这种方法毫无用处。我必须找到不同的方法 - 在自定义模型绑定期间(无论如何我都必须这样做)我操纵 ValidationStateEntry 禁用对子模型选定部分的验证。无论如何 +1。
猜你喜欢
  • 2022-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-18
  • 1970-01-01
  • 1970-01-01
  • 2018-06-23
  • 2021-04-30
相关资源
最近更新 更多