fix(api): Исправлена ошибка асинхронной валидации FluentValidation
- удалён устаревший пакет FluentValidation.AspNetCore, вызывавший конфликт версий (NU1605) - реализован глобальный фильтр AsyncValidationFilter для поддержки MustAsync-правил
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using FluentValidation.AspNetCore;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using PARR.API.Contracts.V1.Responses.Base;
|
using PARR.API.Contracts.V1.Responses.Base;
|
||||||
|
using PARR.API.Infrastructure.Filters;
|
||||||
using PARR.API.Infrastructure.Middleware;
|
using PARR.API.Infrastructure.Middleware;
|
||||||
|
|
||||||
namespace PARR.API.Infrastructure
|
namespace PARR.API.Infrastructure
|
||||||
@@ -22,7 +22,11 @@ namespace PARR.API.Infrastructure
|
|||||||
services.AddProblemDetails(); // Генерирует стандартный формат ошибки RFC 7807
|
services.AddProblemDetails(); // Генерирует стандартный формат ошибки RFC 7807
|
||||||
|
|
||||||
// Настройка контроллеров и кастомного формата ошибок валидации
|
// Настройка контроллеров и кастомного формата ошибок валидации
|
||||||
services.AddControllers()
|
services.AddControllers(options =>
|
||||||
|
{
|
||||||
|
// Автоматически применяем асинхронную валидацию ко всем контроллерам
|
||||||
|
options.Filters.Add<AsyncValidationFilter>();
|
||||||
|
})
|
||||||
.ConfigureApiBehaviorOptions(options =>
|
.ConfigureApiBehaviorOptions(options =>
|
||||||
{
|
{
|
||||||
options.InvalidModelStateResponseFactory = context =>
|
options.InvalidModelStateResponseFactory = context =>
|
||||||
@@ -43,7 +47,10 @@ namespace PARR.API.Infrastructure
|
|||||||
//services.AddValidatorsFromAssemblies(Assembly.GetExecutingAssembly());
|
//services.AddValidatorsFromAssemblies(Assembly.GetExecutingAssembly());
|
||||||
|
|
||||||
// Включаем авто-валидацию FluentValidation для контроллеров
|
// Включаем авто-валидацию FluentValidation для контроллеров
|
||||||
services.AddFluentValidationAutoValidation();
|
//services.AddFluentValidationAutoValidation();
|
||||||
|
|
||||||
|
services.AddScoped<AsyncValidationFilter>();
|
||||||
|
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|||||||
47
PARR.API/Infrastructure/Filters/AsyncValidationFilter.cs
Normal file
47
PARR.API/Infrastructure/Filters/AsyncValidationFilter.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using PARR.API.Contracts.V1.Responses.Base;
|
||||||
|
|
||||||
|
namespace PARR.API.Infrastructure.Filters
|
||||||
|
{
|
||||||
|
public class AsyncValidationFilter : IAsyncActionFilter
|
||||||
|
{
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
|
public AsyncValidationFilter(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
||||||
|
{
|
||||||
|
foreach (var argument in context.ActionArguments.Values)
|
||||||
|
{
|
||||||
|
if (argument == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var validatorType = typeof(IValidator<>).MakeGenericType(argument.GetType());
|
||||||
|
var validator = _serviceProvider.GetService(validatorType);
|
||||||
|
|
||||||
|
if (validator is IValidator validatorInstance)
|
||||||
|
{
|
||||||
|
var validationContext = new ValidationContext<object>(argument);
|
||||||
|
var validationResult = await validatorInstance.ValidateAsync(validationContext, context.HttpContext.RequestAborted);
|
||||||
|
|
||||||
|
if (!validationResult.IsValid)
|
||||||
|
{
|
||||||
|
var errors = validationResult.Errors
|
||||||
|
.Select(e => new ErrorModel { Message = e.ErrorMessage })
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
context.Result = new BadRequestObjectResult(new Response(false, errors));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,44 +1,44 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
<DockerComposeProjectPath>..\docker-compose.dcproj</DockerComposeProjectPath>
|
<DockerComposeProjectPath>..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
<NoWarn>1701;1702;1591;1587;1573;NU1803</NoWarn>
|
<NoWarn>1701;1702;1591;1587;1573;NU1803</NoWarn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
<NoWarn>1701;1702;1591;1587;1573;NU1803</NoWarn>
|
<NoWarn>1701;1702;1591;1587;1573;NU1803</NoWarn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
|
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
|
||||||
<PackageReference Include="Elastic.CommonSchema.Serilog" Version="8.19.0" />
|
<PackageReference Include="Elastic.CommonSchema.Serilog" Version="8.19.0" />
|
||||||
<PackageReference Include="FluentValidation.AspNetCore" Version="11.3.1" />
|
<PackageReference Include="FluentValidation" Version="12.1.1" />
|
||||||
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="12.1.1" />
|
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="12.1.1" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.16" />
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.16" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.16">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.16">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.23.0" />
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.23.0" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
|
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
|
||||||
<PackageReference Include="Serilog.Extensions.Hosting" Version="9.0.0" />
|
<PackageReference Include="Serilog.Extensions.Hosting" Version="9.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="6.1.1" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="6.1.1" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.6" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.6" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\PARR.Core\PARR.Core.csproj" />
|
<ProjectReference Include="..\PARR.Core\PARR.Core.csproj" />
|
||||||
<ProjectReference Include="..\PARR.DAL\PARR.DAL.csproj" />
|
<ProjectReference Include="..\PARR.DAL\PARR.DAL.csproj" />
|
||||||
<ProjectReference Include="..\PARR.Infrastructure\PARR.Infrastructure.csproj" />
|
<ProjectReference Include="..\PARR.Infrastructure\PARR.Infrastructure.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace PARR.API.Validators
|
|||||||
{
|
{
|
||||||
private readonly ITnkRepository tnkService;
|
private readonly ITnkRepository tnkService;
|
||||||
private readonly IJobGroupRepository jobGroupService;
|
private readonly IJobGroupRepository jobGroupService;
|
||||||
private readonly IJobRepository jobService;
|
private readonly IJobRepository jobRepository;
|
||||||
private readonly IUnitFieldRepository unitFieldService;
|
private readonly IUnitFieldRepository unitFieldService;
|
||||||
private JobGroup? jobGroup;
|
private JobGroup? jobGroup;
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ namespace PARR.API.Validators
|
|||||||
{
|
{
|
||||||
this.tnkService = tnkService;
|
this.tnkService = tnkService;
|
||||||
this.jobGroupService = jobGroupService;
|
this.jobGroupService = jobGroupService;
|
||||||
this.jobService = jobService;
|
this.jobRepository = jobService;
|
||||||
this.unitFieldService = unitFieldService;
|
this.unitFieldService = unitFieldService;
|
||||||
|
|
||||||
RuleFor(t => t.Name)
|
RuleFor(t => t.Name)
|
||||||
|
|||||||
@@ -13,4 +13,10 @@
|
|||||||
<ProjectReference Include="..\PARR.Infrastructure\PARR.Infrastructure.csproj" />
|
<ProjectReference Include="..\PARR.Infrastructure\PARR.Infrastructure.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="PARR.Core">
|
||||||
|
<HintPath>..\PARR.Core\obj\Debug\net9.0\ref\PARR.Core.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
Reference in New Issue
Block a user