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
在我的服务器端 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