闲话 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,如果请求的用户名不存在,即会返回代码中定义的错误信息

相关推荐
初九之潜龙勿用8 小时前
C# 操作Word模拟解析HTML标记之背景色
开发语言·c#·word·.net·office
时光追逐者9 小时前
使用 MWGA 帮助 7 万行 Winforms 程序快速迁移到 WEB 前端
前端·c#·.net
老骥伏枥~10 小时前
【C# 入门】程序结构与 Main 方法
开发语言·c#
全栈师11 小时前
java和C#的基本语法区别
java·开发语言·c#
钰fly11 小时前
联合编程(加载单个工具,ini读写,图片读写,setting存储)
c#
FuckPatience13 小时前
C# 对象初始化器对属性赋值vs构造函数里对属性赋值
c#
m0_7482331714 小时前
C语言vsC#:核心差异全解析
c语言·开发语言·c#
MyBFuture14 小时前
C# 关于联合编程基础
开发语言·c#·visual studio·vision pro
Sunsets_Red15 小时前
单调队列优化dp
c语言·c++·算法·c#·信息学竞赛
故事不长丨15 小时前
《C#委托与事件深度解析:区别、联系与实战应用》
开发语言·c#·委托·事件·event