C# ASP.NET核心验证:动态关闭某些属性的服务器验证

C# ASP.NET核心验证:动态关闭某些属性的服务器验证,c#,asp.net-core,model-validation,C#,Asp.net Core,Model Validation,是否有一种方法可以基于绑定模型值关闭某些模型属性的验证。 例如: 这是一个视图模型,它应该检索此人的姓名,以及他的电话或电子邮件。如果用户选择其中一个,它应该只验证所选的一个。但当选择Phone且电子邮件为空时,ModelState.IsValid==false,反之亦然 我曾尝试连接到验证过程(自定义ValidationAttribute,IValidatableObject),但没有成功,因为ValidationContext没有提供任何有用的上下文-在验证电话/电子邮件时,我需要访问联系人

是否有一种方法可以基于绑定模型值关闭某些模型属性的验证。 例如:

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

我曾尝试连接到验证过程(自定义
ValidationAttribute
IValidatableObject
),但没有成功,因为ValidationContext没有提供任何有用的上下文-在验证
电话/电子邮件时,我需要访问
联系人类型
值。我甚至尝试创建自定义绑定,但在该阶段取消验证并不能提供预期结果,因为它只会将验证状态设置为未验证,这被视为
ModelState.IsValid

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

< P>根据您的描述,我建议您可以考虑使用自定义CuoMealValueAudio和自定义模型验证器来实现您的要求。

通过使用它,我们可以使用它的容器值得到整个模型

更多详细信息,请参考以下代码:

CustomModelValidator提供程序类:

    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;
        }
    }
结果:


有更新吗?我的回答对你有帮助吗?虽然有效,但我不能接受它作为回答。通过在
ContactModel
中实现
IValidatableObject
并检查模型的实际值,可以更轻松地完成上述操作。但这是我的错——在追求尽可能简单的过程中,我选择了简单的例子。事实上,我的模型有一些列表和泛型参数,这使得这个方法毫无用处。我必须找到不同的方法-在自定义模型绑定期间(无论如何我都必须这么做),我操作
validationstatentry
,它禁用子模型选定部分的验证+1无论如何。
    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;
        }
    }
        services.AddControllers(options=> {
            options.ModelValidatorProviders.Add(new CustomModelValidatorProvider()); 
        });