Blazored.FluentValidation:如果我将新的 class 实例分配给表单模型,验证将不起作用

Blazored.FluentValidation: Validation won't work if I assign a new class instance to a form model

在我的服务器端 Blazor 应用程序中,我有一个 TelerikForm,它是 Blazor 的 EditForm 的包装器。表单的模型参数是“vendor” 对于表单验证,我使用 Blazored.FluentValidation,它被注册为一个 Transient 服务。 如果我手动填写所有表单字段,验证工作正常。但在某些情况下,我需要以编程方式填写所有字段,将新的 class 实例分配给“vendor”模型:vendor = newVendor。 在这种情况下,验证器将停止工作。验证器似乎无法识别新模型。我认为它绑定到模型的引用,当模型更改时,它的引用验证器不再工作。但是,如果我一个一个地分配模型属性,那么它就可以正常工作,例如 - vendor.Name = newVendor.Name.

如何让验证器使用模型的新实例?

下面是我的代码:

<TelerikForm Model="@vendor">
    <FormValidation>
        <FluentValidationValidator @ref="vendorValidator" DisableAssemblyScanning="true" />
    </FormValidation>
    <FormItems>
        <FormItem Field="@nameof(Vendor.TaxId)" />
        <FormItem Field="@nameof(Vendor.VendorName)" />
        <FormItem Field="@nameof(Vendor.CountryCode)" />
        <FormItem Field="@nameof(Vendor.CompanyWebsite)" />
        <TelerikValidationSummary />
    </FormItems>
    <FormButtons>
        <TelerikButton OnClick="@(() => ValidateVendor())">Submit</TelerikButton>
    </FormButtons>
</TelerikForm>


@code {
    Vendor? vendor = new();
    FluentValidationValidator? vendorValidator;

    bool ValidateVendor()
    {
        return vendorValidator.Validate(options => options.IncludeAllRuleSets());
    }

    void FillFormProgrammaticallyAndValidate(Vendor newVendor)
    {
        vendor = newVendor;
        ValidateVendor();

        // it works if I assign properties one by one
        // vendor.VendorName = newVendor.VendorName;
        // vendor.CountryCode = newVendor.CountryCode
    }

    public class VendorModelValidator : AbstractValidator<Vendor>
    {
        public VendorModelValidator()
        {
            RuleSet("ValidateName", () =>
            {
                RuleFor(p => p.VendorName)
                    .NotEmpty().WithMessage("'Name' is mandatory");
            });
        }
    }
}

sdsd

TelerikForm 是 Telerik Blazor EditForm 组件,具有与常规 EditForm 相同的参数。

从技术上讲,您可以在 EditForm 中更改模型,如果再次渲染组件,一切都会 运行 正常:

@using System.ComponentModel.DataAnnotations

<EditForm Model="@exampleModel" OnValidSubmit="@HandleValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <InputText id="name" @bind-Value="exampleModel.Name" />

    <button type="submit">Submit</button>
</EditForm>

@exampleModel.Name

<button @onclick="ChangeModel">Change model</button>

@code {
    public class ExampleModel
    {
        [Required]
        [StringLength(10, ErrorMessage = "Name is too long.")]
        public string? Name { get; set; }
    }
    private ExampleModel exampleModel = new();
    private void HandleValidSubmit()
    {
    }
    protected void ChangeModel()
    {
        exampleModel = new();
        // At this point this component is rendered again
    }
}

如果您查看 EditForm source code,您会发现它已准备好处理这种情况:“或者如果他们提供不同的型号”

        // Update _editContext if we don't have one yet, or if they are supplying a
        // potentially new EditContext, or if they are supplying a different Model
        if (Model != null && Model != _editContext?.Model)
        {
            _editContext = new EditContext(Model!);
        }

我不知道您是否可以对 TelerikForm 执行相同的操作,因为这不是开源组件。在 Telerik 上开票并索取。

无论如何,我建议您避免这种做法,只需为当前模型分配新值而不是更改它。在我看来,您应该避免更改 EditForm 的模型。

此外,您可以注意到我发布了一个最小可重现样本,您可以 copy-paste 它 运行 没有问题。你应该了解 How to create a Minimal, Reproducible Example