FluentValidation:如果我将新的类实例分配给表单模型,则验证将胜任

发布于 2025-02-02 22:20:12 字数 1962 浏览 3 评论 0原文

在我的服务器端的Blazor应用中,我有一个Telerikform,它是围绕Blazor的Editform的包装。形式的模型参数是“供应商” 对于表单验证,我使用blazored.fluentvalidation,它被注册为瞬态服务。 如果我手动填写所有表单字段,则验证正常。但是在某些情况下,我需要以编程方式填写所有字段,将新的类实例分配给“供应商”模型: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

In my server-side Blazor app I have a TelerikForm, which is a wrapper around Blazor's EditForm. Form's model parameter is "vendor"
For form validation I use Blazored.FluentValidation, which is registered as a Transient service.
Validation works fine if I fill out all form fields manually. But in some scenarios, I need to fill all fields programmatically, assigning a new class instance to the "vendor" model: vendor = newVendor.
In that case, the validator stops working. It seems that the validator doesn't recognize a new model. I think it is bound to the model's reference, and when the model changes its reference validator doesn't work anymore. However, if I assign model properties one by one, then it works fine, eg - vendor.Name = newVendor.Name.

How can I make a validator work with a new instance of the model?

Below is my code:

<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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

寂寞清仓 2025-02-09 22:20:12

Telerikform是Telerik Blazor 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
    }
}

如果您查看“如果他们提供不同的模型” :

        // 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上打开票,并要求它。

无论如何,我建议您避免这种做法,而只是为当前模型分配新值以更改它。我认为,您应该避免更改编辑形式的模型。

另外,您可能会注意到我发布了最低可再现的样本,可以复制它,并且它可以毫无问题地运行。您应该了解如何创建一个最小的,可重复的示例

TelerikForm is the Telerik Blazor EditForm component, with the same parameters as a regular EditForm.

Technically, you can change model in EditForm and all will run fine if the component is rendered again:

@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
    }
}

If you take a look to EditForm source code, you can appreciate that is ready to deal with this scenario: "or if they are supplying a different Model":

        // 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!);
        }

I don't know if you can do the same with TelerikForm because this is not an open source component. Open a ticket on Telerik and ask for it.

In any case, I recommend to you to avoid this practice and just assign new values to current model instead to change it. In my opinion, you should avoid changing the EditForm's model.

Also, you can notice that I posted a Minimum Reproducible Sample, you can copy-paste it, and it runs without issues. You should to learn about How to create a Minimal, Reproducible Example

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文