【个人博客搭建】(17)使用FluentValidation 参数校验

FluentValidation 是一个用于 .NET 的开源验证库,它提供了一种流畅的接口和强类型验证规则,使得验证逻辑表达得更加清晰和简洁。(Apache-2.0)

FluentValidation 的主要作用包括:

  1. 提高代码可读性:通过使用 Fluent 接口和 lambda 表达式,FluentValidation 能够让验证逻辑更容易被阅读和理解。
  2. 简化验证逻辑编写:它允许开发者以声明式的方式构建复杂的验证规则,这样可以减少编写重复性验证代码的工作量。
  3. 易于维护:由于验证规则是强类型的,这使得维护和重构变得更加容易,因为编译器可以帮助检查类型安全。
  4. 支持 .NET 8:FluentValidation 更新迅速,与 .NET 8 保持同步,确保了在新平台上的可用性。
  5. 自定义错误消息:FluentValidation 允许开发者为每个验证规则定义自定义的错误消息,这样可以提供更具体的错误反馈给最终用户。
  6. 扩展性强:如果默认提供的验证规则不满足需求,开发者可以创建自定义的验证器来应对特定的业务逻辑。
  7. 集成灵活:FluentValidation 可以轻松地集成到现有的 .NET Core Web API 或 MVC 项目中,与模型绑定和数据注解无缝协作。

总的来说,FluentValidation 是一个功能强大且易于使用的验证库,它能够帮助 .NET 开发者构建健壮的应用程序,同时保持良好的代码质量和可维护性。

前边我们做了系统登录注册的简单接口,对于参数的处理都是通过代码去编写的,如下:

//验证
if (string.IsNullOrWhiteSpace(para.UserName) || string.IsNullOrWhiteSpace(para.PassWord))
{
    return ApiResultHelper.Error("请输入账号或密码!");
}

如果其他地方也需要类似的判断处理,则,需要对代码进行复制,复制的地方多了,后续维护的成本也会加大! 

所以,我们希望能有一个统一的处理方式来规划这些值,

于是,便有了对FluentValidation验证体系的使用了。

(五一结束了,也祝各位工作顺利,升职加薪!)

进入正题

1、安装nuget包:FluentValidation 

2、 配置验证规则。

        我这里是把验证模式放在Model层,创建Validation文件夹处理的,也可以放在入参那边的模型下边。

例子:

/// <summary>
/// 用户登录 入参 校验
/// </summary>
public class LoginUserValidator : AbstractValidator<LoginUserParameters>
{
    public LoginUserValidator()
    {
        RuleFor(para => para.UserName).NotEmpty().WithMessage("【用户名】不能为空");
        RuleFor(para => para.PassWord).NotEmpty().WithMessage("【密码】不能为空");
    }
}

/// <summary>
/// 用户注册 入参 校验
/// </summary>
public class RegisterUserValidator : AbstractValidator<RegisterUserParameters>
{

    public RegisterUserValidator()
    {
        //1.不为空
        string notEmpty = "不能为空";
        RuleFor(para => para.UserName).NotEmpty().WithMessage("【用户名】" + notEmpty);
        RuleFor(para => para.PassWord).NotEmpty().WithMessage("【密码】" + notEmpty);
        RuleFor(para => para.Email).NotEmpty().WithMessage("【邮箱】" + notEmpty);
        RuleFor(para => para.AuthCode).NotEmpty().WithMessage("【验证码】" + notEmpty);

        //2.数据库存储长度限制
        //(ps:可用sugar特性或查询数据库配置统一处理吧)
        string notLength = "长度有误";
        RuleFor(para => para.UserName).Length(1, 25).WithMessage("【用户名】" + notLength);
        RuleFor(para => para.PassWord).Length(6, 18).WithMessage("【密码】" + notLength);
        RuleFor(para => para.Email).Length(6, 30).WithMessage("【邮箱】" + notLength);//不建议限制
        RuleFor(user => user.AuthCode).Length(6, 8).WithMessage("【验证码】" + notLength);

        //3.格式(正则)
        string notMatches = "格式不正确";
        RuleFor(user => user.Email).Matches(@"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$").WithMessage("【邮箱】" + notMatches);//可与上边拼接一起

    }

}

        这里一个是简单方式的,一个是验证方式较多的。

        如有其他需要,可自行百度或搜索其他方式方法。

3、注入服务

builder.Services.AddTransient<IValidator<LoginUserParameters>, LoginUserValidator>();
builder.Services.AddTransient<IValidator<RegisterUserParameters>, RegisterUserValidator>();

