Blazor 中复杂模型的自定义远程验证?
Custom remote validations for complex models in blazor?
我目前正在使用 <ObjectGraphDataAnnotationsValidator/>
来验证复杂模型。
到目前为止一切顺利,除了还需要检查数据库以查看是否已存在具有相同值的记录。
中的建议实施 <CustomValidator/>
但是,它似乎只适用于顶级属性。
并且 <ObjectGraphDataAnnotationsValidator/>
不适用于远程验证(或者可以!?)
所以说我有:
*Parent.cs*
public int ID {get;set;}
public List<Child> Children {get;set;}
*Child.cs*
public int ID {get;set;}
public int ParentID {get;set}
public string Code {get;set;}
<EditForm Model="@Parent">
.
.
.
Child.Code
在数据库中有唯一约束。
我想警告用户"This 'Code' already exists! Please try entering a different value."
,这样就不会抛出异常。
现在,我有点迷茫我的下一步是什么。
过去使用 asp.net 核心 mvc,我可以使用远程验证来实现这一点。
Blazor 中是否有等同于远程验证的功能?
如果不是,我应该怎么做才能达到相同的结果,以远程验证复杂模型的子属性?
如有任何建议,我们将不胜感激。谢谢!
[根据@rdmptn 的建议更新 2021/01/24]
ValidationMessageStore.Add()
接受结构 FieldIdentifier
,这意味着我可以简单地添加 CustomValidator.DisplayErrors
的重载以使其工作:
public void DisplayErrors(Dictionary<FieldIdentifier, List<string>> errors)
{
foreach (var err in errors)
{
messageStore.Add(err.Key, err.Value);
}
CurrentEditContext.NotifyValidationStateChanged();
}
完整示例如下:
@using Microsoft.AspNetCore.Components.Forms
@using System.ComponentModel.DataAnnotations
@using System.Collections.Generic
<EditForm Model="parent" OnSubmit="Submit">
<ObjectGraphDataAnnotationsValidator></ObjectGraphDataAnnotationsValidator>
<CustomValidator @ref="customValidator"></CustomValidator>
<ValidationSummary></ValidationSummary>
@if (parent.Children != null)
{
@foreach (var item in parent.Children)
{
<div class="form-group">
<label>Summary</label>
<InputText @bind-Value="item.Code" class="form-control"></InputText>
</div>
}
}
<input type="submit" value="Submit" class="form-control"/>
</EditForm>
@code{
private CustomValidator customValidator;
private Parent parent;
public class Parent
{
public int Id { get; set; }
[ValidateComplexType]
public List<Child> Children { get; set; }
}
public class Child
{
public int Id { get; set; }
public int ParentId { get; set; }
public string Code { get; set; }
}
protected override void OnInitialized()
{
parent = new Parent()
{
Id = 1,
Children = new List<Child>()
{
new Child()
{
Id = 1,
ParentId = 1,
Code = "A"
},
new Child()
{
Id = 1,
ParentId = 1,
Code = "B"
}
}
};
}
public void Submit()
{
customValidator.ClearErrors();
var errors = new Dictionary<FieldIdentifier, List<string>>();
//In real operations, set this when you get data from your db
List<string> existingCodes = new List<string>()
{
"A"
};
foreach (var child in parent.Children)
{
if (existingCodes.Contains(child.Code))
{
FieldIdentifier fid = new FieldIdentifier(model: child, fieldName: nameof(Child.Code));
List<string> msgs = new List<string>() { "This code already exists." };
errors.Add(fid, msgs);
}
}
if (errors.Count() > 0)
{
customValidator.DisplayErrors(errors);
}
}
}
[Remote]
验证属性与 MVC 相关联,不可用于 Blazor。
ObjectGraphDataAnnotationsValidator
不够。此外,每个 属性 代表一个可能验证的对象需要用 [ValidateComplexType]
属性修饰。
在您的 CustomValidatior 中,您可以看到 DI 使您的 API 服务调用您的 API 并验证您的约束。
public class Parent
{
...other properties...
[ValidateComplexType]
public List<Child> Children {get; set; }
}
public class Child
{
...other properties...
[Required]
[IsUnique(ErrorMessage = "This 'Code' already exists! Please try entering a different value.")]
public String Code {get; set;}
}
public class IsUniqueAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var service = (IYourApiService)validationContext.GetService(typeof(IYourApiService));
//unfortunately, no await is possible inside the validation
Boolean exists = service.IsUnique((String)value);
if(exists == false)
{
return ValidationResult.Success;
}
return new ValidationResult(ErrorMessage, new[] { validationContext.MemberName });
}
}
您可能想查看 FluentValidation as this library provide features for asynchronous validation。我不确定这个验证器是否可以在 Blazor WASM 中使用。
我目前正在使用 <ObjectGraphDataAnnotationsValidator/>
来验证复杂模型。
到目前为止一切顺利,除了还需要检查数据库以查看是否已存在具有相同值的记录。
<CustomValidator/>
但是,它似乎只适用于顶级属性。
并且 <ObjectGraphDataAnnotationsValidator/>
不适用于远程验证(或者可以!?)
所以说我有:
*Parent.cs*
public int ID {get;set;}
public List<Child> Children {get;set;}
*Child.cs*
public int ID {get;set;}
public int ParentID {get;set}
public string Code {get;set;}
<EditForm Model="@Parent">
.
.
.
Child.Code
在数据库中有唯一约束。
我想警告用户"This 'Code' already exists! Please try entering a different value."
,这样就不会抛出异常。
现在,我有点迷茫我的下一步是什么。
过去使用 asp.net 核心 mvc,我可以使用远程验证来实现这一点。
Blazor 中是否有等同于远程验证的功能?
如果不是,我应该怎么做才能达到相同的结果,以远程验证复杂模型的子属性?
如有任何建议,我们将不胜感激。谢谢!
[根据@rdmptn 的建议更新 2021/01/24]
ValidationMessageStore.Add()
接受结构 FieldIdentifier
,这意味着我可以简单地添加 CustomValidator.DisplayErrors
的重载以使其工作:
public void DisplayErrors(Dictionary<FieldIdentifier, List<string>> errors)
{
foreach (var err in errors)
{
messageStore.Add(err.Key, err.Value);
}
CurrentEditContext.NotifyValidationStateChanged();
}
完整示例如下:
@using Microsoft.AspNetCore.Components.Forms
@using System.ComponentModel.DataAnnotations
@using System.Collections.Generic
<EditForm Model="parent" OnSubmit="Submit">
<ObjectGraphDataAnnotationsValidator></ObjectGraphDataAnnotationsValidator>
<CustomValidator @ref="customValidator"></CustomValidator>
<ValidationSummary></ValidationSummary>
@if (parent.Children != null)
{
@foreach (var item in parent.Children)
{
<div class="form-group">
<label>Summary</label>
<InputText @bind-Value="item.Code" class="form-control"></InputText>
</div>
}
}
<input type="submit" value="Submit" class="form-control"/>
</EditForm>
@code{
private CustomValidator customValidator;
private Parent parent;
public class Parent
{
public int Id { get; set; }
[ValidateComplexType]
public List<Child> Children { get; set; }
}
public class Child
{
public int Id { get; set; }
public int ParentId { get; set; }
public string Code { get; set; }
}
protected override void OnInitialized()
{
parent = new Parent()
{
Id = 1,
Children = new List<Child>()
{
new Child()
{
Id = 1,
ParentId = 1,
Code = "A"
},
new Child()
{
Id = 1,
ParentId = 1,
Code = "B"
}
}
};
}
public void Submit()
{
customValidator.ClearErrors();
var errors = new Dictionary<FieldIdentifier, List<string>>();
//In real operations, set this when you get data from your db
List<string> existingCodes = new List<string>()
{
"A"
};
foreach (var child in parent.Children)
{
if (existingCodes.Contains(child.Code))
{
FieldIdentifier fid = new FieldIdentifier(model: child, fieldName: nameof(Child.Code));
List<string> msgs = new List<string>() { "This code already exists." };
errors.Add(fid, msgs);
}
}
if (errors.Count() > 0)
{
customValidator.DisplayErrors(errors);
}
}
}
[Remote]
验证属性与 MVC 相关联,不可用于 Blazor。
ObjectGraphDataAnnotationsValidator
不够。此外,每个 属性 代表一个可能验证的对象需要用 [ValidateComplexType]
属性修饰。
在您的 CustomValidatior 中,您可以看到 DI 使您的 API 服务调用您的 API 并验证您的约束。
public class Parent
{
...other properties...
[ValidateComplexType]
public List<Child> Children {get; set; }
}
public class Child
{
...other properties...
[Required]
[IsUnique(ErrorMessage = "This 'Code' already exists! Please try entering a different value.")]
public String Code {get; set;}
}
public class IsUniqueAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var service = (IYourApiService)validationContext.GetService(typeof(IYourApiService));
//unfortunately, no await is possible inside the validation
Boolean exists = service.IsUnique((String)value);
if(exists == false)
{
return ValidationResult.Success;
}
return new ValidationResult(ErrorMessage, new[] { validationContext.MemberName });
}
}
您可能想查看 FluentValidation as this library provide features for asynchronous validation。我不确定这个验证器是否可以在 Blazor WASM 中使用。