net6中使用FluentValidation做实体验证(批量注册)

实体验证-FluentValidation

首先明白两个概念

  • 自动验证:就是在请求进入到控制器前FluentValidation就自行完成实体的验证并做错误返回,
    • 优点:简单 少一些手动调用的代码
    • 缺点:灵活性差,不好控制,不支持异步等。官方不建议使用自动验证
  • 手动验证:在代码中手动示例验证类,进行调用 并自己判断校验结果 获取错误信息,自行做错误返回控制
    • 优点:控制方便,返回结构可控制
    • 缺点:需要手动创建并传入校验体,重复代码较多(可自己做一次封装,这样就不多了)

如下是官方原文

With automatic validation, FluentValidation plugs into the validation pipeline that’s part of ASP.NET Core MVC and allows models to be validated before a controller action is invoked (during model-binding). This approach to validation is more seamless but has several downsides:

Auto validation is not asynchronous: If your validator contains asynchronous rules then your validator will not be able to run. You will receive an exception at runtime if you attempt to use an asynchronous validator with auto-validation.
Auto validation is MVC-only: Auto-validation only works with MVC Controllers and Razor Pages. It does not work with the more modern parts of ASP.NET such as Minimal APIs or Blazor.
Auto validation is hard to debug: The ‘magic’ nature of auto-validation makes it hard to debug/troubleshoot if something goes wrong as so much is done behind the scenes.

We do not generally recommend using auto validation for new projects, but it is still available for legacy implementations.

需要的扩展包

  • FluentValidation.AspNetCore :自动验证需要的包,若不需要自动验证只使用手动验证的话 可以不添加这个包
  • FluentValidation.DependencyInjectionExtensions :自动注册所有的扩展验证类到服务管道

添加服务注册

下面的代码我做了一个类的封装,直接在Program.cs中可以用builder.Services.AddFluentValidationAutoValidation(); 这样来使用

/// <summary>
        /// 添加 FluentValidation 到容器
        /// 自动注册所有验证器
        /// </summary>
        public static void AddFluentValidationSetup(this IServiceCollection services)
        {
            if (services == null) 
                throw new ArgumentNullException(nameof(services));
            if (!Appsettings.app(new string[] { "Startup", "FluentValidation", "Enabled" }).ObjToBool())
                return;
            if (Appsettings.app(new string[] { "Startup", "FluentValidation", "AutoValidation" }).ObjToBool()) // 通过配置文件来控制是否需要使用自动校验
                services.AddFluentValidationAutoValidation(); // 注册这个会 启用自动验证,在控制器前进行实体验证
            services.AddValidatorsFromAssemblyContaining(typeof(IFluentValidation));

        }

IFluentValidation 这个i接口如下:

  /// <summary>
    /// 功 能: 一个空接口,验证类继承该接口,用于批量管道注册
    /// V0.01 2023-2-16 10:23:22 xliu  初版
    /// </summary>
    public interface IFluentValidation
    {
    }

添加两个页面实体

  /// <summary>
    /// 功 能:  用户信息
    /// V0.01 2023-2-13 15:59:21 xliu  初版
    /// </summary>
    public class UserDto
    {
        /// <summary>
        /// 用户id
        /// </summary>
        public string UID { get; set; }

        /// <summary>
        /// 用户类型
        /// </summary>
        public string UType { get; set; }

        /// <summary>
        /// 登录名
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 角色id
        /// </summary>
        public string RoleID { get; set; }

        /// <summary>
        /// 角色名称
        /// </summary>
        public string RoleName { get; set; }

        /// <summary>
        /// 权限集
        /// </summary>
        public string Permissions { get; set; }
    }

创建两个 验证是否可以直接注册所有的类到服务

 public class UserDto2
    {
        /// <summary>
        /// 用户id
        /// </summary>
        public string UID { get; set; }

        /// <summary>
        /// 用户类型
        /// </summary>
        public string UType { get; set; }

        /// <summary>
        /// 登录名
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 角色id
        /// </summary>
        public string RoleID { get; set; }

        /// <summary>
        /// 角色名称
        /// </summary>
        public string RoleName { get; set; }

        /// <summary>
        /// 权限集
        /// </summary>
        public string Permissions { get; set; }
    }

创建实体验证方法

/// <summary>
    /// 功 能: user请求实体验证
    /// V0.01 2023-2-15 16:56:11 xliu  初版
    /// </summary>
    public class UserValidation: AbstractValidator<UserDto>, IFluentValidation
    {
        public UserValidation() 
        {
            RuleFor(p => p.Name).NotEmpty().WithMessage("用户名不能为空");
        }
    }

    /// <summary>
    /// 功 能: user请求实体验证
    /// V0.01 2023-2-15 16:56:11 xliu  初版
    /// </summary>
    public class UserValidation2: AbstractValidator<UserDto2>, IFluentValidation
    {
        public UserValidation2() 
        {
            RuleFor(p => p.RoleID).NotEmpty().WithMessage("角色ID不能为空");
            RuleFor(p => p.RoleName).NotEmpty();
        }
    }

