C# Web開發(fā)教程(十二)數(shù)據(jù)校驗機制
內置數(shù)據(jù)校驗機制
- 框架內置了對數(shù)據(jù)校驗的支持
- 在System.ComponentModel.DataAnnotations這個命名空間下:
- 比如[Required]、[EmailAddress] 、[RegularExpression] 、 CustomValidationAttribute、IValidatableObject等待
- demo演示
// LoginRequest1.cs
using System.ComponentModel.DataAnnotations;
namespace WebApplicationAboutDataValidate
{
public class LoginRequest1
{
[Required]
[EmailAddress]
[RegularExpression("^.*@(qq|163)\\.com$", ErrorMessage = "只支持QQ和163郵箱")]
public string Email { get; set; }
[Required]
[StringLength(10, MinimumLength = 3)]
public string Password { get; set; }
[Compare(nameof(Password2), ErrorMessage = "兩次密碼必須一致")]
public string Password2 { get; set; }
}
}
- 測試效果
- 提交如下字段
{
"email": "user@example.com",
"password": "string",
"password2": "string"
}
- 返回:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-840f868ea1c247a51f659d0092a68ae9-a7f61df6b9a99cd3-00",
"errors": {
"Email": [
"只支持QQ和163郵箱"
]
}
}
- 提交如下字段:
{
"email": "user@qq.com",
"password": "string123",
"password2": "string"
}
- 返回:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-e635ad8de5684008becbe67b9be814e8-fea276f49eca5228-00",
"errors": {
"Password2": [
"兩次密碼必須一致"
]
}
}
內置數(shù)據(jù)校驗機制的問題點
- 校驗規(guī)則都是和模型類耦合在一起,違反“單一職責原則”;
- 很多常用的校驗都需要編寫自定義校驗規(guī)則,而且寫起來麻煩。
數(shù)據(jù)校驗機制第三方庫--- FluentValidation1
-
FluentValidation在很多項目中都可以使用(比如WinForm,WPF) -
注意事項:
FluentValidation可以和內置的數(shù)據(jù)校驗機制混用,但最好不要這么干,避免混淆和未知的坑. -
安裝庫
- Install-Package Microsoft.EntityFrameworkCore.Tools -Version 6.0.0
- Install-Package FluentValidation.AspNetCore -Version 10.3.4 // 這里不要搞成6的版本,有坑
Program.cs注冊一下
// LoginRequest1.cs
using System.ComponentModel.DataAnnotations;
namespace WebApplicationAboutDataValidate
{
public class LoginRequest1
{
public string Email { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string Password2 { get; set; }
}
}
// AddNewUserRequestValidator.cs---自定義校驗器
using FluentValidation;
namespace WebApplicationAboutDataValidate
{
public class AddNewUserRequestValidator : AbstractValidator<LoginRequest1>
{
public AddNewUserRequestValidator()
{
RuleFor(x => x.Email).NotNull().EmailAddress().WithMessage("郵箱必須是合法地址").Must(x => x.EndsWith("@163.com") || x.EndsWith("@qq.com")).WithMessage("支持163或者QQ郵箱");
RuleFor(x => x.UserName).NotNull().Length(3,10);
RuleFor(x => x.Password).Equal(x => x.Password2).WithMessage("兩次密碼必須一致");
}
}
}
// Program.cs
......
builder.Services.AddSwaggerGen();
// 注冊全局驗證器
builder.Services.AddFluentValidation(fv => {
Assembly assembly = Assembly.GetExecutingAssembly();
fv.RegisterValidatorsFromAssembly(assembly);
});
var app = builder.Build();
......
// 測試接口
using Microsoft.AspNetCore.Mvc;
namespace WebApplicationAboutDataValidate.Controllers
{
[ApiController]
[Route("[controller]/[action]")]
public class ValidateDataController : ControllerBase
{
[HttpPost]
public ActionResult Login(LoginRequest1 req)
{
return Ok(req);
}
}
}
- 測試: https://localhost:7263/ValidateData/Login
{
"email": "string",
"userName": "string",
"password": "string",
"password2": "string111"
}
- 返回結果
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-7666f45f49e7afcab428d6bbd34d5bfb-1d6ed200ab8f73e3-00",
"errors": {
"Email": [
"郵箱必須是合法地址",
"支持163或者QQ郵箱"
],
"Password": [
"兩次密碼必須一致"
]
}
}
FluentValidation+DI高級功能---依賴注入: 可以通過構造方法來向校驗器注入服務
using FluentValidation;
using Microsoft.AspNetCore.Identity;
namespace WebApplicationAboutDataValidate
{
public class AddNewUserRequestValidator : AbstractValidator<LoginRequest1>
{
public AddNewUserRequestValidator(UserManager<LoginRequest1> userManager)
{
RuleFor(x => x.Email).NotNull().EmailAddress().WithMessage("郵箱必須是合法地址").Must(x => x.EndsWith("@163.com") || x.EndsWith("@qq.com")).WithMessage("支持163或者QQ郵箱");
RuleFor(x => x.UserName).NotNull().Length(3,10).MustAsync(async (x,_) => await userManager.FindByNameAsync(x) == null).WithMessage("用戶名已存在");
//RuleFor(x => x.Password).Equal(x => x.Password2).WithMessage("兩次密碼必須一致");
RuleFor(x => x.Password).Equal(x => x.Password2).WithMessage(x => $"密碼{x.Password}和{x.Password2}不一致");
}
}
}
核心要點總結
- 分離關注點:FluentValidation 將校驗邏輯從模型類中分離出來
- 鏈式編程:使用流暢的接口設計,代碼可讀性更強
- 靈活性強:支持復雜的業(yè)務邏輯校驗,包括異步校驗
- 錯誤信息定制:可以靈活定制錯誤消息,支持動態(tài)消息
- 依賴注入支持:可以在校驗器中注入服務,實現(xiàn)更復雜的業(yè)務校驗

浙公網(wǎng)安備 33010602011771號