I have a custom Required if that works fine. I then needed a Ranged If - Required if another item was a certain value, and it needs to be within a range. this does work - but does not throw the error under the box. I assume due to "return new ValidationResult". is there a way to just throw error in custom attributes that I'm missing that will link back to the text box?
Ranged if reads like this: Value I want to look at, the value I want to make it require, min and max values for the range.
public string IsMonetized { get; set; }
// [RequiredIf("IsMonetized", "Yes", "Please Enter a Value")]
// [Range(1, double.MaxValue, ErrorMessage = "Please Enter an Amount greater than 0")]
[RangedIf("IsMonetized", "Yes", 1, 200)]
public double MaxAmount { get; set; }
//[Range(1, 200, ErrorMessage = "Please Enter an Amount greater than 0")]
[RangedIf("IsMonetized", "Yes", 1, 200)]
public double? AnnualAmount { get; set; }
public class RangedIfAttribute : RequiredAttribute
{
private String PropertyName { get; set; }
private Object DesiredValue { get; set; }
private double max { get; set; }
private double min { get; set; }
public RangedIfAttribute(String propertyName, Object desiredvalue, double Min, double Max)
{
PropertyName = propertyName;
DesiredValue = desiredvalue;
min = Min;
max = Max;
}
public RangedIfAttribute(String propertyName, Object desiredvalue, double Min, double Max, String Errormessage)
{
PropertyName = propertyName;
DesiredValue = desiredvalue;
ErrorMessage = Errormessage;
min = Min;
max = Max;
}
protected override ValidationResult IsValid(object value, ValidationContext context)
{
Object instance = context.ObjectInstance;
Type type = instance.GetType();
Object proprtyvalue = type.GetProperty(PropertyName).GetValue(instance, null);
try
{
if (proprtyvalue == null)
{
if (DesiredValue == null)
{
if (min <= (double)value && (double)value <= max)
{
return base.IsValid(value, context); // Null was intended , and value in range - Valid
}
}
}
else if (proprtyvalue.ToString().Equals(DesiredValue))
{
if (min <= (double)value && (double)value <= max)
{
return base.IsValid(value, context); // desired = property value, and value in range - Valid
}
}
// This should submit Not Valid
return new ValidationResult(this.FormatErrorMessage(context.DisplayName));
}
catch
{
// this should submit not valid - the required item is null
return new ValidationResult($"Value must be within the range of {min} and {max}");
}
}
}
I have tried looking through all of the custom attributes information I can find and it seems nothing is coming up useful. the Validate.Success can send a successful validation, but it seems there is no Auto Failure (Validate.Failure). seems like an over site to the attribute system.
The boxes on both do nothing right away - and are not flagged - but a validation summary at the bottom will read:
The MaxAmount field is required. - Max Amount Field falls to the bottom with not matching the correct if logic.
Value must be within the range of 1 and 200 - annual amount will hit the try/catch since it was null and throws an error.
Again - it stops the form from submitting, but there is no indication what box (normally highlights red when validation fails) fails to validate.
the "fix" was this line for a false return:
return new ValidationResult($"Value must be within the range of {min} and {max}", new[] { context.MemberName });
Basically this allows the system to link back which entry box needed to be flagged, while you are able to send a custom message for each failed area. my bottom one could read "no null values" but having them say between A and B sounds better.
Here is the finished product:
[Required(ErrorMessage = "Please Select an Option")]
public string IsMonetized { get; set; }
[RangedIf("IsMonetized", "Yes", 1, 200)]
public double? AnnualAmount { get; set; }
public class RangedIfAttribute : RequiredAttribute
{
private String PropertyName { get; set; }
private Object DesiredValue { get; set; }
private double max { get; set; }
private double min { get; set; }
public RangedIfAttribute(String propertyName, Object desiredvalue, double Min, double Max)
{
PropertyName = propertyName;
DesiredValue = desiredvalue;
min = Min;
max = Max;
}
public RangedIfAttribute(String propertyName, Object desiredvalue, double Min, double Max, String Errormessage)
{
PropertyName = propertyName;
DesiredValue = desiredvalue;
ErrorMessage = Errormessage;
min = Min;
max = Max;
}
protected override ValidationResult IsValid(object value, ValidationContext context)
{
Object instance = context.ObjectInstance;
Type type = instance.GetType();
Object proprtyvalue = type.GetProperty(PropertyName).GetValue(instance, null);
try
{
if (proprtyvalue == null)
{
if (DesiredValue == null)
{
if (min <= (double)value && (double)value <= max)
{
return base.IsValid(value, context); // Null was intended , and value in range
}
else
{
return new ValidationResult($"Value must be within the range of {min} and {max}", new[] { context.MemberName }); // null was intended but value not in range
}
}
else
{
return ValidationResult.Success; //property value is null - needs to be selected first - do not trigger
}
}
else if (proprtyvalue.ToString().Equals(DesiredValue))
{
if (min <= (double)value && (double)value <= max)
{
return base.IsValid(value, context); // property = intended value and value in range
}
else
{
return new ValidationResult($"Value must be within the range of {min} and {max}", new[] { context.MemberName }); //property = inteded value but not in range
}
}
return ValidationResult.Success; //not required
}
catch
{
// most likely a null value
return new ValidationResult($"Value must be within the range of {min} and {max}", new[] { context.MemberName });
}
}
}