c# - 自定义类的 Blazor 验证
问题描述
我正在测试 Blazor,但遇到了验证问题。在验证一个简单的类时,我可以只使用注释。如果我有自己的自定义类,但验证不会对自定义类中的所有内容运行。这个问题似乎是 Blazor 特有的,因为我可以在 ASP 中使用此验证。
这是我的两个简单模型:
public class TestModel
{
[Required]
[Range(12, 400, ErrorMessage = "This works")]
public int Count { get; set; }
public KeyValue KeyValues { get; set; }
public TestModel()
{
Count = 4;
KeyValues = new KeyValue()
{
Key = 5,
Value = "str"
};
}
}
和 KeyValue 类
public class KeyValue
{
[Required]
[Range(10, 300, ErrorMessage = "This number check doesn't")]
public int Key { get; set; }
[Required]
[StringLength(10, MinimumLength = 5, ErrorMessage = "Nor the string one")]
public string Value { get; set; }
}
那是我的组成部分。它验证 Model.Count 属性,但不验证嵌套类。
<EditForm Model="@Model" OnValidSubmit="@DoStuff">
<DataAnnotationsValidator />
<ValidationSummary />
<div class="row">
<div class="col-md-4">
<input type="number" bind="@Model.Count" class="form-control" placeholder="Condition property name" />
</div>
<div class="col-md-4">
<input type="number" bind="@Model.KeyValues.Key" class="form-control" placeholder="Condition property name" />
</div>
<div class="col-md-4">
<InputText bind-Value="@Model.KeyValues.Value"></InputText>
</div>
</div>
<div class="row">
<div class="col-md-12">
<button type="submit" class="btn btn-info">Create</button>
</div>
</div>
</EditForm>
解决方案
这是 Blazor 的一个已知限制,但您可以解决它。
首先,使用OnSubmit
事件 on<EditForm>
而不是OnValidSubmit
. 该方法是EditContext
这样传递的......
private void FormSubmitted(EditContext context)
{
...
}
如果您使用以下扩展,您可以在您的FormSubmitted
方法中使用以下代码,它不仅会验证您的整个对象树,还会根据结果更新您的 UI。
{
if (context.ValdiateObjectTree())
{
... do whatever
}
}
扩展...
using Microsoft.AspNetCore.Components.Forms;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace PeterLeslieMorris.Blazor.Validation.Extensions
{
public static class EditContextExtensions
{
static PropertyInfo IsModifiedProperty;
static MethodInfo GetFieldStateMethod;
/// <summary>
/// Validates an entire object tree
/// </summary>
/// <param name="editContext">The EditContext to validate the Model of</param>
/// <returns>True if valid, otherwise false</returns>
public static bool ValidateObjectTree(this EditContext editContext)
{
var validatedObjects = new HashSet<object>();
ValidateObject(editContext, editContext.Model, validatedObjects);
editContext.NotifyValidationStateChanged();
return !editContext.GetValidationMessages().Any();
}
public static void ValidateProperty(this EditContext editContext, FieldIdentifier fieldIdentifier)
{
if (fieldIdentifier.Model == null)
return;
var propertyInfo = fieldIdentifier.Model.GetType().GetProperty(
fieldIdentifier.FieldName,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static);
var validatedObjects = new HashSet<object>();
ValidateProperty(editContext, fieldIdentifier.Model, propertyInfo, validatedObjects);
}
private static void ValidateObject(
EditContext editContext,
object instance,
HashSet<object> validatedObjects)
{
if (instance == null)
return;
if (validatedObjects.Contains(instance))
return;
if (instance is IEnumerable && !(instance is string))
{
foreach (object value in (IEnumerable)instance)
ValidateObject(editContext, value, validatedObjects);
return;
}
if (instance.GetType().Assembly == typeof(string).Assembly)
return;
validatedObjects.Add(instance);
var properties = instance.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (PropertyInfo property in properties)
ValidateProperty(editContext, instance, property, validatedObjects);
}
private static void ValidateProperty(
EditContext editContext,
object instance,
PropertyInfo property,
HashSet<object> validatedObjects)
{
NotifyPropertyChanged(editContext, instance, property.Name);
object value = property.GetValue(instance);
ValidateObject(editContext, value, validatedObjects);
}
private static void NotifyPropertyChanged(
EditContext editContext,
object instance,
string propertyName)
{
if (GetFieldStateMethod == null)
{
GetFieldStateMethod = editContext.GetType().GetMethod(
"GetFieldState",
BindingFlags.NonPublic | BindingFlags.Instance);
}
var fieldIdentifier = new FieldIdentifier(instance, propertyName);
object fieldState = GetFieldStateMethod.Invoke(editContext, new object[] { fieldIdentifier, true });
if (IsModifiedProperty == null)
{
IsModifiedProperty = fieldState.GetType().GetProperty(
"IsModified",
BindingFlags.Public | BindingFlags.Instance);
}
object originalIsModified = IsModifiedProperty.GetValue(fieldState);
editContext.NotifyFieldChanged(fieldIdentifier);
IsModifiedProperty.SetValue(fieldState, originalIsModified);
}
}
}
您可以在此处找到扩展源。您也可以使用Blazor-Validation,它也允许您使用FluentValidation。
如果您想更深入地了解 Blazor 表单/验证的工作原理,可以在Blazor University的这一部分中阅读相关内容。
推荐阅读
- c# - AWS RabbitMQ 没有一个端点是可访问的 C#
- python - 按索引访问数据框的列以进行验证
- python - Python 输出到 CSV 文件作业
- sql - 在 ORACLE SQL 中使用 distinct 时如何避免在列中出现重复
- node.js - 如何使用 JOI Validator 对嵌套 JSON 执行条件检查
- python - 为什么 tensorflow/keras 与训练和验证指标相距甚远?
- bash - 在 bash 脚本中,我有一组参数要传递给另一个 bash 脚本。我该怎么做?
- typescript - 如何从 Jest 中的超测试请求中检索 cookie?
- javascript - 如何使用 css 一张一张地展示我的幻灯片
- ffmpeg - 如何将多个 RTSP 的 FFMPEG 命令组合到 HLS