4、使用。

        4.1、控制器层注入

 private readonly ILogger<UsersController> _logger;
 private readonly IUsersService _usersService;
 //参数验证
 private readonly IValidator<LoginUserParameters> _loginUserParametersValidator;
 private readonly IValidator<RegisterUserParameters> _registerUserParametersValidator;

 /// <summary>
 /// 构造函数
 /// </summary>
 /// <param name="logger"></param>
 public UsersController(ILogger<UsersController> logger, IUsersService usersService,
     IValidator<LoginUserParameters> loginUserParametersValidator,
     IValidator<RegisterUserParameters> registerUserParametersValidator)
 {
     _logger = logger;
     _usersService = usersService;

     _loginUserParametersValidator = loginUserParametersValidator;
     _registerUserParametersValidator = registerUserParametersValidator;
 }

        4.2、方法Action中使用

 var validationResult = _loginUserParametersValidator.Validate(para);
 if (!validationResult.IsValid)
 {
     //return BadRequest(validationResult.Errors);
     var errs = validationResult.Errors;
     var errsStr = string.Empty;
     var index = 1;
     validationResult.Errors.ForEach(t =>
     {
         errsStr = errsStr + index.ToString() + "、" + t.ToString() + ";";
         index ++;
     });
     return ApiResultHelper.Error("【参数验证失败】" + errsStr);
 }

5、测试:

        5.1、如图。(无账号)

        这里把所有有误的都加上来了

        然后,我们通过信息查看,其实为空的是否必然长度是不对的,也就没必要体现出来

        所以,在注入后再添加代码:

//(1)设置模型类的CascadeMode,当模型的第一个验证失败,后续验证不执行。
ValidatorOptions.Global.DefaultClassLevelCascadeMode = CascadeMode.Stop;
//(2)设置模型字段的CascadeMode,当字段的第一个验证失败,后续验证不执行。
ValidatorOptions.Global.DefaultRuleLevelCascadeMode = CascadeMode.Stop;

        这就很符合我们自己写逻辑的规则方式了。        

        继续测试的效果也就是第一个错误提示了。

        最后,在验证那一串循环代码,可以在封装一下,不然也是每次写这么多重复代码。

6、其他:

        6.1、在查询该功能实现及其他处理,可参考文章:

fluentvalidation - 简书

https://www.cnblogs.com/wenthing/p/18006465 

        6.2、拓展:自定义一个处理方式。

  • 16
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好,针对您的问题,我们可以通过自定义校验器和依赖注入来实现在校验过程中进行数据库查询。以下是一个简单的示例: 1. 创建一个自定义校验器 ```csharp public class UniqueEmailValidator : AbstractValidator<string> { private readonly IDbConnection _dbConnection; public UniqueEmailValidator(IDbConnection dbConnection) { _dbConnection = dbConnection; RuleFor(email => email) .NotEmpty() .EmailAddress() .MustAsync(BeUniqueEmail) .WithMessage("该邮箱已被注册!"); } private async Task<bool> BeUniqueEmail(string email, CancellationToken cancellationToken) { var count = await _dbConnection.ExecuteScalarAsync<int>("SELECT COUNT(*) FROM Users WHERE Email = @Email", new { Email = email }); return count == 0; } } ``` 在上面的代码中,我们定义了一个 `UniqueEmailValidator` 类,它继承自 `AbstractValidator<string>`,用于验证邮件地址是否唯一。在构造函数中,我们注入了一个 `IDbConnection` 对象,这样可以在校验过程中使用它来进行数据库查询。 在 `BeUniqueEmail` 方法中,我们使用 `IDbConnection` 对象执行了一个查询语句,检查是否有相同的邮件地址。如果查询结果为 0,表示该邮件地址是唯一的,返回 `true`,否则返回 `false`。 2. 注册自定义校验器 ```csharp services.AddTransient<IValidator<string>, UniqueEmailValidator>(); ``` 在上面的代码中,我们使用 ASP.NET Core 的依赖注入机制,将 `UniqueEmailValidator` 类注册为 `IValidator<string>` 接口的实现,这样就可以在需要进行邮件地址校验的地方使用它了。 3. 在控制器中使用自定义校验器 ```csharp public async Task<IActionResult> Register(RegisterViewModel model) { if (!ModelState.IsValid) { return View(model); } // do something... return RedirectToAction(nameof(HomeController.Index), "Home"); } ``` 在上面的代码中,我们在控制器的 `Register` 方法中使用了自定义校验器。如果模型状态不合法,即校验失败,就返回模型本身,否则就执行其他的业务逻辑。 希望这个示例能够帮助到您。如果您还有其他问题,可以随时向我提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值