我在 Blazor Server 应用程序中有一个 EditForm,我想检查 InputText 值是否在列表中。 如何将要比较的列表从我的 UI 传递到验证器类进行比较?
我尝试比较行中的 @bind 值并封装验证消息,但是当封装函数测试 true 时,它会跳过验证消息。
<EditForm Model="@resourceToBeCreated">
<FluentValidationValidator ValidatorType=typeof(ResourceValidator)/>
@if (resourcesSortedCollection.FirstOrDefault(x => x.Name == resourceToBeCreated.Name) != null)
{
<CustomValidationMessage For="() => resourceToBeCreated.Name" />
}
<InputTextOnInput @bind-Value="@resourceToBeCreated.Name" class="form-control" placeholder="Name..." />
</EditForm>
我显然可以在@code部分中执行此操作或类似操作,但是在inupt上没有收到验证弹出窗口。
所以问题是,我如何将此列表传递给验证器类进行比较?
编辑 1: InputTextOnInput 组件:
@inherits InputText
<input @attributes="AdditionalAttributes"
class="@CssClass"
value="@CurrentValue"
@oninput="EventCallback.Factory.CreateBinder<string>(this, __value => CurrentValueAsString = __value, CurrentValueAsString)" />
编辑2: 一种潜在的解决方法,同时仍使用流畅的验证。
1、为模型添加新属性:
public List<string> ResourceNames { get; set; }
2,在浏览器中创建新资源时,更新模型中的该属性
resourceToBeCreated.ResourceNames = resourcesSortedCollection.Select(x => x.Name).ToList();
3、在流畅验证中编写规则
RuleFor(x => x.Name).Null().When(x => x.ResourceNames.Contains(x.Name)).WithMessage("Duplicate resource name");
不确定这是否是最好的方法(代码气味?),但它现在有效。 无论哪种方式,我都必须创建一个包含所有资源名称的字符串列表。 如果有更直接的方法将 resourcesSortedCollection 对象传递给验证人 id 喜欢理解。
首先是继承的InputText
控件。 这将覆盖TryParseValueFromString
并在那里进行验证。
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using System.Diagnostics.CodeAnalysis;
namespace BlazorApp1.Pages;
public class InputTextValidated : InputText
{
[Parameter, EditorRequired] public IEnumerable<string>? CheckList { get; set; }
{ get; set; }
protected override bool TryParseValueFromString(string? value, out string? result, [NotNullWhen(false)] out string? validationErrorMessage)
{
result = null;
validationErrorMessage = null;
var isValid = this.CheckList is not null
&& this.CheckList.Any(item => item.Equals(value, StringComparison.InvariantCultureIgnoreCase));
if (isValid)
result = value;
else
validationErrorMessage = "You must enter a value in the validation list";
return isValid;
}
}
还有一个测试页面:
@page "/"
<PageTitle>Index</PageTitle>
<EditForm Model=this.model>
<DataAnnotationsValidator />
<InputTextValidated class="form-control" CheckList=Countries @bind-Value="@this.model.Country" />
<ValidationSummary />
</EditForm>
<div>
Country : @model.Country
</div>
@code {
private DataModel model = new DataModel();
private List<string> Countries = new List<string> { "UK", "Spain" };
public class DataModel
{
public string? Country;
}
}
作为替代方法,您可以使用/生成输入列表控件。
验证的工作原理
验证数据保存在与EditContext
相关联的ValidationMessageStore
中。ValidationMessageStore
是键/值对的组合集合:
- 定义为
FieldIdentifier
的字段 [模型作为object
,字段名称定义为string
] - 验证消息为
string
。
每个验证提供程序都有自己的消息存储库,可以清除消息并向其中添加消息。 它只能对其自己的邮件存储具有写入/删除访问权限。 提供程序获取EditForm
级联的EditContext
,创建与EditContext
关联的消息存储,并将消息记录到该存储区并从该存储区清除消息。FluentValidationValidator
、DataAnnotationsValidator
、您编写的任何与EditContext
交互的InputBase
控件或类都是具有与EditContext
关联的消息存储的提供程序。
ValidationSummary
和ValidationMessage
都是消费者。 它们通过级联EditContext
与与 EditContext 关联的消息存储库进行交互。 所有消息都以只读形式提供。ValidationMessage
从For
表达式构造一个FieldIdentifier
来筛选消息。
我认为 id 会抛出一个答案,因为我在做其他事情时偶然发现了一个答案,它可能会帮助另一个答案。
您可以在实例化验证程序时将要验证的值传递到验证程序中。在这种情况下,通过构造函数将 BaseResourceMoldes 列表传递到 ResouceValidator 中。 由于列表不会在实例化和验证之间更改,因此这是合适的。
然后使用 Must 扩展,该扩展会将您正在验证的参数传递到调用的函数中以测试布尔值。 在这种情况下.Must(IsUnique) 将 x.Name 传递到 IsUnique(string arg1) 中并返回一个布尔值。
语法可能与上面的示例略有不同,因为代码库在那时和现在之间会发生变化,但概念是相同的。
具有要验证的表单的类:
[Parameter] public List<BaseResourceModel> Resources { get; set; }
ResourceValidator resourceValidator;
protected override void OnInitialized()
{
resourceValidator = new ResourceValidator(Resources);
}
然后是 ResourceValidator 类:
private List<BaseResourceModel> _resources;
private void ResourceValidator(List<BaseResourceModel> resources)
{
_resources = resources;
RuleFor(x => x.Name).NotEmpty().Must(IsUnique).WithMessage("Resource name must be unique");
}
private bool IsUnique(string arg1)
{
bool isUnique = true;
foreach (var resource in _resources)
{
if (resource.Name == arg1)
{
isUnique = false;
}
}
return isUnique;
}
我假设如果列表有可能更改,您也可以异步执行此操作。 流畅验证具有异步方法。