Browse Source

Merge pull request #408 from colinin/4.4.2

feat(wrapper): 增加自定义异常处理器
pull/426/head
yx lin 4 years ago
committed by GitHub
parent
commit
44e4277c8c
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      aspnet-core/LINGYUN.MicroService.Common.sln
  2. 2
      aspnet-core/modules/common/LINGYUN.Abp.Wrapper/LINGYUN.Abp.Wrapper.csproj
  3. 4
      aspnet-core/modules/common/LINGYUN.Abp.Wrapper/LINGYUN/Abp/Wrapper/AbpWrapperModule.cs
  4. 40
      aspnet-core/modules/common/LINGYUN.Abp.Wrapper/LINGYUN/Abp/Wrapper/AbpWrapperOptions.cs
  5. 36
      aspnet-core/modules/common/LINGYUN.Abp.Wrapper/LINGYUN/Abp/Wrapper/DefaultExceptionWrapHandler.cs
  6. 45
      aspnet-core/modules/common/LINGYUN.Abp.Wrapper/LINGYUN/Abp/Wrapper/ExceptionWrapContext.cs
  7. 30
      aspnet-core/modules/common/LINGYUN.Abp.Wrapper/LINGYUN/Abp/Wrapper/ExceptionWrapHandlerFactory.cs
  8. 7
      aspnet-core/modules/common/LINGYUN.Abp.Wrapper/LINGYUN/Abp/Wrapper/IExceptionWrapHandler.cs
  9. 9
      aspnet-core/modules/common/LINGYUN.Abp.Wrapper/LINGYUN/Abp/Wrapper/IExceptionWrapHandlerFactory.cs
  10. 28
      aspnet-core/modules/mvc/LINGYUN.Abp.AspNetCore.Mvc.Wrapper/LINGYUN/Abp/AspNetCore/Mvc/Wrapper/ExceptionHandling/AbpExceptionPageWrapResultFilter.cs
  11. 25
      aspnet-core/modules/mvc/LINGYUN.Abp.AspNetCore.Mvc.Wrapper/LINGYUN/Abp/AspNetCore/Mvc/Wrapper/ExceptionHandling/AbpExceptionWrapResultFilter.cs
  12. 19
      aspnet-core/tests/LINGYUN.Abp.AspNetCore.Mvc.Tests/LINGYUN/Abp/AspNetCore/Mvc/Results/ThrowMiddleware.cs
  13. 18
      aspnet-core/tests/LINGYUN.Abp.Wrapper.Tests/LINGYUN.Abp.Wrapper.Tests.csproj
  14. 8
      aspnet-core/tests/LINGYUN.Abp.Wrapper.Tests/LINGYUN/Abp/Wrapper/AbpWrapperTestsBase.cs
  15. 19
      aspnet-core/tests/LINGYUN.Abp.Wrapper.Tests/LINGYUN/Abp/Wrapper/AbpWrapperTestsModule.cs
  16. 16
      aspnet-core/tests/LINGYUN.Abp.Wrapper.Tests/LINGYUN/Abp/Wrapper/FakeException.cs
  17. 12
      aspnet-core/tests/LINGYUN.Abp.Wrapper.Tests/LINGYUN/Abp/Wrapper/FakeExceptionWrapHandler.cs
  18. 75
      aspnet-core/tests/LINGYUN.Abp.Wrapper.Tests/LINGYUN/Abp/Wrapper/FakeExceptionWrapHandler_Tests.cs

7
aspnet-core/LINGYUN.MicroService.Common.sln

@ -204,6 +204,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.AspNetCore.Test
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.AspNetCore.Mvc.Tests", "tests\LINGYUN.Abp.AspNetCore.Mvc.Tests\LINGYUN.Abp.AspNetCore.Mvc.Tests.csproj", "{AE5E6DE8-FC02-4633-BA49-C4B8ABADB502}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Wrapper.Tests", "tests\LINGYUN.Abp.Wrapper.Tests\LINGYUN.Abp.Wrapper.Tests.csproj", "{31AED9ED-29BD-4F2F-8D3A-F00CBB9FC73C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -530,6 +532,10 @@ Global
{AE5E6DE8-FC02-4633-BA49-C4B8ABADB502}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AE5E6DE8-FC02-4633-BA49-C4B8ABADB502}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AE5E6DE8-FC02-4633-BA49-C4B8ABADB502}.Release|Any CPU.Build.0 = Release|Any CPU
{31AED9ED-29BD-4F2F-8D3A-F00CBB9FC73C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{31AED9ED-29BD-4F2F-8D3A-F00CBB9FC73C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{31AED9ED-29BD-4F2F-8D3A-F00CBB9FC73C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{31AED9ED-29BD-4F2F-8D3A-F00CBB9FC73C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -632,6 +638,7 @@ Global
{D72748AF-2CC8-4B5B-9710-ECDE5D812D7F} = {F55B987D-1DFF-4EB0-9949-8A7136A7B689}
{BD4165DB-F8A4-4715-A05A-CC08F6A18D67} = {B86C21A4-73B7-471E-B73A-B4B905EC9435}
{AE5E6DE8-FC02-4633-BA49-C4B8ABADB502} = {B86C21A4-73B7-471E-B73A-B4B905EC9435}
{31AED9ED-29BD-4F2F-8D3A-F00CBB9FC73C} = {B86C21A4-73B7-471E-B73A-B4B905EC9435}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {06C707C6-02C0-411A-AD3B-2D0E13787CB8}

2
aspnet-core/modules/common/LINGYUN.Abp.Wrapper/LINGYUN.Abp.Wrapper.csproj

@ -8,7 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Core" Version="4.4.0" />
<PackageReference Include="Volo.Abp.ExceptionHandling" Version="4.4.0" />
</ItemGroup>
</Project>

4
aspnet-core/modules/common/LINGYUN.Abp.Wrapper/LINGYUN/Abp/Wrapper/AbpWrapperModule.cs

@ -1,7 +1,9 @@
using Volo.Abp.Modularity;
using Volo.Abp.ExceptionHandling;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.Wrapper
{
[DependsOn(typeof(AbpExceptionHandlingModule))]
public class AbpWrapperModule: AbpModule
{

40
aspnet-core/modules/common/LINGYUN.Abp.Wrapper/LINGYUN/Abp/Wrapper/AbpWrapperOptions.cs

@ -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;
}
}
}

36
aspnet-core/modules/common/LINGYUN.Abp.Wrapper/LINGYUN/Abp/Wrapper/DefaultExceptionWrapHandler.cs

@ -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);
}
}
}
}

45
aspnet-core/modules/common/LINGYUN.Abp.Wrapper/LINGYUN/Abp/Wrapper/ExceptionWrapContext.cs

@ -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;
}
}
}

30
aspnet-core/modules/common/LINGYUN.Abp.Wrapper/LINGYUN/Abp/Wrapper/ExceptionWrapHandlerFactory.cs

@ -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;
}
}
}

7
aspnet-core/modules/common/LINGYUN.Abp.Wrapper/LINGYUN/Abp/Wrapper/IExceptionWrapHandler.cs

@ -0,0 +1,7 @@
namespace LINGYUN.Abp.Wrapper
{
public interface IExceptionWrapHandler
{
void Wrap(ExceptionWrapContext context);
}
}

9
aspnet-core/modules/common/LINGYUN.Abp.Wrapper/LINGYUN/Abp/Wrapper/IExceptionWrapHandlerFactory.cs

@ -0,0 +1,9 @@
using System;
namespace LINGYUN.Abp.Wrapper
{
public interface IExceptionWrapHandlerFactory
{
IExceptionWrapHandler CreateFor(ExceptionWrapContext context);
}
}

28
aspnet-core/modules/mvc/LINGYUN.Abp.AspNetCore.Mvc.Wrapper/LINGYUN/Abp/AspNetCore/Mvc/Wrapper/ExceptionHandling/AbpExceptionPageWrapResultFilter.cs

@ -41,8 +41,6 @@ namespace LINGYUN.Abp.AspNetCore.Mvc.Wrapper.ExceptionHandling
remoteServiceErrorInfoBuilder.AppendLine($"---------- {nameof(RemoteServiceErrorInfo)} ----------");
remoteServiceErrorInfoBuilder.AppendLine(context.GetRequiredService<IJsonSerializer>().Serialize(remoteServiceErrorInfo, indented: true));
context.HttpContext.Response.Headers.Add(AbpHttpWrapConsts.AbpWrapResult, "true");
var logger = context.GetService<ILogger<AbpExceptionPageWrapResultFilter>>(NullLogger<AbpExceptionPageWrapResultFilter>.Instance);
logger.LogWithLevel(logLevel, remoteServiceErrorInfoBuilder.ToString());
@ -50,21 +48,17 @@ namespace LINGYUN.Abp.AspNetCore.Mvc.Wrapper.ExceptionHandling
await context.GetRequiredService<IExceptionNotifier>().NotifyAsync(new ExceptionNotificationContext(context.Exception));
// Warp Error Response
string errorCode = remoteServiceErrorInfo.Code;
if (context.Exception is IHasErrorCode exceptionWithErrorCode)
{
if (!exceptionWithErrorCode.Code.IsNullOrWhiteSpace() &&
exceptionWithErrorCode.Code.Contains(":"))
{
errorCode = exceptionWithErrorCode.Code.Split(':')[1];
}
else
{
errorCode = exceptionWithErrorCode.Code;
}
}
context.Result = new ObjectResult(new WrapResult(errorCode, remoteServiceErrorInfo.Message, remoteServiceErrorInfo.Details));
var exceptionWrapHandler = context.GetRequiredService<IExceptionWrapHandlerFactory>();
var exceptionWrapContext = new ExceptionWrapContext(context.Exception, remoteServiceErrorInfo, context.HttpContext.RequestServices);
exceptionWrapHandler.CreateFor(exceptionWrapContext).Wrap(exceptionWrapContext);
var wrapResult = new WrapResult(
exceptionWrapContext.ErrorInfo.Code,
exceptionWrapContext.ErrorInfo.Message,
exceptionWrapContext.ErrorInfo.Details);
context.Result = new ObjectResult(wrapResult);
context.HttpContext.Response.Headers.Add(AbpHttpWrapConsts.AbpWrapResult, "true");
context.HttpContext.Response.StatusCode = (int)wrapResultOptions.HttpStatusCode;
context.Exception = null; //Handled!
}