开始验证

自动验证

注意 自动验证需要注入自动验证那个服务
services.AddFluentValidationAutoValidation();

创建两个控制器
_model 是一个返回实体

 		/// <summary>
        /// 测试 IFluentValidation 效果
        /// </summary>
        /// <param name="userDto2"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("CreateTokenByUser2")]
        public async Task<IActionResult> CreateTokenByUser2(UserDto2 userDto2)
        {
        	// 业务代码
            return BadRequest(_model);
        }
	    [HttpPost]
        [Route("CreateTokenByUser")]
        public async Task<IActionResult> CreateTokenByUser(UserDto userDto)
        {
	        // 业务代码
            return BadRequest(_model);
        }

手动验证

手动验证就需要把那个自动验证的服务注释掉,不然依旧会优先执行自动验证

注入验证器

   		private IValidator<UserDto> _validator;

        public TokenController(IValidator<UserDto> validator)
        {          
            _validator = validator;
        }

		/// <summary>
        /// 根据用户信息创建token
        /// </summary>
        /// <param name="userDto"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("CreateTokenByUser")]
        public async Task<IActionResult> CreateTokenByUser(UserDto userDto)
        {
        // 这里就是手动验证代码,将需要验证的实体带到验证器
            ValidationResult result = await _validator.ValidateAsync(userDto);
            if (!result.IsValid)
            {
                _model.Code = 401;
                _model.Msg = result.Errors.ToArray().ToString();
                return Ok(_model);
            }
            
            return Ok(_model);
        }

结果

UserDTO 自动验证

传入一个空的实体

在这里插入图片描述

传入正确的实体

加了创建token的业务
在这里插入图片描述

UserDTO2自动验证

传入一个空的实体

在这里插入图片描述
可以看出利用 IFluentValidation 这个接口做批量注册是成功的

然后再看看手动验证的方式

UserDTO 手动验证

在这里插入图片描述
可以看到,格式是按照我们的返回实体来做的 使得结构可以控制。但是我没有正确的获取 实体错误信息,使得msg有问题。
验证错误信息在 result.Errors 中。

使用可以参照其他的文章会比较好,这里只是简单的做一个介绍和记录。

记录

简单的记录下遇到的坑,看到FluentValidation这个验证 感觉挺好的,想用。但是看到好多文章都是介绍使用 没有一篇在说怎么做批量注入的,都只是按照官网文档做了一个类的注入。想着不合理 应该是批量注入的方法,找了好久 终于在外网看到了一个解决方法:网址
在这里插入图片描述
不过很可惜,这是21年时的方案,现在官方已经废弃这种方式了
变更记录

在这里插入图片描述

可是最新官网介绍,也只有注入一个验证器的示例:
在这里插入图片描述
通过反编译,可以看到是也是通过类似反射的方式拿到哪些使用过这type的类 全部注册到服务。
在这里插入图片描述
在这里插入图片描述
之后就想着,弄一个空接口 让所有的验证器继承并实现该接口,那就可以去找所有实现过该接口的类 那这些就是我需要注册进去的验证器了。

开始打算直接将整个model层的都通过autofac全部注入,想想太大了 太不合理,后又打算通过反射去找符合条件的类 再注册,感觉不好看就没继续。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FluentValidation 是一个用于验证 .NET 应用程序的输入数据的库。以下是使用 FluentValidation 的一些步骤: 1. 安装 FluentValidation:可以使用 NuGet 包管理器来安装。 2. 创建一个验证器类:创建一个类,继承自 AbstractValidator<T>,其 T 是要验证的模型类。 3. 在验证器类添加规则:使用 Fluent API 在验证器类添加验证规则。 4. 在代码使用验证器:在需要验证输入数据的地方,实例化验证器并调用 Validate() 方法进行验证。 5. 处理验证结果:处理验证结果,可以将错误信息返回给用户或者进行其他操作。 以下是一个使用 FluentValidation 进行验证的示例: ```csharp public class PersonValidator : AbstractValidator<Person> { public PersonValidator() { RuleFor(person => person.Name).NotEmpty().WithMessage("姓名不能为空"); RuleFor(person => person.Age).InclusiveBetween(18, 60).WithMessage("年龄必须在18到60岁之间"); } } Person person = new Person { Name = "", Age = 16 }; PersonValidator validator = new PersonValidator(); ValidationResult result = validator.Validate(person); if (!result.IsValid) { foreach (var error in result.Errors) { Console.WriteLine(error.ErrorMessage); } } ``` 在上面的示例,我们创建了一个 PersonValidator 类,添加了两个验证规则。然后,在代码创建一个 Person 对象,实例化验证器,并调用 Validate() 方法进行验证。如果验证结果不合法,我们将错误信息输出到控制台上。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值