总览
在Blazor中介绍表单验证方法。
我将以以下登录表单为例。
本文的演示(从菜单中选择"表单")
源代码
假设
.NET Core SDK 3.1.100-preview3-014645
Microsoft.AspNetCore.Blazor 3.1.0-preview2.19528.8
Visual Studio 2019
我正在使用Web程序集版本(客户端版本)。
此外,该示例还将MatBlazor用作UI元素。
有关详情,请参见下文。
https://qiita.com/nobu17/items/ecf2121f7bbb6bc5294b
如果不使用MatBlazor,则将其替换为常规Form元素。
MatTextField→InputText或输入
MatButton→按钮(类型="提交")
基本版
我们将实现并解释最常用的基本模式。
创建输入模型
首先,定义要绑定到输入屏幕的类。
然后为每个项目添加一个验证定义。
用属性表示验证与ASP.NET MVC等的相同方法,因此我认为.NET开发人员对此很熟悉。
LoginData.cs
1 2 3 4 5 6 7 8 9 10 | public class LoginData { [Required(ErrorMessage = "ユーザIDを入力してください。")] [StringLength(16, ErrorMessage = "ユーザIDが長すぎます。")] public string UserID { get; set; } [Required(ErrorMessage = "パスワードを入力してください。")] [StringLength(32, ErrorMessage = "パスワードが長すぎます。")] public string Password { get; set; } } |
在
之后创建代码
接下来,创建一个将LoginData作为成员的类,该类绑定到View。
这次,我将在后面的代码中分别描述razor组件和C#代码。
有关隐藏代码的更多信息,请参见下文。
https://qiita.com/nobu17/items/b7dc78db7beb1d833dc8
Form1ViewModel.cs
1 2 3 4 5 6 7 8 9 | public class Form1ViewModel : ComponentBase { public LoginData LoginData { get; set; } = new LoginData(); public void Submit() { // do something } } |
查看定义
创建一个屏幕以绑定后台代码。
Form1.razor
1 2 3 4 5 6 7 8 9 10 11 12 13 | @inherits MatTest.Models.Form.Form1ViewModel <EditForm Model="@LoginData" OnValidSubmit="@Submit"> <DataAnnotationsValidator /> <ValidationSummary /> <MatTextField FullWidth="true" Label="UserID" @bind-Value="@LoginData.UserID"></MatTextField> <ValidationMessage For="@(() => LoginData.UserID)" /> <MatTextField FullWidth="true" Label="Password" @bind-Value="@LoginData.Password" Type="password"></MatTextField> <ValidationMessage For="@(() => LoginData.Password)" /> <MatButton Label="Login" Outlined="true" Type="submit"> </EditForm> |
编辑表格
使用此标签将您在表单中输入的元素括起来。
-将您在表单中输入的属性绑定到"模型"。
-当输入正常时,将确认处理方法绑定到OnValidSubmit。
另外,如果要检测由于无效输入而导致按下确认按钮的情况,可以通过绑定OnInvalidSubmit事件来检测到它。
DataAnnotationsValidator
在较早验证分配给输入数据类的属性(必填等)时描述。
验证摘要
显示验证期间发生的错误的详细信息。
验证消息
ValidationSummary显示所有错误详细信息,因此
当您要显示每个输入项的单独验证时,请使用此选项。
在For中使用lambda指定属性。
2019/12/22附录
OnSubmit
根据验证结果,执行OnValidSubmit或OnInvalidSubmit,但是通过使用OnSubmit,可以注册始终在提交时执行的过程。
您可以使用作为参数传递的EditContext来执行验证或实现自己的验证过程。
Form1.razor
1 2 3 4 | @inherits MatTest.Models.Form.Form1ViewModel <EditForm Model="@LoginData" OnSubmit="@Submit"> //略 </EditForm> |
Form1ViewModel.cs
1 2 3 4 5 6 7 8 | public class Form1ViewModel : ComponentBase { public void Submit(EditContext editContext) { // 検証を実施して結果を取得 bool isValid = editContext.Validate(); } } |
自定义验证属性
如果要创建自己的验证属性,请扩展ValidationAttribute类。
这是.NET中特定于Blazor的一种更常用的技术。
CustomeValidationAttribute.cs
1 2 3 4 5 6 7 8 9 10 11 12 | public class CustomeValidationAttribute : ValidationAttribute { protected override ValidationResult IsValid(object value, ValidationContext validationContext) { var str = value as string; if (str != null && string.IsNullOrWhiteSpace(str)) { return new ValidationResult("空白は無効です。", new[] { validationContext.MemberName }); } return ValidationResult.Success; } } |
覆盖
IsValid以验证目标对象。
- 如果正常,则返回ValidationResult.Success
- 如果输入错误,则将错误消息和validationContext.MemberName放入ValidationResult中并返回
发生输入错误时,将显示错误消息,如下所示。
进阶版
基于基础知识,我们将介绍各种情况。
嵌套类
的验证
DataAnnotationsValidator不适用于嵌套对象。
当前它仍然是预览版本,但是您可以按照以下步骤进行操作。
新增模块
从Nuget添加以下模块。
Microsoft.AspNetCore.Blazor.DataAnnotations.Validation
属性添加
将ValidateComplexType属性授予嵌套类的属性。
NestedData.cs
1 2 3 4 5 6 | public class NestedData { [Required] [ValidateComplexType] public LoginData LoginData { get; set; } = new LoginData(); } |
Varidata更改
使用ObjectGraphDataAnnotationsValidator代替DataAnnotationsValidator。
Form2.razor
1 2 3 4 5 6 7 8 9 | @inherits MatTest.Models.Form.Form2ViewModel <EditForm Model="@NestedData" OnValidSubmit="@Submit"> <ObjectGraphDataAnnotationsValidator /> <ValidationSummary /> <MatTextField FullWidth="true" Label="UserID" @bind-Value="@NestedData.LoginData.UserID"></MatTextField> <MatTextField FullWidth="true" Label="Password" @bind-Value="@NestedData.LoginData.Password" Type="password"></MatTextField> <MatButton Label="Login" Outlined="true" Type="submit"> </EditForm> |
使用OSS模块进行自定义验证(流式验证)
您可以使用OSS提供的功能创建除属性验证之外的其他验证。
由于介绍了使.NET验证库(例如FluentValidation与Blazor兼容)的方法,因此我们将在此基础上实现该方法。
https://chrissainty.com/using-fluentvalidation-for-forms-validation-in-razor-components/
套餐介绍
从Nuget安装Fluent验证。
创建Varidata
根据Fluent Validation方法创建一个验证类。
LoginDataValidator.cs
1 2 3 4 5 6 7 8 9 10 | public class LoginDataValidator : AbstractValidator<LoginData> { public LoginDataValidator() { RuleFor(p => p.UserID).NotEmpty().WithMessage("ログインIDを入力してください。"); RuleFor(p => p.UserID).MaximumLength(10).WithMessage("ログインIDは10文字まで入力してください。"); RuleFor(p => p.Password).NotEmpty().WithMessage("パスワードを入力してください。"); RuleFor(p => p.Password).MaximumLength(10).WithMessage("パスワードは10文字まで入力してください。"); } } |
创建一个继承AbstractValidator的类。
(指定要验证泛型的类)
使用构造函数中的RuleFor Lambda对每个成员实施验证。
创建组件
由于无法像在Blazor中那样使用创建的验证数据,因此请创建一个组件以支持Blazor方面的验证。
Blazor提供了诸如EditContext之类的验证机制,并且Fluent Validation的验证是在该机制内执行的。
我将省略EditContext的详细信息,但是以下内容将有所帮助。
https://gunnarpeipman.com/blazor-form-validation/
Publisher(由于自发布以来某些API规范已更改,因此我们正在处理。将AddRange更改为Add。Reference)。
FluentValidationValidator.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | public class FluentValidationValidator : ComponentBase { [CascadingParameter] EditContext CurrentEditContext { get; set; } protected override void OnInitialized() { if (CurrentEditContext == null) { throw new InvalidOperationException($"{nameof(FluentValidationValidator)} requires a cascading " + $"parameter of type {nameof(EditContext)}. For example, you can use {nameof(FluentValidationValidator)} " + $"inside an {nameof(EditForm)}."); } CurrentEditContext.AddFluentValidation(); } } public static class EditContextFluentValidationExtensions { public static EditContext AddFluentValidation(this EditContext editContext) { if (editContext == null) { throw new ArgumentNullException(nameof(editContext)); } var messages = new ValidationMessageStore(editContext); editContext.OnValidationRequested += (sender, eventArgs) => ValidateModel((EditContext)sender, messages); editContext.OnFieldChanged += (sender, eventArgs) => ValidateField(editContext, messages, eventArgs.FieldIdentifier); return editContext; } private static void ValidateModel(EditContext editContext, ValidationMessageStore messages) { var validator = GetValidatorForModel(editContext.Model); var validationResults = validator.Validate(editContext.Model); messages.Clear(); foreach (var validationResult in validationResults.Errors) { messages.Add(editContext.Field(validationResult.PropertyName), validationResult.ErrorMessage); } editContext.NotifyValidationStateChanged(); } private static void ValidateField(EditContext editContext, ValidationMessageStore messages, in FieldIdentifier fieldIdentifier) { var properties = new[] { fieldIdentifier.FieldName }; var context = new ValidationContext(fieldIdentifier.Model, new PropertyChain(), new MemberNameValidatorSelector(properties)); var validator = GetValidatorForModel(fieldIdentifier.Model); var validationResults = validator.Validate(context); messages.Clear(fieldIdentifier); // APIの仕様変更のため、Addに変更 //messages.AddRange(fieldIdentifier, validationResults.Errors.Select(error => error.ErrorMessage)); messages.Add(fieldIdentifier, validationResults.Errors.Select(error => error.ErrorMessage)); editContext.NotifyValidationStateChanged(); } private static IValidator GetValidatorForModel(object model) { var abstractValidatorType = typeof(AbstractValidator<>).MakeGenericType(model.GetType()); var modelValidatorType = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(t => t.IsSubclassOf(abstractValidatorType)); var modelValidatorInstance = (IValidator)Activator.CreateInstance(modelValidatorType); return modelValidatorInstance; } } |
实施
放置创建的验证器组件(FluentValidationValidator)。
Form3.razor
1 2 3 4 5 6 7 | <EditForm Model="@LoginData" OnValidSubmit="@HandleValidSubmit" class="mat-layout-grid-cell mat-layout-grid-cell-span-12"> <FluentValidationValidator /> <ValidationSummary /> <MatTextField FullWidth="true" Label="UserID" @bind-Value="@LoginData.UserID"></MatTextField> <MatTextField FullWidth="true" Label="Password" @bind-Value="@LoginData.Password" Type="password"></MatTextField> <MatButton Label="Login" Outlined="true" Type="submit"></MatButton> </EditForm> |
概要
我总结了Blazor中的表单验证方法。
由于验证方法遵循常规的.NET方法,因此许多人可能对此很熟悉。
Blazor的其他文章
我写了一些有关Blazor的文章,因此,如果您愿意,请看一下。
- 尝试使用MatBlazor,这是Blazor的UI框架
- 更改Blazor的初始加载屏幕(正在加载)
- 未使用Blazor登录时重定向到登录页面
- 使用Blazor在代码隐藏中分离逻辑和视图
- 尝试使用Radzen.Blazor,这是Blazor的UI框架
- 在GitHub Pages上发布使用Blazor创建的网站
- 在Firebase上发布使用Blazor创建的网站
参考资料
https://docs.microsoft.com/ja-jp/aspnet/core/blazor/forms-validation?view=aspnetcore-3.0
https://gunnarpeipman.com/blazor-form-validation/
https://chrissainty.com/using-fluentvalidation-for-forms-validation-in-razor-components/
https://blazor-university.com/forms/writing-custom-validation/
http://blazorhelpwebsite.com/Blog/tabid/61/EntryId/4337/Blazor-Forms-and-Validation.aspx
https://remibou.github.io/Client-side-validation-with-Blazor-and-Data-Annotations/
https://dzone.com/articles/blazor-form-validation
https://itnext.io/blazor-forms-and-validation-418173350435