具有自定义属性的 ValidationMessage 奇怪行为

ValidationMessage strange behaviour with custom attribute

我在 Blazor 应用程序中显示验证消息时遇到问题。

我有以下模型(用于测试目的):

public class MyModel
{
    [Required(ErrorMessage = "Amount is required")]
    public int Amount { get; set; }

    [Required(ErrorMessage = "NullableAmount is required")]
    public int? NullableAmount { get; set; }

    [RequiredIf(nameof(Foo), new[] { "bar" }, ErrorMessage = "Id is required")]
    public int Id { get; set; }

    [RequiredIf(nameof(Foo), new[] { "bar" }, ErrorMessage = "NullableId is required")]
    public int? NullableId { get; set; }

    public string Foo { get; set; }
}

我用内置的 RequiredAttribute 修饰了属性,并创建了一个自定义的 RequiredIfAttribute,这是它的代码:

public class RequiredIfAttribute : ValidationAttribute
{
    private readonly string _otherPropertyName;
    private readonly string[] _otherPropertyValues;

    public RequiredIfAttribute(string otherPropertyName, string[] otherPropertyValues)
    {
        _otherPropertyName = otherPropertyName;
        _otherPropertyValues = otherPropertyValues;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var instance = validationContext.ObjectInstance;
        var type = instance.GetType();
        var propertyValue = type.GetProperty(_otherPropertyName)?.GetValue(instance);

        if (!_otherPropertyValues.Contains(propertyValue?.ToString()))
        {
            return ValidationResult.Success;
        }

        if(value == null)
        {
            return new ValidationResult(ErrorMessage);
        }

        if(int.TryParse(value.ToString(), out var intValue))
        {
            if(intValue == 0)
            {
                return new ValidationResult(ErrorMessage);
            }
        }

        return ValidationResult.Success;
    }
}

我取另一个 属性 的名称,属性 的值,如果另一个 属性 的值与指定值之一匹配,它会检查是否用 RequiredIf 装饰的 属性 为 null,或者如果它是整数,则为 0。(我将它用于具有可为 null 的 int 属性 的模型,如果另一个 属性有一定的价值)。

在 WebAPI 方面它工作正常,但在 Blazor 表单中我遇到了一些问题。这是我的表格:

<EditForm Model="MyModel" OnValidSubmit="OnSubmit">
    <div style="display: flex; flex-direction: column; width: 300px;">
        <DataAnnotationsValidator />
        <ValidationSummary />

        <label>
            Foo:
            <InputText @bind-Value="MyModel.Foo" />
        </label>
        <ValidationMessage For="@(() => MyModel.Foo)" />

        <label>
            Amount:
            <InputNumber @bind-Value="MyModel.Amount" />
        </label>
        <ValidationMessage For="@(() => MyModel.Amount)" />

        <label>
            Null Amount:
            <InputNumber @bind-Value="MyModel.NullableAmount" />
        </label>
        <ValidationMessage For="@(() => MyModel.NullableAmount)" />

        <label>
            Id:
            <InputNumber @bind-Value="MyModel.Id" />
        </label>
        <ValidationMessage For="@(() => MyModel.Id)" />

        <label>
            Null Id:
            <InputNumber @bind-Value="MyModel.NullableId" />
        </label>
        <ValidationMessage For="@(() => MyModel.NullableId)" />

        <button type="submit">submit</button>
    </div>



</EditForm>

我打开表单,为 Foo 输入值“bar”,然后单击提交,我得到以下结果:

Amount 有效,因为它具有默认值 0,并且 RequiredAttribute 仅检查空值。 NullAmount 无效,它显示在 ValidationSummary 中,输入字段也是红色的,因为它无效,并且还显示验证消息。 Id 无效,因为在 RequiredIf 属性中我检查 int 值是否为 0,它具有默认值 0,错误消息显示在 ValidationSummary 中,有趣的部分来了,输入字段不是红色,验证消息未显示。 Nullable Id 字段也是如此,验证摘要中显示了错误消息,但该字段不是红色,没有显示验证消息。

现在,如果我为 Id 和 NullableId(具有自定义属性的字段)输入有效值,然后我将 Id 更改为 0,将 NullableId 更改为空,则会发生以下情况:

两个输入字段都变为红色,两个属性都显示验证消息,但在验证摘要中,两个错误消息都显示两次。

现在,如果我点击提交,两个输入字段都会变为绿色,验证消息也消失了,但仍会显示在摘要中。

我完全迷路了,不知道是我的自定义验证属性有问题,Blazor 组件有问题,还是未知问题。内置的 Required 属性工作正常,我只是将它添加到代码中以查看我的表单是否适用。

你有什么想法吗?

终于找到问题所在了。在validation属性中,当返回错误结果时,我必须在构造函数中传递memberName。

return new ValidationResult(ErrorMessage, validationContext.MemberName)

非常感谢@petyusa,我也运行 关注这个问题,这让我抓狂。我偶然发现了您的解决方案,它立即解决了。但是,我不得不将一个字符串数组传递给第二个参数(可能是因为我使用的是 .NET 5.0),而不是一个简单的字符串:

return new ValidationResult(ErrorMessage, new []{validationContext.MemberName});