简体   繁体   中英

.NET 6 Blazor Server App - Custom Data Validation Annotation Not Operating Properly

I have an EditForm that has three properties, one of which at least must be specified and cannot be empty/white space. To enforce this, I built a custom "RequiredIf" data annotation with the following code inside of the "IsValid" method:

protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
{
    if (value != null)
    {
        return ValidationResult.Success;
    }

    int numberOfInvalidProperties = 0;

    object instance = validationContext.ObjectInstance;
    Type containerType = instance.GetType();
    Type type = instance.GetType();

    for (int i = 0; i < this.PropertyNames.Length; i++)
    {
        PropertyInfo? otherProperty = validationContext.ObjectType.GetProperty(this.PropertyNames[i]);

        if (otherProperty == null)
        {
            return new ValidationResult(string.Format(CultureInfo.CurrentCulture, "Could not find a property named '{0}'.", this.PropertyNames[i]));
        }

        object? propertyValue = otherProperty.GetValue(validationContext.ObjectInstance);

        if (propertyValue == this.DesiredValues[i])
        {
            numberOfInvalidProperties++;
        }
        else if (otherProperty?.PropertyType == typeof(string))
        {
            // treat empty strings as null
            if (this.DesiredValues[i] == null && string.IsNullOrWhiteSpace((string?)propertyValue))
            {
                numberOfInvalidProperties++;
            }
        }
    }

    if (numberOfInvalidProperties == this.PropertyNames.Length)
    {
        return new ValidationResult(this.ErrorMessage, new[] { validationContext.MemberName }!);
    }
    else
    {
        return ValidationResult.Success;
    }
}

In turn, my model has the following three properties with this custom annotation set:

[RequiredIf(new string[] { "OrderNumber", "InternalOrderNumber" }, new object?[] { null, null }, ErrorMessage = "At least one of these is required")]
public string CardStatementId { get; set; }

[RequiredIf(new string[] { "OrderNumber", "CardStatementId" }, new object?[] { null, null }, ErrorMessage = "At least one of these is required")]
public string InternalOrderNumber { get; set; }

[RequiredIf(new string[] { "CardStatementId", "InternalOrderNumber" }, new object?[] { null, null }, ErrorMessage = "At least one of these is required")]
public string OrderNumber { get; set; }

When I try to submit the form with no value specified on any of the properties, I get the "At least one of these is required" error message to appear on all three. Now here are the two issues I am running into:

  1. When I specify a valid value in any of those three properties, the error message only goes away from the property who had the value entered for. The error message does not clear off of the other two properties. This does not prevent the form from submitting.
  2. The second issue is that while even though the "IsValid" code above is checking for whitespace strings, it is not showing any error message even though it does enter the numberOfInvalidProperties == this.PropertyNames.Length code branch.

Can anyone spot the issue at play here? Am I missing a "StateHasChanged" call somewhere or are custom validation annotations not bound into the same behavioral context as the built in ones?

EditFormExampleWithCustomAnnotations

I'm speculating here. But do you have a module for purchase order and one of card-statment?

I'm not sure, but i believe when your creating a purchase order, it retrieves a null object. Or p-card-statement id is null. Have you checked what kind of value your getting when your retrieving the data and checking if they are valid.

I would recommend using the deBugger and checking the value for those two. Another thing you might need to check, which i often miss is to use the Include method. If your working with joint tables.

When I specify a valid value in any of those three properties, the error message only goes away from the property who had the value entered for. The error message does not clear off of the other two properties. This does not prevent the form from submitting

This is normal. You have placed validation on individual fields. Well, any field whose value is not validated will show an error message. To fix this problem, it is better to apply your validation to the model. For Example:

 public class CustomAnnotationValidator : ValidationAttribute
{
    protected override ValidationResult
    IsValid(object value, ValidationContext validationContext)
    {
        OrderModel orderModel = (OrderModel)value;
        bool resultFlag = true;
        string errorMessage = "";

        if (string.IsNullOrEmpty(orderModel.CardStatementId) &&
            string.IsNullOrEmpty(orderModel.InternalOrderNumber) &&
            string.IsNullOrEmpty(orderModel.OrderNumber))
        {
            errorMessage = "At least one of CardStatementId,InternalOrderNumber,OrderNumber are required";
            resultFlag = false;
        }

        if (resultFlag)
        {
            return ValidationResult.Success;
        }
        else
        {
            return new ValidationResult(errorMessage);
        }
    }
}

Now, you can apply the CustomAnnotationValidator on your order model (viewModel, DTO, ...) as follows:

[CustomAnnotationValidator ]
Public class OrderModel
{
   public string CardStatementId { get; set; }
   public string InternalOrderNumber { get; set; }
   public string OrderNumber { get; set; }
}

Note: These codes are not tested, I just tried to present the method that I use in the form of your codes. I hope it is useful.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM