1
This commit is contained in:
parent
a686d5d3a3
commit
ba53652de6
2
InterfaceForward.sln.DotSettings.user
Normal file
2
InterfaceForward.sln.DotSettings.user
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:Boolean x:Key="/Default/Monitoring/IsToolWindowHidden/@EntryValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||||
@ -2,6 +2,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<!-- <WarningsAsErrors>Nullable</WarningsAsErrors>-->
|
<!-- <WarningsAsErrors>Nullable</WarningsAsErrors>-->
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -0,0 +1,9 @@
|
|||||||
|
using Fake.Modularity;
|
||||||
|
using InterfaceForward.Domain;
|
||||||
|
|
||||||
|
namespace InterfaceForward.Api.Contract;
|
||||||
|
|
||||||
|
[DependsOn(typeof(InterfaceForwardDomainModule))]
|
||||||
|
public class InterfaceForwardApiContractModule:FakeModule
|
||||||
|
{
|
||||||
|
}
|
||||||
@ -14,8 +14,8 @@ public class InterfaceController: ControllerBase
|
|||||||
/// <param name="input"></param>
|
/// <param name="input"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpPost("/SystemInterfacePaginatedList")]
|
[HttpPost("/SystemInterfacePaginatedList")]
|
||||||
public async Task<PagedResultDto<>> SystemInterfacePaginatedListAsync(SystemInterfacePaginatedInputObjectValue input)
|
public async Task SystemInterfacePaginatedListAsync()
|
||||||
{
|
{
|
||||||
return await _interfaceRepository.GetSystemInterfacePaginatedListAsync(input);
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace InterfaceForward.Api.Filters;
|
||||||
|
|
||||||
|
public class CustomerResultAttribute : Attribute
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@ -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<object>();
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
36
src/InterfaceForward.Api/Filters/GlobalExceptionFilter.cs
Normal file
36
src/InterfaceForward.Api/Filters/GlobalExceptionFilter.cs
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/InterfaceForward.Api/Filters/IUnifiedResultHandler.cs
Normal file
11
src/InterfaceForward.Api/Filters/IUnifiedResultHandler.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
|
||||||
|
namespace InterfaceForward.Api.Filters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 在这里定义你的结果格式
|
||||||
|
/// </summary>
|
||||||
|
public interface IUnifiedResultHandler
|
||||||
|
{
|
||||||
|
void HandleActionResult(ResultExecutingContext context);
|
||||||
|
}
|
||||||
19
src/InterfaceForward.Api/Filters/ResultFactory.cs
Normal file
19
src/InterfaceForward.Api/Filters/ResultFactory.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
namespace InterfaceForward.Api.Filters;
|
||||||
|
|
||||||
|
public static class ResultFactory
|
||||||
|
{
|
||||||
|
public static SimpleResult CreateSimpleResult()
|
||||||
|
{
|
||||||
|
return new SimpleResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DataResult<T> CreateDataResult<T>() where T : class
|
||||||
|
{
|
||||||
|
return new DataResult<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ErrorResult CreateErrorResult()
|
||||||
|
{
|
||||||
|
return new ErrorResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/InterfaceForward.Api/Filters/Results.cs
Normal file
42
src/InterfaceForward.Api/Filters/Results.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace InterfaceForward.Api.Filters;
|
||||||
|
|
||||||
|
public class SimpleResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 响应状态码
|
||||||
|
/// </summary>
|
||||||
|
public int? Code { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 响应消息
|
||||||
|
/// </summary>
|
||||||
|
public string? Message { get; set; }
|
||||||
|
|
||||||
|
public SimpleResult(int code = (int)HttpStatusCode.OK)
|
||||||
|
{
|
||||||
|
Code = code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DataResult<T> : SimpleResult where T : class
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 响应数据
|
||||||
|
/// </summary>
|
||||||
|
public T? Data { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ErrorResult : SimpleResult
|
||||||
|
{
|
||||||
|
public ErrorResult()
|
||||||
|
{
|
||||||
|
Code = (int)HttpStatusCode.InternalServerError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异常堆栈
|
||||||
|
/// </summary>
|
||||||
|
public string? StackTrace { get; set; }
|
||||||
|
}
|
||||||
26
src/InterfaceForward.Api/Filters/UnifiedResultFilter.cs
Normal file
26
src/InterfaceForward.Api/Filters/UnifiedResultFilter.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
|
||||||
|
namespace InterfaceForward.Api.Filters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 统一包装action-result
|
||||||
|
/// </summary>
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,9 +1,9 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<Import Project="../../common.props" />
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
@ -21,7 +21,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Fake.AspNetCore" Version="8.0.0-preview.2" />
|
<PackageReference Include="Fake.AspNetCore" Version="8.0.0-preview.3" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,14 @@
|
|||||||
using Fake.AspNetCore;
|
using Fake.AspNetCore;
|
||||||
|
using Fake.Authorization;
|
||||||
using Fake.Modularity;
|
using Fake.Modularity;
|
||||||
using InterfaceForward.Api.Contract;
|
using InterfaceForward.Api.Contract;
|
||||||
|
using InterfaceForward.Api.Filters;
|
||||||
using InterfaceForward.Domain;
|
using InterfaceForward.Domain;
|
||||||
|
|
||||||
namespace InterfaceForward.Api;
|
namespace InterfaceForward.Api;
|
||||||
|
|
||||||
[DependsOn(typeof(FakeAspNetCoreModule))]
|
[DependsOn(typeof(FakeAspNetCoreModule))]
|
||||||
|
[DependsOn(typeof(FakeAuthorizationModule))]
|
||||||
[DependsOn(typeof(InterfaceForwardDomainModule))]
|
[DependsOn(typeof(InterfaceForwardDomainModule))]
|
||||||
[DependsOn(typeof(InterfaceForwardApiContractModule))]
|
[DependsOn(typeof(InterfaceForwardApiContractModule))]
|
||||||
public class InterfaceForwardApiModule : FakeModule
|
public class InterfaceForwardApiModule : FakeModule
|
||||||
@ -16,6 +19,14 @@ public class InterfaceForwardApiModule : FakeModule
|
|||||||
|
|
||||||
// Add services to the container.
|
// Add services to the container.
|
||||||
services.AddProblemDetails();
|
services.AddProblemDetails();
|
||||||
|
|
||||||
|
services.AddControllers(options =>
|
||||||
|
{
|
||||||
|
options.Filters.AddService<GlobalExceptionFilter>();
|
||||||
|
options.Filters.AddService<UnifiedResultFilter>();
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddSwagger();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ConfigureApplication(ApplicationConfigureContext context)
|
public override void ConfigureApplication(ApplicationConfigureContext context)
|
||||||
@ -26,5 +37,28 @@ public class InterfaceForwardApiModule : FakeModule
|
|||||||
app.MapDefaultEndpoints();
|
app.MapDefaultEndpoints();
|
||||||
|
|
||||||
app.MapGet("/", () => "Hello World!");
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
using InterfaceForward.Api;
|
using InterfaceForward.Api;
|
||||||
|
|
||||||
var builder = WebApplication.CreateSlimBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
builder.Services.AddApplication<InterfaceForwardApiModule>();
|
builder.Services.AddApplication<InterfaceForwardApiModule>();
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
using System;
|
using Fake.DomainDrivenDesign.Entities;
|
||||||
using System.Collections.Generic;
|
|
||||||
using Fake.DomainDrivenDesign.Entities;
|
|
||||||
using Fake.DomainDrivenDesign.Entities.Auditing;
|
using Fake.DomainDrivenDesign.Entities.Auditing;
|
||||||
|
|
||||||
namespace InterfaceForward.Domain.Aggregates.InterfaceMapAggregate;
|
namespace InterfaceForward.Domain.Aggregates.InterfaceMapAggregate;
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Fake.DomainDrivenDesign" Version="8.0.0-preview.2"/>
|
<PackageReference Include="Fake.DomainDrivenDesign" Version="8.0.0-preview.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Fake.EntityFrameworkCore" Version="8.0.0-preview.2" />
|
<PackageReference Include="Fake.EntityFrameworkCore" Version="8.0.0-preview.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -13,12 +13,12 @@
|
|||||||
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="8.0.0"/>
|
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="8.0.0"/>
|
||||||
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" Version="8.0.0-preview.1.23557.2"/>
|
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" Version="8.0.0-preview.1.23557.2"/>
|
||||||
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.7.0-alpha.1"/>
|
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.8.0-beta.1" />
|
||||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.7.0-alpha.1"/>
|
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.8.0-beta.1" />
|
||||||
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.6.0-beta.2"/>
|
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.7.1" />
|
||||||
<PackageReference Include="OpenTelemetry.Instrumentation.GrpcNetClient" Version="1.6.0-beta.2"/>
|
<PackageReference Include="OpenTelemetry.Instrumentation.GrpcNetClient" Version="1.7.0-beta.1" />
|
||||||
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.6.0-beta.2"/>
|
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.7.1" />
|
||||||
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.5.1"/>
|
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.7.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
1
tests/InterfaceForward.Domain.Tests/GlobalUsings.cs
Normal file
1
tests/InterfaceForward.Domain.Tests/GlobalUsings.cs
Normal file
@ -0,0 +1 @@
|
|||||||
|
global using Xunit;
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<IsTestProject>true</IsTestProject>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0-preview-24080-01" />
|
||||||
|
<PackageReference Include="xunit" Version="2.7.0" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.7">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\src\InterfaceForward.Domain\InterfaceForward.Domain.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
using Fake.Modularity;
|
||||||
|
|
||||||
|
namespace InterfaceForward.Domain.Tests;
|
||||||
|
|
||||||
|
[DependsOn(
|
||||||
|
typeof(InterfaceForwardDomainModule)
|
||||||
|
)]
|
||||||
|
public class InterfaceForwardDomainTestModule:FakeModule
|
||||||
|
{
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user