mirror of
https://github.com/alex289/CleanArchitecture.git
synced 2025-06-29 18:21:08 +00:00
feat: Add swagger attribute for sorting
This commit is contained in:
parent
6d63df1eda
commit
3410c8575d
@ -7,29 +7,29 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.ApplicationStatus" Version="7.0.0"/>
|
<PackageReference Include="AspNetCore.HealthChecks.ApplicationStatus" Version="7.0.0" />
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="7.0.0"/>
|
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="7.0.0" />
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.Redis" Version="7.0.0"/>
|
<PackageReference Include="AspNetCore.HealthChecks.Redis" Version="7.0.0" />
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="7.0.0"/>
|
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="7.0.0" />
|
||||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="7.1.0"/>
|
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="7.1.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.10"/>
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.10" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.10"/>
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.10" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.10">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.10">
|
||||||
<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.EntityFrameworkCore.Proxies" Version="7.0.10"/>
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.10" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="7.0.10"/>
|
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="7.0.10" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="7.0.10"/>
|
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="7.0.10" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0"/>
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.5.0"/>
|
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.5.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\CleanArchitecture.Application\CleanArchitecture.Application.csproj"/>
|
<ProjectReference Include="..\CleanArchitecture.Application\CleanArchitecture.Application.csproj" />
|
||||||
<ProjectReference Include="..\CleanArchitecture.Domain\CleanArchitecture.Domain.csproj"/>
|
<ProjectReference Include="..\CleanArchitecture.Domain\CleanArchitecture.Domain.csproj" />
|
||||||
<ProjectReference Include="..\CleanArchitecture.gRPC\CleanArchitecture.gRPC.csproj"/>
|
<ProjectReference Include="..\CleanArchitecture.gRPC\CleanArchitecture.gRPC.csproj" />
|
||||||
<ProjectReference Include="..\CleanArchitecture.Infrastructure\CleanArchitecture.Infrastructure.csproj"/>
|
<ProjectReference Include="..\CleanArchitecture.Infrastructure\CleanArchitecture.Infrastructure.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CleanArchitecture.Api.Models;
|
using CleanArchitecture.Api.Models;
|
||||||
|
using CleanArchitecture.Api.Swagger;
|
||||||
using CleanArchitecture.Application.Interfaces;
|
using CleanArchitecture.Application.Interfaces;
|
||||||
|
using CleanArchitecture.Application.SortProviders;
|
||||||
using CleanArchitecture.Application.ViewModels;
|
using CleanArchitecture.Application.ViewModels;
|
||||||
using CleanArchitecture.Application.ViewModels.Sorting;
|
using CleanArchitecture.Application.ViewModels.Sorting;
|
||||||
using CleanArchitecture.Application.ViewModels.Tenants;
|
using CleanArchitecture.Application.ViewModels.Tenants;
|
||||||
|
using CleanArchitecture.Domain.Entities;
|
||||||
using CleanArchitecture.Domain.Notifications;
|
using CleanArchitecture.Domain.Notifications;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
@ -34,7 +37,7 @@ public sealed class TenantController : ApiController
|
|||||||
[FromQuery] PageQuery query,
|
[FromQuery] PageQuery query,
|
||||||
[FromQuery] string searchTerm = "",
|
[FromQuery] string searchTerm = "",
|
||||||
[FromQuery] bool includeDeleted = false,
|
[FromQuery] bool includeDeleted = false,
|
||||||
[FromQuery] SortQuery? sortQuery = null)
|
[FromQuery, SortableFieldsAttribute<TenantViewModelSortProvider, TenantViewModel, Tenant>] SortQuery? sortQuery = null)
|
||||||
{
|
{
|
||||||
var tenants = await _tenantService.GetAllTenantsAsync(
|
var tenants = await _tenantService.GetAllTenantsAsync(
|
||||||
query,
|
query,
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CleanArchitecture.Api.Models;
|
using CleanArchitecture.Api.Models;
|
||||||
|
using CleanArchitecture.Api.Swagger;
|
||||||
using CleanArchitecture.Application.Interfaces;
|
using CleanArchitecture.Application.Interfaces;
|
||||||
|
using CleanArchitecture.Application.SortProviders;
|
||||||
using CleanArchitecture.Application.ViewModels;
|
using CleanArchitecture.Application.ViewModels;
|
||||||
using CleanArchitecture.Application.ViewModels.Sorting;
|
using CleanArchitecture.Application.ViewModels.Sorting;
|
||||||
using CleanArchitecture.Application.ViewModels.Users;
|
using CleanArchitecture.Application.ViewModels.Users;
|
||||||
|
using CleanArchitecture.Domain.Entities;
|
||||||
using CleanArchitecture.Domain.Notifications;
|
using CleanArchitecture.Domain.Notifications;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
@ -34,7 +37,7 @@ public sealed class UserController : ApiController
|
|||||||
[FromQuery] PageQuery query,
|
[FromQuery] PageQuery query,
|
||||||
[FromQuery] string searchTerm = "",
|
[FromQuery] string searchTerm = "",
|
||||||
[FromQuery] bool includeDeleted = false,
|
[FromQuery] bool includeDeleted = false,
|
||||||
[FromQuery] SortQuery? sortQuery = null)
|
[FromQuery, SortableFieldsAttribute<UserViewModelSortProvider, UserViewModel, User>] SortQuery? sortQuery = null)
|
||||||
{
|
{
|
||||||
var users = await _userService.GetAllUsersAsync(
|
var users = await _userService.GetAllUsersAsync(
|
||||||
query,
|
query,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using CleanArchitecture.Api.Swagger;
|
||||||
using CleanArchitecture.Domain.Settings;
|
using CleanArchitecture.Domain.Settings;
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
@ -34,6 +35,10 @@ public static class ServiceCollectionExtension
|
|||||||
Scheme = "bearer"
|
Scheme = "bearer"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
c.ParameterFilter<SortableFieldsAttributeFilter>();
|
||||||
|
|
||||||
|
c.SupportNonNullableReferenceTypes();
|
||||||
|
|
||||||
c.AddSecurityRequirement(new OpenApiSecurityRequirement
|
c.AddSecurityRequirement(new OpenApiSecurityRequirement
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
16
CleanArchitecture.Api/Swagger/SortableFieldsAttribute.cs
Normal file
16
CleanArchitecture.Api/Swagger/SortableFieldsAttribute.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using CleanArchitecture.Application.ViewModels.Sorting;
|
||||||
|
|
||||||
|
namespace CleanArchitecture.Api.Swagger;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
|
||||||
|
public sealed class SortableFieldsAttribute<TSortingProvider, TViewModel, TEntity>
|
||||||
|
: SwaggerSortableFieldsAttribute
|
||||||
|
where TSortingProvider : ISortingExpressionProvider<TViewModel, TEntity>, new()
|
||||||
|
{
|
||||||
|
public override IEnumerable<string> GetFields()
|
||||||
|
{
|
||||||
|
return new TSortingProvider().GetSortingExpressions().Keys;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
|
||||||
|
namespace CleanArchitecture.Api.Swagger;
|
||||||
|
|
||||||
|
public sealed class SortableFieldsAttributeFilter : IParameterFilter
|
||||||
|
{
|
||||||
|
public void Apply(OpenApiParameter parameter, ParameterFilterContext context)
|
||||||
|
{
|
||||||
|
if (context.ParameterInfo is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var attribute = context.ParameterInfo
|
||||||
|
.GetCustomAttributes<SwaggerSortableFieldsAttribute>()
|
||||||
|
.SingleOrDefault();
|
||||||
|
|
||||||
|
if (attribute is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var description = string.Join("<br/>", attribute.GetFields().Order());
|
||||||
|
|
||||||
|
parameter.Description = $"{parameter.Description}<br/><br/>" +
|
||||||
|
$"**Allowed values:**<br/>{description}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace CleanArchitecture.Api.Swagger;
|
||||||
|
|
||||||
|
public abstract class SwaggerSortableFieldsAttribute : Attribute
|
||||||
|
{
|
||||||
|
public abstract IEnumerable<string> GetFields();
|
||||||
|
}
|
@ -10,6 +10,7 @@ public sealed class SortQuery
|
|||||||
|
|
||||||
public ReadOnlyCollection<SortParameter> Parameters { get; private set; } = new(Array.Empty<SortParameter>());
|
public ReadOnlyCollection<SortParameter> Parameters { get; private set; } = new(Array.Empty<SortParameter>());
|
||||||
|
|
||||||
|
|
||||||
[FromQuery(Name = "order_by")]
|
[FromQuery(Name = "order_by")]
|
||||||
public string? Query
|
public string? Query
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user