C# 验证需要其他属性值的属性

C# 验证需要其他属性值的属性,c#,asp.net-mvc,model-binding,asp.net-mvc-validation,C#,Asp.net Mvc,Model Binding,Asp.net Mvc Validation,因此,我已经检查了这个答案,它没有涵盖我的问题 我正在使用服务器端验证。我有一个要求 仅当指定了其他属性时才需要值 问题 MVC绑定每个属性,并在绑定属性时调用该属性上的每个验证器。如果我在检查validationContext.ObjectInstance.[MY_dependent_PROPERTY]时依赖于设置的多个属性,则这些依赖属性可能尚未绑定 我需要的是一个validation属性,它在绑定后验证——如果存在的话 因此,这里有一个简单的例子来解释我的情况(不打算执行,因为这很可能是

因此,我已经检查了这个答案,它没有涵盖我的问题

我正在使用服务器端验证。我有一个要求

仅当指定了其他属性时才需要值

问题 MVC绑定每个属性,并在绑定属性时调用该属性上的每个验证器。如果我在检查
validationContext.ObjectInstance.[MY_dependent_PROPERTY]
时依赖于设置的多个属性,则这些依赖属性可能尚未绑定

我需要的是一个validation属性,它在绑定后验证——如果存在的话


因此,这里有一个简单的例子来解释我的情况(不打算执行,因为这很可能是好的,因为这个问题与约束性命令有关)

我的模型 我的验证器 本质上,这里发生的是它调用模型上的静态方法,以查看它是否应该验证

public sealed class RequiredIfAttribute : RequiredAttribute
{
    private readonly MethodInfo _validationMethod;
    public override bool RequiresValidationContext => true;

    public RequiredIfAttribute(Type type, string methodName)
    {
        this._validationMethod = type.GetMethod(methodName);
        if (this._validationMethod == null)
        {
            throw new MethodAccessException($"The validation method '{methodName}' does not exist on type '{type}");
        }
    }

    public override bool IsValid(object value)
    {
        throw new NotSupportedException();
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        ValidationResult result = ValidationResult.Success;

        var parameters = this._validationMethod.GetParameters();
        var returnType = this._validationMethod.ReturnType;

        if (returnType == typeof(bool) && parameters.Length == 1 && parameters[0].ParameterType == validationContext.ObjectType)
        {
            if ((bool)_validationMethod.Invoke(null, new object[] { validationContext.ObjectInstance }))
            {
                if (!base.IsValid(value))
                {
                    string[] memberNames;
                    if (validationContext.MemberName == null)
                    {
                        memberNames = null;
                    }
                    else
                    {
                        memberNames = new string[1];
                        memberNames[0] = validationContext.MemberName;
                    }
                    result = new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName), memberNames);
                }
            }
            return result;
        }

        var expectedFuncType = typeof(Func<,>).MakeGenericType(validationContext.ObjectType, typeof(bool));
        throw new MethodAccessException($"The validation method '{this._validationMethod}' does not have the correct definition. Expected '{expectedFuncType}'");
    }
}
公共密封类RequiredIFTTribute:RequiredAttribute
{
私有只读MethodInfo\u validationMethod;
public override bool RequiresValidationContext=>true;
public RequirediftAttribute(类型、字符串方法名)
{
此._validationMethod=type.GetMethod(methodName);
if(this.\u validationMethod==null)
{
抛出新的MethodAccessException($“验证方法{methodName}在类型{type}上不存在”);
}
}
公共覆盖布尔值有效(对象值)
{
抛出新的NotSupportedException();
}
受保护的重写ValidationResult有效(对象值,ValidationContext ValidationContext)
{
ValidationResult=ValidationResult.Success;
var parameters=this.\u validationMethod.GetParameters();
var returnType=此。_validationMethod.returnType;
if(returnType==typeof(bool)和¶meters.Length==1和¶meters[0]。ParameterType==validationContext.ObjectType)
{
if((bool)u validationMethod.Invoke(null,新对象[]{validationContext.ObjectInstance}))
{
如果(!base.IsValid(值))
{
字符串[]成员名称;
if(validationContext.MemberName==null)
{
memberNames=null;
}
其他的
{
memberNames=新字符串[1];
MemberName[0]=validationContext.MemberName;
}
结果=新的ValidationResult(this.FormatErrorMessage(validationContext.DisplayName),memberNames);
}
}
返回结果;
}
var expectedFuncType=typeof(Func).MakeGenericType(validationContext.ObjectType,typeof(bool));
抛出新的MethodAccessException($“验证方法{this.\u validationMethod}”没有正确的定义。应为{expectedFuncType}”);
}
}

所以我遇到的这个问题是我继承了
RequiredAttribute
。在内部,MVC处理该属性的方式与处理其他属性的方式不同

当模型绑定器在属性之间循环时,它会获取
RequiredAttribute
s并同时执行它们

// System.Web.Mvc.DefaultModelBinder.SetProperty
....
    ModelValidator modelValidator = (from v in ModelValidatorProviders.Providers.GetValidators(modelMetadata, controllerContext)
        where v.IsRequired
        select v).FirstOrDefault<ModelValidator>();
        if (modelValidator != null)
        {
            foreach (ModelValidationResult current in modelValidator.Validate(bindingContext.Model))
            {
                bindingContext.ModelState.AddModelError(key, current.Message);
            }
        }
....
//System.Web.Mvc.DefaultModelBinder.SetProperty
....
ModelValidator ModelValidator=(来自ModelValidatorProviders.Providers.GetValidators(modelMetadata,controllerContext)中的v)
需要v
选择v).FirstOrDefault();
if(modelValidator!=null)
{
foreach(modelValidator.Validate(bindingContext.Model))中的ModelValidationResult当前值
{
bindingContext.ModelState.AddModelError(key,current.Message);
}
}
....
v.IsRequired
实际上解析为一行,该行测试当前属性是否为
RequiredAttribute
,并将在当前不完整的模型状态下验证该属性

通过继承
ValidationAttribute
它在构建模型并解决我的问题后运行验证



感谢@StephenMuecke给我的提示。

您不希望客户端验证和服务器端验证有什么原因吗。您可以使用
[RequiredIfFalse(“PostalIsTheSameAsResidential”)]
或类似的验证属性(或者您可以轻松编写自己的-请注意,您应该继承自
ValidationAttribute
,而不是
RequiredAttribute
,并且您对绑定和验证工作方式的假设是不正确的-
validationContext
参数是有效的()
方法包含有关所需属性值的所有信息-
var property=validationContext.ObjectInstance.GetType().GetProperty(“PostListHeSameasResidential”);var propertyValue=property.GetValue(validationContext.ObjectInstance,null);
将返回您的
bool
属性的值。@StephenMuecke您的第二条评论就是问题所在。我将发表一篇文章作为回答您还应该注意另外两条(您编写的代码是完成此操作所需代码的两倍)
// System.Web.Mvc.DefaultModelBinder.SetProperty
....
    ModelValidator modelValidator = (from v in ModelValidatorProviders.Providers.GetValidators(modelMetadata, controllerContext)
        where v.IsRequired
        select v).FirstOrDefault<ModelValidator>();
        if (modelValidator != null)
        {
            foreach (ModelValidationResult current in modelValidator.Validate(bindingContext.Model))
            {
                bindingContext.ModelState.AddModelError(key, current.Message);
            }
        }
....