From ba53652de62b80a3bbec6958924372348626d876 Mon Sep 17 00:00:00 2001 From: xiaolipro <2357729423@qq.com> Date: Fri, 22 Mar 2024 18:12:29 +0800 Subject: [PATCH] 1 --- InterfaceForward.sln.DotSettings.user | 2 + common.props | 1 + .../InterfaceForwardApiContractModule.cs | 9 +++ .../Controllers/InterfaceController.cs | 4 +- .../Filters/CustomerResultAttribute.cs | 8 +++ .../Filters/DefaultUnifiedResultHandler.cs | 56 +++++++++++++++++++ .../Filters/GlobalExceptionFilter.cs | 36 ++++++++++++ .../Filters/IUnifiedResultHandler.cs | 11 ++++ .../Filters/ResultFactory.cs | 19 +++++++ src/InterfaceForward.Api/Filters/Results.cs | 42 ++++++++++++++ .../Filters/UnifiedResultFilter.cs | 26 +++++++++ .../InterfaceForward.Api.csproj | 6 +- .../InterfaceForwardApiModule.cs | 34 +++++++++++ src/InterfaceForward.Api/Program.cs | 2 +- .../InterfaceMapEntity.cs | 4 +- .../InterfaceForward.Domain.csproj | 2 +- .../InterfaceForward.Infrastructure.csproj | 2 +- .../InterfaceForward.ServiceDefaults.csproj | 12 ++-- .../GlobalUsings.cs | 1 + .../InterfaceForward.Domain.Tests.csproj | 29 ++++++++++ .../InterfaceForwardDomainTestModule.cs | 10 ++++ 21 files changed, 299 insertions(+), 17 deletions(-) create mode 100644 InterfaceForward.sln.DotSettings.user create mode 100644 src/InterfaceForward.Api.Contract/InterfaceForwardApiContractModule.cs create mode 100644 src/InterfaceForward.Api/Filters/CustomerResultAttribute.cs create mode 100644 src/InterfaceForward.Api/Filters/DefaultUnifiedResultHandler.cs create mode 100644 src/InterfaceForward.Api/Filters/GlobalExceptionFilter.cs create mode 100644 src/InterfaceForward.Api/Filters/IUnifiedResultHandler.cs create mode 100644 src/InterfaceForward.Api/Filters/ResultFactory.cs create mode 100644 src/InterfaceForward.Api/Filters/Results.cs create mode 100644 src/InterfaceForward.Api/Filters/UnifiedResultFilter.cs create mode 100644 tests/InterfaceForward.Domain.Tests/GlobalUsings.cs create mode 100644 tests/InterfaceForward.Domain.Tests/InterfaceForward.Domain.Tests.csproj create mode 100644 tests/InterfaceForward.Domain.Tests/InterfaceForwardDomainTestModule.cs diff --git a/InterfaceForward.sln.DotSettings.user b/InterfaceForward.sln.DotSettings.user new file mode 100644 index 0000000..ea7af24 --- /dev/null +++ b/InterfaceForward.sln.DotSettings.user @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/common.props b/common.props index 9ad7e59..6dfdd8f 100644 --- a/common.props +++ b/common.props @@ -2,6 +2,7 @@ latest enable + enable diff --git a/src/InterfaceForward.Api.Contract/InterfaceForwardApiContractModule.cs b/src/InterfaceForward.Api.Contract/InterfaceForwardApiContractModule.cs new file mode 100644 index 0000000..2fdf836 --- /dev/null +++ b/src/InterfaceForward.Api.Contract/InterfaceForwardApiContractModule.cs @@ -0,0 +1,9 @@ +using Fake.Modularity; +using InterfaceForward.Domain; + +namespace InterfaceForward.Api.Contract; + +[DependsOn(typeof(InterfaceForwardDomainModule))] +public class InterfaceForwardApiContractModule:FakeModule +{ +} \ No newline at end of file diff --git a/src/InterfaceForward.Api/Controllers/InterfaceController.cs b/src/InterfaceForward.Api/Controllers/InterfaceController.cs index 90b7372..68f0be9 100644 --- a/src/InterfaceForward.Api/Controllers/InterfaceController.cs +++ b/src/InterfaceForward.Api/Controllers/InterfaceController.cs @@ -14,8 +14,8 @@ public class InterfaceController: ControllerBase /// /// [HttpPost("/SystemInterfacePaginatedList")] - public async Task> SystemInterfacePaginatedListAsync(SystemInterfacePaginatedInputObjectValue input) + public async Task SystemInterfacePaginatedListAsync() { - return await _interfaceRepository.GetSystemInterfacePaginatedListAsync(input); + return; } } \ No newline at end of file diff --git a/src/InterfaceForward.Api/Filters/CustomerResultAttribute.cs b/src/InterfaceForward.Api/Filters/CustomerResultAttribute.cs new file mode 100644 index 0000000..5854bff --- /dev/null +++ b/src/InterfaceForward.Api/Filters/CustomerResultAttribute.cs @@ -0,0 +1,8 @@ +using System; + +namespace InterfaceForward.Api.Filters; + +public class CustomerResultAttribute : Attribute +{ + +} \ No newline at end of file diff --git a/src/InterfaceForward.Api/Filters/DefaultUnifiedResultHandler.cs b/src/InterfaceForward.Api/Filters/DefaultUnifiedResultHandler.cs new file mode 100644 index 0000000..c7d422b --- /dev/null +++ b/src/InterfaceForward.Api/Filters/DefaultUnifiedResultHandler.cs @@ -0,0 +1,56 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; + +namespace InterfaceForward.Api.Filters; + +public class DefaultUnifiedResultHandler : IUnifiedResultHandler +{ + public void HandleActionResult(ResultExecutingContext context) + { + // void、Task会被包装成EmptyResult + if (context.Result is EmptyResult) + { + var res = ResultFactory.CreateSimpleResult(); + context.Result = new ObjectResult(res); + + return; + } + + // string、int、list以及自定义的模型,都会被包装成为ObjectResult + if (context.Result is ObjectResult objectResult) + { + var value = objectResult.Value; + + // 已unified的无须再包装 + if (value is SimpleResult) return; + + var res = ResultFactory.CreateDataResult(); + + // A machine-readable format for specifying errors in HTTP API responses based on https://tools.ietf.org/html/rfc7807. + if (value is ProblemDetails details) + { + res.Code = details.Status; + res.Message = details.Title; + res.Data = context.ModelState.Keys + .SelectMany(key => + context.ModelState[key]!.Errors + .Where(x => !string.IsNullOrWhiteSpace(key)) + .Select(x => new + { + Field = key, + Message = x.ErrorMessage + }) + ) + .ToList(); + objectResult.Value = res; + return; + } + + res.Data = value; + objectResult.Value = res; + + // 解决string格式问题 + objectResult.DeclaredType = res.GetType(); + } + } +} diff --git a/src/InterfaceForward.Api/Filters/GlobalExceptionFilter.cs b/src/InterfaceForward.Api/Filters/GlobalExceptionFilter.cs new file mode 100644 index 0000000..aa074e4 --- /dev/null +++ b/src/InterfaceForward.Api/Filters/GlobalExceptionFilter.cs @@ -0,0 +1,36 @@ +using System.Net; +using System.Text; +using Fake; +using Fake.DependencyInjection; +using Fake.Json; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; + +namespace InterfaceForward.Api.Filters; + +public class GlobalExceptionFilter(IHostEnvironment environment) : IAsyncExceptionFilter, ITransientDependency +{ + public async Task OnExceptionAsync(ExceptionContext context) + { + if (context.ExceptionHandled) return; + + var result = ResultFactory.CreateErrorResult(); + result.Message = context.Exception.Message; + if (environment.IsDevelopment()) + { + result.StackTrace = context.Exception.StackTrace; + } + + if (context.Exception is BusinessException) //业务异常 + { + result.Code = (int)HttpStatusCode.BadRequest; + } + else //未处理异常 + { + result.Code = (int)HttpStatusCode.InternalServerError; + } + + context.Result = new JsonResult(result); + context.ExceptionHandled = true; + } +} \ No newline at end of file diff --git a/src/InterfaceForward.Api/Filters/IUnifiedResultHandler.cs b/src/InterfaceForward.Api/Filters/IUnifiedResultHandler.cs new file mode 100644 index 0000000..457db8c --- /dev/null +++ b/src/InterfaceForward.Api/Filters/IUnifiedResultHandler.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Mvc.Filters; + +namespace InterfaceForward.Api.Filters; + +/// +/// 在这里定义你的结果格式 +/// +public interface IUnifiedResultHandler +{ + void HandleActionResult(ResultExecutingContext context); +} \ No newline at end of file diff --git a/src/InterfaceForward.Api/Filters/ResultFactory.cs b/src/InterfaceForward.Api/Filters/ResultFactory.cs new file mode 100644 index 0000000..36a9553 --- /dev/null +++ b/src/InterfaceForward.Api/Filters/ResultFactory.cs @@ -0,0 +1,19 @@ +namespace InterfaceForward.Api.Filters; + +public static class ResultFactory +{ + public static SimpleResult CreateSimpleResult() + { + return new SimpleResult(); + } + + public static DataResult CreateDataResult() where T : class + { + return new DataResult(); + } + + public static ErrorResult CreateErrorResult() + { + return new ErrorResult(); + } +} \ No newline at end of file diff --git a/src/InterfaceForward.Api/Filters/Results.cs b/src/InterfaceForward.Api/Filters/Results.cs new file mode 100644 index 0000000..0cd6b45 --- /dev/null +++ b/src/InterfaceForward.Api/Filters/Results.cs @@ -0,0 +1,42 @@ +using System.Net; + +namespace InterfaceForward.Api.Filters; + +public class SimpleResult +{ + /// + /// 响应状态码 + /// + public int? Code { get; set; } + + /// + /// 响应消息 + /// + public string? Message { get; set; } + + public SimpleResult(int code = (int)HttpStatusCode.OK) + { + Code = code; + } +} + +public class DataResult : SimpleResult where T : class +{ + /// + /// 响应数据 + /// + public T? Data { get; set; } +} + +public class ErrorResult : SimpleResult +{ + public ErrorResult() + { + Code = (int)HttpStatusCode.InternalServerError; + } + + /// + /// 异常堆栈 + /// + public string? StackTrace { get; set; } +} diff --git a/src/InterfaceForward.Api/Filters/UnifiedResultFilter.cs b/src/InterfaceForward.Api/Filters/UnifiedResultFilter.cs new file mode 100644 index 0000000..2475e25 --- /dev/null +++ b/src/InterfaceForward.Api/Filters/UnifiedResultFilter.cs @@ -0,0 +1,26 @@ +using Microsoft.AspNetCore.Mvc.Filters; + +namespace InterfaceForward.Api.Filters; + +/// +/// 统一包装action-result +/// +public class UnifiedResultFilter : IAsyncResultFilter +{ + private readonly IUnifiedResultHandler _unifiedResultHandler; + + public UnifiedResultFilter(IUnifiedResultHandler unifiedResultHandler) + { + _unifiedResultHandler = unifiedResultHandler; + } + + public virtual async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) + { + if (context.ActionDescriptor.EndpointMetadata.Any( + x => x.GetType() == typeof(CustomerResultAttribute))) return; + + _unifiedResultHandler.HandleActionResult(context); + + await next(); + } +} diff --git a/src/InterfaceForward.Api/InterfaceForward.Api.csproj b/src/InterfaceForward.Api/InterfaceForward.Api.csproj index a251e8e..5ee26d7 100644 --- a/src/InterfaceForward.Api/InterfaceForward.Api.csproj +++ b/src/InterfaceForward.Api/InterfaceForward.Api.csproj @@ -1,9 +1,9 @@ + + net8.0 - enable - enable Linux @@ -21,7 +21,7 @@ - + diff --git a/src/InterfaceForward.Api/InterfaceForwardApiModule.cs b/src/InterfaceForward.Api/InterfaceForwardApiModule.cs index 96c79aa..b8cceb5 100644 --- a/src/InterfaceForward.Api/InterfaceForwardApiModule.cs +++ b/src/InterfaceForward.Api/InterfaceForwardApiModule.cs @@ -1,11 +1,14 @@ using Fake.AspNetCore; +using Fake.Authorization; using Fake.Modularity; using InterfaceForward.Api.Contract; +using InterfaceForward.Api.Filters; using InterfaceForward.Domain; namespace InterfaceForward.Api; [DependsOn(typeof(FakeAspNetCoreModule))] +[DependsOn(typeof(FakeAuthorizationModule))] [DependsOn(typeof(InterfaceForwardDomainModule))] [DependsOn(typeof(InterfaceForwardApiContractModule))] public class InterfaceForwardApiModule : FakeModule @@ -16,6 +19,14 @@ public class InterfaceForwardApiModule : FakeModule // Add services to the container. services.AddProblemDetails(); + + services.AddControllers(options => + { + options.Filters.AddService(); + options.Filters.AddService(); + }); + + services.AddSwagger(); } public override void ConfigureApplication(ApplicationConfigureContext context) @@ -26,5 +37,28 @@ public class InterfaceForwardApiModule : FakeModule app.MapDefaultEndpoints(); app.MapGet("/", () => "Hello World!"); + + // Configure the HTTP request pipeline. + if (app.Environment.IsDevelopment()) + { + app.UseSwagger(); + app.UseSwaggerUI(options => + { + options.SwaggerEndpoint("/swagger/v1/swagger.json", "v1"); + options.RoutePrefix = string.Empty; + }); + } + } +} + +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddSwagger(this IServiceCollection services) + { + // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle + services.AddEndpointsApiExplorer(); + services.AddSwaggerGen(); + + return services; } } \ No newline at end of file diff --git a/src/InterfaceForward.Api/Program.cs b/src/InterfaceForward.Api/Program.cs index 9fc5ea9..a7022db 100644 --- a/src/InterfaceForward.Api/Program.cs +++ b/src/InterfaceForward.Api/Program.cs @@ -1,6 +1,6 @@ using InterfaceForward.Api; -var builder = WebApplication.CreateSlimBuilder(args); +var builder = WebApplication.CreateBuilder(args); builder.Services.AddApplication(); diff --git a/src/InterfaceForward.Domain/Aggregates/InterfaceMapAggregate/InterfaceMapEntity.cs b/src/InterfaceForward.Domain/Aggregates/InterfaceMapAggregate/InterfaceMapEntity.cs index eec7e45..6f6a9af 100644 --- a/src/InterfaceForward.Domain/Aggregates/InterfaceMapAggregate/InterfaceMapEntity.cs +++ b/src/InterfaceForward.Domain/Aggregates/InterfaceMapAggregate/InterfaceMapEntity.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using Fake.DomainDrivenDesign.Entities; +using Fake.DomainDrivenDesign.Entities; using Fake.DomainDrivenDesign.Entities.Auditing; namespace InterfaceForward.Domain.Aggregates.InterfaceMapAggregate; diff --git a/src/InterfaceForward.Domain/InterfaceForward.Domain.csproj b/src/InterfaceForward.Domain/InterfaceForward.Domain.csproj index ed1f667..9fba51f 100644 --- a/src/InterfaceForward.Domain/InterfaceForward.Domain.csproj +++ b/src/InterfaceForward.Domain/InterfaceForward.Domain.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/InterfaceForward.Infrastructure/InterfaceForward.Infrastructure.csproj b/src/InterfaceForward.Infrastructure/InterfaceForward.Infrastructure.csproj index b330ac3..f6ab911 100644 --- a/src/InterfaceForward.Infrastructure/InterfaceForward.Infrastructure.csproj +++ b/src/InterfaceForward.Infrastructure/InterfaceForward.Infrastructure.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/InterfaceForward.ServiceDefaults/InterfaceForward.ServiceDefaults.csproj b/src/InterfaceForward.ServiceDefaults/InterfaceForward.ServiceDefaults.csproj index 97fe4f4..2da4ee2 100644 --- a/src/InterfaceForward.ServiceDefaults/InterfaceForward.ServiceDefaults.csproj +++ b/src/InterfaceForward.ServiceDefaults/InterfaceForward.ServiceDefaults.csproj @@ -13,12 +13,12 @@ - - - - - - + + + + + + diff --git a/tests/InterfaceForward.Domain.Tests/GlobalUsings.cs b/tests/InterfaceForward.Domain.Tests/GlobalUsings.cs new file mode 100644 index 0000000..8c927eb --- /dev/null +++ b/tests/InterfaceForward.Domain.Tests/GlobalUsings.cs @@ -0,0 +1 @@ +global using Xunit; \ No newline at end of file diff --git a/tests/InterfaceForward.Domain.Tests/InterfaceForward.Domain.Tests.csproj b/tests/InterfaceForward.Domain.Tests/InterfaceForward.Domain.Tests.csproj new file mode 100644 index 0000000..90b269c --- /dev/null +++ b/tests/InterfaceForward.Domain.Tests/InterfaceForward.Domain.Tests.csproj @@ -0,0 +1,29 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/tests/InterfaceForward.Domain.Tests/InterfaceForwardDomainTestModule.cs b/tests/InterfaceForward.Domain.Tests/InterfaceForwardDomainTestModule.cs new file mode 100644 index 0000000..77e3c02 --- /dev/null +++ b/tests/InterfaceForward.Domain.Tests/InterfaceForwardDomainTestModule.cs @@ -0,0 +1,10 @@ +using Fake.Modularity; + +namespace InterfaceForward.Domain.Tests; + +[DependsOn( + typeof(InterfaceForwardDomainModule) +)] +public class InterfaceForwardDomainTestModule:FakeModule +{ +} \ No newline at end of file