赞
踩
目录
在使用 MediatR 框架时,我们经常需要对命令对象进行验证。为了实现自动验证,我们可以使用 MediatR 的管道行为在命令处理之前执行验证逻辑。本文档将介绍如何在控制器外部使用 MediatR 的管道行为来自动验证实现了 ICommand/IRequest 接口的类,并提供正确地注册验证器和管道行为的方法。
使用Mediator来构建项目框架具有一系列的优点和缺点。以下是对这些优缺点的详细分析:
优点:
缺点:
- ProductManage/
- │
- ├── Controllers/ // 控制器文件夹
- │ └── ProductController.cs
- │
- ├── Models/ // 模型文件夹
- │ └── Product.cs
- │
- ├── Application/ // 应用层文件夹
- │ ├── Commands/ // 命令文件夹
- │ │ └── CreateProductCommand.cs
- │ │
- │ ├── Queries/ // 查询文件夹
- │ │ └── GetProductQuery.cs
- │ │
- │ └── Handlers/ // 处理程序文件夹
- │ ├── CreateProductCommandHandler.cs
- │ └── GetProductQueryHandler.cs
- │
- ├── Infrastructure/ // 基础设施层文件夹
- │ └── Persistence/ // 持久化文件夹
- │ └── DbContext.cs
- │
- ├── Domain/ // 领域层文件夹
- │ └── Entities/ // 实体文件夹
- │ └── Product.cs
- │
- ├── Validators/ // 验证器文件夹
- │ └── CreateProductCommandValidator.cs
- │
- └── Startup.cs // 启动文件
编写一个管道行为来执行验证逻辑,这个管道行为将在命令处理之前执行验证。由于ICommand继承自IRequest接口,所以只需要添加IRequest管道拦截器
- using FluentValidation;
- using MediatR;
- using System.Collections.Generic;
- using System.Linq;
- using System.Threading;
- using System.Threading.Tasks;
- public class ValidationQueryBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
- where TRequest : IRequest<TResponse>
- {
- private readonly IEnumerable<IValidator<TRequest>> _validators;
-
- public ValidationQueryBehavior(IEnumerable<IValidator<TRequest>> validators)
- {
- _validators = validators;
- }
-
- public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
- {
- // 执行所有验证器
-
- var failures = _validators
- .Select(v => v.Validate(request))
- .SelectMany(result => result.Errors)
- .Where(error => error != null)
- .ToList();
-
- var failuresAsync = _validators
- .Select(async v => await v.ValidateAsync(request))
- .SelectMany(result => result.Result.Errors)
- .Where(error => error != null)
- .ToList();
- failures.AddRange(failuresAsync);
-
-
- if (failures.Any())
- {
- throw new DecBussinessExpection(failures.FirstOrDefault().ErrorMessage, Convert.ToInt32(failures.FirstOrDefault().ErrorCode));
- }
-
- // 如果通过验证,则继续执行下一个处理程序
- return await next();
- }
-
-
- }
接下来,我们需要将验证器和管道行为注册到 DI 容器中,以便在 MediatR 的管道中使用它们进行自动验证。
-
- using FluentValidation.AspNetCore;
- using MediatR;
- using Microsoft.Extensions.DependencyInjection;
- using System.Reflection;
-
- public class Startup
- {
- public void ConfigureServices(IServiceCollection services)
- {
- var assemblies = Directory
- .GetFiles(AppDomain.CurrentDomain.BaseDirectory, "ProductManage.Application.*.dll", SearchOption.TopDirectoryOnly)
- .Select(Assembly.LoadFrom).ToArray();
- // 注册 MediatR
- builder.Services.AddMediatR(assemblies);
-
- // 注册 FluentValidation 验证器
- builder.Services.AddValidatorsFromAssemblies(assemblies)
- .AddFluentValidationAutoValidation()
- .AddFluentValidationClientsideAdapters().AddMemoryCache().AddRuleEngine();
-
- // 注册管道行为
- builder.Services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationQueryBehavior<,>));
- }
- }
我们需要定义一个实现了 ICommand 接口的命令类。这个命令类将在 MediatR 管道中被自动验证。
- public class CreateProductCommand : ICommand<ProductDTO>
- {
- public string Name { get; set; }
- public decimal Price { get; set; }
- }
定义一个实现ICommandHandler接口的处理程序类,该类主要实现业务逻辑。
- public class CreateProductHandler : ICommandHandler<CreateProductCommand, ProductDto>
- {
- public Task<ProductDto> Handle(CreateProductCommand request, CancellationToken cancellationToken)
- {
- //实现业务逻辑
-
- }
- }
然后,我们需要编写一个验证器来验证命令类。这个验证器将使用 FluentValidation 等验证库来定义验证规则。
- using FluentValidation;
-
- public class CreateProductCommandValidator : AbstractValidator<CreateProductCommand>
- {
- private IProductService _productService;
-
- public CreateProductCommandValidator(IProductService productService)
- {
- _productService=productService;
- }
-
-
- public override async Task<ValidationResult> ValidateAsync(ValidationContext<CreateProductCommand> context, CancellationToken cancellation = default)
- {
-
- RuleFor(it => it.Name).NotNull().CustomException(CustomerErrorMsg.名称不能为空);
-
- var command = context.InstanceToValidate;
-
-
- if (await _decCustomerMainService.CheckData())
- {
- return new ValidationResult(new[] { new CustomValidationFailure(ProductErrorMsg.该商品不存在) });
- }
-
-
- return await base.ValidateAsync(context, cancellation);
- }
- }
- [HttpPost()]
- public async Task<ApiResponse<ProductDTO>> Create(CreateProductReq requestDto)
- {
-
- var productInfo= await _mediator.Send(new CreateProductCommand(requestDto));
-
- return new ApiResponse<ProductDTO>() { Code = (int)ApiErrorCode.成功, Message = "成功", Result = productInfo};
-
- }
通过以上步骤,我们成功地实现了在控制器外部使用 MediatR 的管道行为来自动验证实现了 ICommand 接口的类。首先,我们定义了命令类和命令验证器。然后,我们注册了验证器和管道行为到 DI 容器中,并编写了管道行为来执行验证逻辑。最终,我们可以在控制器中发送命令,而管道行为会自动执行验证逻辑,并在需要时抛出验证异常。
注:控制器方法参数,FluentValidation会自动拦截验证,不需要额外的在管道里配置拦截验证。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。