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

相关推荐
向宇it27 分钟前
【从零开始入门unity游戏开发之——unity篇02】unity6基础入门——软件下载安装、Unity Hub配置、安装unity编辑器、许可证管理
开发语言·unity·c#·编辑器·游戏引擎
yngsqq1 小时前
一键打断线(根据相交点打断)——CAD c# 二次开发
windows·microsoft·c#
TENET信条2 小时前
day53 第十一章:图论part04
开发语言·c#·图论
anlog3 小时前
C#在自定义事件里传递数据
开发语言·c#·自定义事件
向宇it5 小时前
【从零开始入门unity游戏开发之——unity篇01】unity6基础入门开篇——游戏引擎是什么、主流的游戏引擎、为什么选择Unity
开发语言·unity·c#·游戏引擎
仰望大佬0075 小时前
Avalonia实例实战五:Carousel自动轮播图
数据库·microsoft·c#
糖朝5 小时前
c#读取json
c#·json
向宇it10 小时前
【从零开始入门unity游戏开发之——C#篇26】C#面向对象动态多态——接口(Interface)、接口里氏替换原则、密封方法(`sealed` )
java·开发语言·unity·c#·游戏引擎·里氏替换原则
Java Fans14 小时前
C# 中串口读取问题及解决方案
开发语言·c#
盛派网络小助手14 小时前
微信 SDK 更新 Sample,NCF 文档和模板更新,更多更新日志,欢迎解锁
开发语言·人工智能·后端·架构·c#