25
aspnet-core/modules/mvc/LINGYUN.Abp.AspNetCore.Mvc.Wrapper/LINGYUN/Abp/AspNetCore/Mvc/Wrapper/ExceptionHandling/AbpExceptionWrapResultFilter.cs

@ -51,25 +51,18 @@ namespace LINGYUN.Abp.AspNetCore.Mvc.Wrapper.ExceptionHandling
await context.GetRequiredService<IExceptionNotifier>().NotifyAsync(new ExceptionNotificationContext(context.Exception));
var exceptionWrapHandler = context.GetRequiredService<IExceptionWrapHandlerFactory>();
var exceptionWrapContext = new ExceptionWrapContext(context.Exception, remoteServiceErrorInfo, context.HttpContext.RequestServices);
exceptionWrapHandler.CreateFor(exceptionWrapContext).Wrap(exceptionWrapContext);
var wrapResult = new WrapResult(
exceptionWrapContext.ErrorInfo.Code,
exceptionWrapContext.ErrorInfo.Message,
exceptionWrapContext.ErrorInfo.Details);
context.Result = new ObjectResult(wrapResult);
context.HttpContext.Response.Headers.Add(AbpHttpWrapConsts.AbpWrapResult, "true");
context.HttpContext.Response.StatusCode = (int)wrapResultOptions.HttpStatusCode;
// Warp Error Response
string errorCode = remoteServiceErrorInfo.Code;
if (context.Exception is IHasErrorCode exceptionWithErrorCode)
{
if (!exceptionWithErrorCode.Code.IsNullOrWhiteSpace() &&
exceptionWithErrorCode.Code.Contains(":"))
{
errorCode = exceptionWithErrorCode.Code.Split(':')[1];
}
else
{
errorCode = exceptionWithErrorCode.Code;
}
}
context.Result = new ObjectResult(new WrapResult(errorCode, remoteServiceErrorInfo.Message, remoteServiceErrorInfo.Details));
context.Exception = null; //Handled!
}

19
aspnet-core/tests/LINGYUN.Abp.AspNetCore.Mvc.Tests/LINGYUN/Abp/AspNetCore/Mvc/Results/ThrowMiddleware.cs

@ -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);
}
}
}

18
aspnet-core/tests/LINGYUN.Abp.Wrapper.Tests/LINGYUN.Abp.Wrapper.Tests.csproj

@ -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>

8
aspnet-core/tests/LINGYUN.Abp.Wrapper.Tests/LINGYUN/Abp/Wrapper/AbpWrapperTestsBase.cs

@ -0,0 +1,8 @@
using LINGYUN.Abp.Tests;
namespace LINGYUN.Abp.Wrapper
{
public abstract class AbpWrapperTestsBase: AbpTestsBase<AbpWrapperTestsModule>
{
}
}

19
aspnet-core/tests/LINGYUN.Abp.Wrapper.Tests/LINGYUN/Abp/Wrapper/AbpWrapperTestsModule.cs

@ -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());
});
}
}
}

16
aspnet-core/tests/LINGYUN.Abp.Wrapper.Tests/LINGYUN/Abp/Wrapper/FakeException.cs

@ -0,0 +1,16 @@
using Volo.Abp;
namespace LINGYUN.Abp.Wrapper
{
public class FakeException: AbpException
{
public FakeException()
{
}
public FakeException(string message)
: base(message)
{
}
}
}

12
aspnet-core/tests/LINGYUN.Abp.Wrapper.Tests/LINGYUN/Abp/Wrapper/FakeExceptionWrapHandler.cs

@ -0,0 +1,12 @@
namespace LINGYUN.Abp.Wrapper
{
public class FakeExceptionWrapHandler : IExceptionWrapHandler
{
public void Wrap(ExceptionWrapContext context)
{
context.WithCode("1001")
.WithMessage("自定义异常处理消息")
.WithDetails("自定义异常处理消息明细");
}
}
}

75
aspnet-core/tests/LINGYUN.Abp.Wrapper.Tests/LINGYUN/Abp/Wrapper/FakeExceptionWrapHandler_Tests.cs

@ -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…
Cancel
Save