前言
一个在实际应用中 EF Core 集成 FluentValidation 进行数据校验的例子。
Step By Step 步骤
-
创建一个 Asp.Net Core WebApi 项目
-
引用以下 Nuget 包
FluentValidation.AspNetCore
Microsoft.AspNetCore.Identity.EntityFrameworkCore
Microsoft.EntityFrameworkCore.Relational
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools -
创建 Login 操作方法的请求参数模型类 LoginRequest
// LoginRequest 类只是一个普通的C#类, // 没有标注任何的Attribute或者实现任何的接口, // 它的唯一责任就是传递数据 public record LoginRequest(string Email, string Password, string PasswordConfirm);
-
修改 appsettings.json,添加数据库连接字符串
{"Logging": {"LogLevel": {"Default": "Information","Microsoft.AspNetCore": "Warning"}},"AllowedHosts": "*","ConnectionStrings": {"Default": "Server=(localdb)\\mssqllocaldb;Database=IdentityTestDB;Trusted_Connection=True;MultipleActiveResultSets=true"} }
-
创建用户实体类User和Role
using Microsoft.AspNetCore.Identity;public class User : IdentityUser<long> {public DateTime CreationTime { get; set; }public string? NickName { get; set; } }public class Role : IdentityRole<long> {}
-
创建继承自IdentityDbContext的上下文类
using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;public class TestDbContext : IdentityDbContext<User, Role, long> {public TestDbContext(DbContextOptions<TestDbContext> options): base(options){}protected override void OnModelCreating(ModelBuilder modelBuilder){base.OnModelCreating(modelBuilder);modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);} }
-
打开 Program.cs,注册 Identity 和 FluentValidation
using FluentValidation; using FluentValidation.AspNetCore; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using System.Reflection;var builder = WebApplication.CreateBuilder(args);// Add services to the container.builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen();// 注册标识框架相关的服务,并配置相关选项 IServiceCollection services = builder.Services; services.AddDbContext<TestDbContext>(opt => {string connStr = builder.Configuration.GetConnectionString("Default")!;opt.UseSqlServer(connStr); }); services.AddDataProtection(); services.AddIdentityCore<User>(options => {options.Password.RequireDigit = false;options.Password.RequireLowercase = false;options.Password.RequireNonAlphanumeric = false;options.Password.RequireUppercase = false;options.Password.RequiredLength = 6;options.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultEmailProvider;options.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider; }); var idBuilder = new IdentityBuilder(typeof(User), typeof(Role), services); idBuilder.AddEntityFrameworkStores<TestDbContext>().AddDefaultTokenProviders().AddRoleManager<RoleManager<Role>>().AddUserManager<UserManager<User>>();// 注册 FluentValidation 服务 Assembly assembly = Assembly.GetExecutingAssembly(); builder.Services.AddFluentValidationAutoValidation().AddFluentValidationClientsideAdapters().AddValidatorsFromAssembly(assembly);var app = builder.Build();// Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) {app.UseSwagger();app.UseSwaggerUI(); }app.UseHttpsRedirection();app.UseAuthorization();app.MapControllers();app.Run();
-
编写请求参数模型类 LoginRequest
public record LoginRequest(string UserName, string Password);
-
编写继承自AbstractValidator的数据校验类,留意注释
using FluentValidation; using Microsoft.EntityFrameworkCore;public class LoginRequestValidator : AbstractValidator<LoginRequest> {// 通过构造方法注入了TestDbContextpublic LoginRequestValidator(TestDbContext dbCtx){RuleFor(x => x.UserName).NotNull()// 使用TestDbContext服务检查用户名是否存在// 同步方式.Must(name => dbCtx.Users.Any(u => u.UserName == name))// 异步方式,但使用异步后出错,暂时未能找到解决方案//.MustAsync((name,_) => dbCtx.Users.AnyAsync(u => u.UserName == name))// 用Lambda表达式的形式使用模型类中的属性对报错信息进行格式化.WithMessage(c => $"用户名{c.UserName}不存在");} }
-
打开登录请求控制器,编写 Login API
using Microsoft.AspNetCore.Mvc;namespace FluentValidationSample2.Controllers {[ApiController][Route("[controller]/[action]")]public class TestController : ControllerBase{[HttpPost]public ActionResult Login(LoginRequest req){return Ok();}} }
-
在 Postman 或 Swagger 测试 Login API,如果请求的用户名不存在,即会返回代码中定义的错误信息