闲话 Asp.Net Core 数据校验(三)EF Core 集成 FluentValidation 校验数据例子

前言

一个在实际应用中 EF Core 集成 FluentValidation 进行数据校验的例子。

Step By Step 步骤

  1. 创建一个 Asp.Net Core WebApi 项目

  2. 引用以下 Nuget 包

    FluentValidation.AspNetCore

    Microsoft.AspNetCore.Identity.EntityFrameworkCore

    Microsoft.EntityFrameworkCore.Relational

    Microsoft.EntityFrameworkCore.SqlServer

    Microsoft.EntityFrameworkCore.Tools

  3. 创建 Login 操作方法的请求参数模型类 LoginRequest

    c# 复制代码
    // LoginRequest 类只是一个普通的C#类,
    // 没有标注任何的Attribute或者实现任何的接口,
    // 它的唯一责任就是传递数据
    public record LoginRequest(string Email, string Password, string PasswordConfirm);
  4. 修改 appsettings.json,添加数据库连接字符串

    复制代码
    {
      "Logging": {
    	"LogLevel": {
    	  "Default": "Information",
    	  "Microsoft.AspNetCore": "Warning"
    	}
      },
      "AllowedHosts": "*",
      "ConnectionStrings": {
    	"Default": "Server=(localdb)\\mssqllocaldb;Database=IdentityTestDB;Trusted_Connection=True;MultipleActiveResultSets=true"
      }
    }	
  5. 创建用户实体类User和Role

    c# 复制代码
    using Microsoft.AspNetCore.Identity;
    
    public class User : IdentityUser<long>
    {
    	public DateTime CreationTime { get; set; }
    	public string? NickName { get; set; }
    }
    
    public class Role : IdentityRole<long>
    {
    
    }
  6. 创建继承自IdentityDbContext的上下文类

    c# 复制代码
    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);
    	}
    }
  7. 打开 Program.cs,注册 Identity 和 FluentValidation

    c# 复制代码
    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();	
  8. 编写请求参数模型类 LoginRequest

    c# 复制代码
    public record LoginRequest(string UserName, string Password);
  9. 编写继承自AbstractValidator的数据校验类,留意注释

    c# 复制代码
    using FluentValidation;
    using Microsoft.EntityFrameworkCore;
    
    public class LoginRequestValidator : AbstractValidator<LoginRequest>
    {
    	// 通过构造方法注入了TestDbContext
    	public 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}不存在");
    	}
    }
  10. 打开登录请求控制器,编写 Login API

    c# 复制代码
    using Microsoft.AspNetCore.Mvc;
    
    namespace FluentValidationSample2.Controllers
    {
    	[ApiController]
    	[Route("[controller]/[action]")]
    	public class TestController : ControllerBase
    	{
    		[HttpPost]
    		public ActionResult Login(LoginRequest req)
    		{
    			return Ok();
    		}
    	}
    }
  11. 在 Postman 或 Swagger 测试 Login API,如果请求的用户名不存在,即会返回代码中定义的错误信息

相关推荐
公子小六1 小时前
基于.NET的Windows窗体编程之WinForms数据持久化(1)
windows·microsoft·c#·.net·winforms
三雷科技2 小时前
第6章第4节:自定义分词器
开发语言·c#
zhanghaha13143 小时前
C# 系列教程_12 字符串 string 保姆级系统教程(面向新手,大量示例 + 原理讲解)
开发语言·数据库·c#
Coder_Shenshen18 小时前
罗克韦尔ACD工程归档离线变量树解析
算法·c#
寂寞的船1 天前
【Unity知识速递】第10期 Unity GC 零分配实战:从 UnityEngine.Pool 到手动 GC 控制的全链路优化
jvm·unity·c#·游戏引擎·lucene
1-1=01 天前
C# 数据结构和特殊类型
数据结构·c#·.net·.netcore
波力海苔夹心脆6753 天前
C# WPF 资源字典详解:ResourceDictionary、MergedDictionaries 与自定义控件案例
开发语言·c#·wpf·入门教程·resource·资源字典
AI导出鸭PC端3 天前
Perplexity批量导出没有PDF模式?AI导出鸭插件补上最后一块拼图
人工智能·pdf·c#·ai导出鸭
Risehuxyc3 天前
C# 选用更流行的语言版本
c#
淡海水4 天前
09-04-内存-Unity原生对象生命周期
unity·c#·游戏引擎·gc