18 changed files with 365 additions and 35 deletions
@ -0,0 +1,40 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace LINGYUN.Abp.Wrapper |
|||
{ |
|||
public class AbpWrapperOptions |
|||
{ |
|||
/// <summary>
|
|||
/// 未处理异常代码
|
|||
/// 默认: 500
|
|||
/// </summary>
|
|||
public string CodeWithUnhandled { get; set; } |
|||
|
|||
internal IDictionary<Type, IExceptionWrapHandler> ExceptionHandles { get; } |
|||
|
|||
public AbpWrapperOptions() |
|||
{ |
|||
CodeWithUnhandled = "500"; |
|||
ExceptionHandles = new Dictionary<Type, IExceptionWrapHandler>(); |
|||
} |
|||
|
|||
public void AddHandler<TException>(IExceptionWrapHandler handler) |
|||
where TException : Exception |
|||
{ |
|||
AddHandler(typeof(TException), handler); |
|||
} |
|||
|
|||
public void AddHandler(Type exceptionType, IExceptionWrapHandler handler) |
|||
{ |
|||
ExceptionHandles[exceptionType] = handler; |
|||
} |
|||
|
|||
public IExceptionWrapHandler GetHandler(Type exceptionType) |
|||
{ |
|||
ExceptionHandles.TryGetValue(exceptionType, out IExceptionWrapHandler handler); |
|||
|
|||
return handler; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Options; |
|||
using System; |
|||
using Volo.Abp.ExceptionHandling; |
|||
|
|||
namespace LINGYUN.Abp.Wrapper |
|||
{ |
|||
public class DefaultExceptionWrapHandler : IExceptionWrapHandler |
|||
{ |
|||
public void Wrap(ExceptionWrapContext context) |
|||
{ |
|||
if (context.Exception is IHasErrorCode exceptionWithErrorCode) |
|||
{ |
|||
string errorCode; |
|||
if (!exceptionWithErrorCode.Code.IsNullOrWhiteSpace() && |
|||
exceptionWithErrorCode.Code.Contains(":")) |
|||
{ |
|||
errorCode = exceptionWithErrorCode.Code.Split(':')[1]; |
|||
} |
|||
else |
|||
{ |
|||
errorCode = exceptionWithErrorCode.Code; |
|||
} |
|||
|
|||
context.WithCode(errorCode); |
|||
} |
|||
|
|||
// 没有处理的异常代码统一用配置代码处理
|
|||
if (context.ErrorInfo.Code.IsNullOrWhiteSpace()) |
|||
{ |
|||
var wrapperOptions = context.ServiceProvider.GetRequiredService<IOptions<AbpWrapperOptions>>().Value; |
|||
context.WithCode(wrapperOptions.CodeWithUnhandled); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
using System; |
|||
using Volo.Abp.Http; |
|||
|
|||
namespace LINGYUN.Abp.Wrapper |
|||
{ |
|||
public class ExceptionWrapContext |
|||
{ |
|||
public Exception Exception { get; } |
|||
public IServiceProvider ServiceProvider { get; } |
|||
public RemoteServiceErrorInfo ErrorInfo { get; } |
|||
public ExceptionWrapContext( |
|||
Exception exception, |
|||
RemoteServiceErrorInfo errorInfo, |
|||
IServiceProvider serviceProvider) |
|||
{ |
|||
Exception = exception; |
|||
ErrorInfo = errorInfo; |
|||
ServiceProvider = serviceProvider; |
|||
} |
|||
|
|||
public ExceptionWrapContext WithCode(string code) |
|||
{ |
|||
ErrorInfo.Code = code; |
|||
return this; |
|||
} |
|||
|
|||
public ExceptionWrapContext WithMessage(string message) |
|||
{ |
|||
ErrorInfo.Message = message; |
|||
return this; |
|||
} |
|||
|
|||
public ExceptionWrapContext WithDetails(string details) |
|||
{ |
|||
ErrorInfo.Details = details; |
|||
return this; |
|||
} |
|||
|
|||
public ExceptionWrapContext WithData(string key, object value) |
|||
{ |
|||
ErrorInfo.Data[key] = value; |
|||
return this; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace LINGYUN.Abp.Wrapper |
|||
{ |
|||
public class ExceptionWrapHandlerFactory : IExceptionWrapHandlerFactory, ITransientDependency |
|||
{ |
|||
private readonly AbpWrapperOptions _options; |
|||
|
|||
public ExceptionWrapHandlerFactory( |
|||
IOptions<AbpWrapperOptions> options) |
|||
{ |
|||
_options = options.Value; |
|||
} |
|||
|
|||
public IExceptionWrapHandler CreateFor(ExceptionWrapContext context) |
|||
{ |
|||
var exceptionType = context.Exception.GetType(); |
|||
var handler = _options.GetHandler(exceptionType); |
|||
if (handler == null) |
|||
{ |
|||
handler = new DefaultExceptionWrapHandler(); |
|||
_options.AddHandler(exceptionType, handler); |
|||
return handler; |
|||
} |
|||
|
|||
return handler; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
namespace LINGYUN.Abp.Wrapper |
|||
{ |
|||
public interface IExceptionWrapHandler |
|||
{ |
|||
void Wrap(ExceptionWrapContext context); |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using System; |
|||
|
|||
namespace LINGYUN.Abp.Wrapper |
|||
{ |
|||
public interface IExceptionWrapHandlerFactory |
|||
{ |
|||
IExceptionWrapHandler CreateFor(ExceptionWrapContext context); |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
using Microsoft.AspNetCore.Http; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace LINGYUN.Abp.AspNetCore.Mvc.Results |
|||
{ |
|||
public class ThrowMiddleware : IMiddleware, ITransientDependency |
|||
{ |
|||
public async Task InvokeAsync(HttpContext context, RequestDelegate next) |
|||
{ |
|||
if (context.Request.Path.ToString().StartsWith("/use-throw-middleware")) |
|||
{ |
|||
throw new BusinessException("Test:1001"); |
|||
} |
|||
await next(context); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net5.0</TargetFramework> |
|||
<RootNamespace /> |
|||
<IsPackable>false</IsPackable> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\modules\common\LINGYUN.Abp.Wrapper\LINGYUN.Abp.Wrapper.csproj" /> |
|||
<ProjectReference Include="..\LINGYUN.Abp.TestBase\LINGYUN.Abp.TestsBase.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,8 @@ |
|||
using LINGYUN.Abp.Tests; |
|||
|
|||
namespace LINGYUN.Abp.Wrapper |
|||
{ |
|||
public abstract class AbpWrapperTestsBase: AbpTestsBase<AbpWrapperTestsModule> |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
using LINGYUN.Abp.Tests; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.Wrapper |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpWrapperModule), |
|||
typeof(AbpTestsBaseModule))] |
|||
public class AbpWrapperTestsModule: AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<AbpWrapperOptions>(options => |
|||
{ |
|||
options.AddHandler<FakeException>(new FakeExceptionWrapHandler()); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
using Volo.Abp; |
|||
|
|||
namespace LINGYUN.Abp.Wrapper |
|||
{ |
|||
public class FakeException: AbpException |
|||
{ |
|||
public FakeException() |
|||
{ |
|||
} |
|||
|
|||
public FakeException(string message) |
|||
: base(message) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
namespace LINGYUN.Abp.Wrapper |
|||
{ |
|||
public class FakeExceptionWrapHandler : IExceptionWrapHandler |
|||
{ |
|||
public void Wrap(ExceptionWrapContext context) |
|||
{ |
|||
context.WithCode("1001") |
|||
.WithMessage("自定义异常处理消息") |
|||
.WithDetails("自定义异常处理消息明细"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,75 @@ |
|||
using Shouldly; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Http; |
|||
using Xunit; |
|||
|
|||
namespace LINGYUN.Abp.Wrapper.Tests |
|||
{ |
|||
public class FakeExceptionWrapHandler_Tests: AbpWrapperTestsBase |
|||
{ |
|||
private readonly IExceptionWrapHandlerFactory _exceptionWrapHandlerFactory; |
|||
|
|||
public FakeExceptionWrapHandler_Tests() |
|||
{ |
|||
_exceptionWrapHandlerFactory = GetRequiredService<IExceptionWrapHandlerFactory>(); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Return_Wraped_Result_With_Fake_Exception() |
|||
{ |
|||
var exception = new FakeException(); |
|||
var exceptionWrapContext = new ExceptionWrapContext( |
|||
exception, |
|||
new RemoteServiceErrorInfo(), |
|||
ServiceProvider); |
|||
|
|||
var handler = _exceptionWrapHandlerFactory.CreateFor(exceptionWrapContext); |
|||
handler.Wrap(exceptionWrapContext); |
|||
|
|||
exceptionWrapContext.ErrorInfo.Code.ShouldBe("1001"); |
|||
exceptionWrapContext.ErrorInfo.Message.ShouldBe("自定义异常处理消息"); |
|||
exceptionWrapContext.ErrorInfo.Details.ShouldBe("自定义异常处理消息明细"); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Return_Wraped_Result_With_Default_Exception() |
|||
{ |
|||
var exception = new AbpException(); |
|||
var errorInfo = new RemoteServiceErrorInfo( |
|||
"默认异常处理消息", |
|||
"默认异常处理消息明细", |
|||
"1000"); |
|||
var exceptionWrapContext = new ExceptionWrapContext( |
|||
exception, |
|||
errorInfo, |
|||
ServiceProvider); |
|||
|
|||
var handler = _exceptionWrapHandlerFactory.CreateFor(exceptionWrapContext); |
|||
handler.Wrap(exceptionWrapContext); |
|||
|
|||
exceptionWrapContext.ErrorInfo.Code.ShouldBe("1000"); |
|||
exceptionWrapContext.ErrorInfo.Message.ShouldBe("默认异常处理消息"); |
|||
exceptionWrapContext.ErrorInfo.Details.ShouldBe("默认异常处理消息明细"); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Return_Wraped_Result_Code_500_With_Unhandled_Exception() |
|||
{ |
|||
var exception = new AbpException(); |
|||
var errorInfo = new RemoteServiceErrorInfo( |
|||
"默认异常处理消息", |
|||
"默认异常处理消息明细"); |
|||
var exceptionWrapContext = new ExceptionWrapContext( |
|||
exception, |
|||
errorInfo, |
|||
ServiceProvider); |
|||
|
|||
var handler = _exceptionWrapHandlerFactory.CreateFor(exceptionWrapContext); |
|||
handler.Wrap(exceptionWrapContext); |
|||
|
|||
exceptionWrapContext.ErrorInfo.Code.ShouldBe("500"); |
|||
exceptionWrapContext.ErrorInfo.Message.ShouldBe("默认异常处理消息"); |
|||
exceptionWrapContext.ErrorInfo.Details.ShouldBe("默认异常处理消息明细"); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue