Skip to content

Commit

Permalink
支持不同的path提供不同的异常处理配置
Browse files Browse the repository at this point in the history
  • Loading branch information
witskeeper committed Dec 31, 2023
1 parent a706a8d commit c9deee5
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 13 deletions.
2 changes: 1 addition & 1 deletion eng/versions.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<VersionPrefix>1.0.3</VersionPrefix>
<VersionPrefix>1.0.4</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
27 changes: 24 additions & 3 deletions src/AspNetCore/ApplicationBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,42 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace NetCorePal.Extensions.AspNetCore
{
public static class ApplicationBuilderExtensions
{
public static IApplicationBuilder UseKnownExceptionHandler(this IApplicationBuilder app, Action<KnownExceptionHandleMiddlewareOptions>? configOptions = null)
public static IApplicationBuilder UseKnownExceptionHandler(this IApplicationBuilder app,
Action<KnownExceptionHandleMiddlewareOptions>? configOptions = null)
{
KnownExceptionHandleMiddlewareOptions options = new();
configOptions?.Invoke(options);

app.UseExceptionHandler(builder =>
{
builder.UseMiddleware<KnownExceptionHandleMiddleware>(options, app.ApplicationServices.GetRequiredService<ILogger<KnownExceptionHandleMiddleware>>());
builder.UseMiddleware<KnownExceptionHandleMiddleware>(options,
app.ApplicationServices.GetRequiredService<ILogger<KnownExceptionHandleMiddleware>>());
});
return app;
}


/// <summary>
/// 支持为不同的请求定义不同的配置
/// </summary>
/// <param name="app"></param>
/// <param name="optionFactory"></param>
/// <returns></returns>
public static IApplicationBuilder UseKnownExceptionHandler(this IApplicationBuilder app,
Func<HttpContext, KnownExceptionHandleMiddlewareOptions> optionFactory)
{
app.UseExceptionHandler(builder =>
{
builder.UseMiddleware<KnownExceptionHandleMiddleware>(optionFactory,
app.ApplicationServices.GetRequiredService<ILogger<KnownExceptionHandleMiddleware>>());
});
return app;
}
}
}
}
24 changes: 18 additions & 6 deletions src/AspNetCore/KnownExceptionHandleMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ namespace NetCorePal.Extensions.AspNetCore
{
public class KnownExceptionHandleMiddleware
{
private readonly KnownExceptionHandleMiddlewareOptions _options;
private readonly KnownExceptionHandleMiddlewareOptions? _options;
private readonly ILogger _logger;
private readonly Func<HttpContext, KnownExceptionHandleMiddlewareOptions> _optionFactory;

#pragma warning disable IDE0060 // 删除未使用的参数
public KnownExceptionHandleMiddleware(RequestDelegate next, KnownExceptionHandleMiddlewareOptions options,
Expand All @@ -19,24 +20,35 @@ public KnownExceptionHandleMiddleware(RequestDelegate next, KnownExceptionHandle
{
_options = options;
_logger = logger;
_optionFactory = _ => options;
}

public KnownExceptionHandleMiddleware(RequestDelegate next,
Func<HttpContext, KnownExceptionHandleMiddlewareOptions> optionFactory,
ILogger<KnownExceptionHandleMiddleware> logger)
{
_optionFactory = optionFactory;
_logger = logger;
}


public async Task InvokeAsync(HttpContext context)
{
var options = _optionFactory(context);
var exceptionHandlerFeature = context.Features.Get<IExceptionHandlerFeature>()!;
ResponseData responseData;
if (exceptionHandlerFeature.Error is IKnownException ex)
{
context.Response.StatusCode = (int)_options.KnownExceptionStatusCode;
context.Response.StatusCode = (int)options.KnownExceptionStatusCode;
responseData = new ResponseData(success: false, message: ex.Message, code: ex.ErrorCode,
errorData: ex.ErrorData);
}
else
{
_logger.LogError(exceptionHandlerFeature.Error, message: "{message}", _options.UnknownExceptionMessage);
context.Response.StatusCode = (int)_options.UnknownExceptionStatusCode;
responseData = new ResponseData(success: false, message: _options.UnknownExceptionMessage,
code: _options.UnknownExceptionCode);
_logger.LogError(exceptionHandlerFeature.Error, message: "{message}", options.UnknownExceptionMessage);
context.Response.StatusCode = (int)options.UnknownExceptionStatusCode;
responseData = new ResponseData(success: false, message: options.UnknownExceptionMessage,
code: options.UnknownExceptionCode);
}

await context.Response.WriteAsJsonAsync(responseData, context.RequestAborted);
Expand Down
46 changes: 45 additions & 1 deletion test/NetCorePal.Web.UnitTests/ProgramTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public async Task SagaTest()
public async Task KnownExceptionTest()
{
var client = factory.CreateClient();
var response = client.GetAsync("/knownexception").Result;
var response = await client.GetAsync("/knownexception");
Assert.True(response.IsSuccessStatusCode);
var data = await response.Content.ReadFromJsonAsync<ResponseData>();
Assert.NotNull(data);
Expand All @@ -69,6 +69,50 @@ public async Task UnknownExceptionTest()
Assert.False(data.Success);
}


[Fact]
public async Task ServiceKnownExceptionTest()
{
var client = factory.CreateClient();
var response = await client.GetAsync("/service/knownexception");
Assert.True(!response.IsSuccessStatusCode);
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
var data = await response.Content.ReadFromJsonAsync<ResponseData>();
Assert.NotNull(data);
Assert.Equal("test known exception message", data.Message);
Assert.Equal(33, data.Code);
Assert.False(data.Success);
}


[Fact]
public async Task ServiceUnknownExceptionTest()
{
var client = factory.CreateClient();
var response = await client.GetAsync("/service/unknownexception");
Assert.True(!response.IsSuccessStatusCode);
Assert.Equal(HttpStatusCode.BadGateway, response.StatusCode);
var data = await response.Content.ReadFromJsonAsync<ResponseData>();
Assert.NotNull(data);
Assert.Equal("未知错误", data.Message);
Assert.Equal(99999, data.Code);
Assert.False(data.Success);
}

// [Fact]
// public async Task BadRequestTest()
// {
// var client = factory.CreateClient();
// var response = await client.GetAsync("/badrequest/{abc}");
// Assert.True(!response.IsSuccessStatusCode);
// Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
// var data = await response.Content.ReadFromJsonAsync<ResponseData>();
// Assert.NotNull(data);
// Assert.Equal("未知错误", data.Message);
// Assert.Equal(99999, data.Code);
// Assert.False(data.Success);
// }

[Fact]
public async Task PostTest()
{
Expand Down
26 changes: 25 additions & 1 deletion test/NetCorePal.Web/Controllers/OrderController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using DotNetCore.CAP;
using System.ComponentModel.DataAnnotations;
using DotNetCore.CAP;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using NetCorePal.Extensions.DistributedTransactions.Sagas;
Expand Down Expand Up @@ -71,6 +72,29 @@ public Task<ResponseData<long>> UnknownException()
{
throw new Exception("系统异常");
}


[HttpGet]
[Route("/service/knownexception")]
public Task<ResponseData<long>> ServiceKnownException()
{
throw new KnownException("test known exception message", 33);
}


[HttpGet]
[Route("/service/unknownexception")]
public Task<ResponseData<long>> ServiceUnknownException()
{
throw new Exception("系统异常");
}

[HttpGet]
[Route("/badrequest/{id}")]
public Task<ResponseData<long>> BadRequest(long id)
{
throw new Exception("系统异常");
}

}
}
16 changes: 15 additions & 1 deletion test/NetCorePal.Web/Program.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Net;
using FluentValidation.AspNetCore;
using FluentValidation;
using NetCorePal.Extensions.Domain.Json;
Expand Down Expand Up @@ -84,7 +85,20 @@

var app = builder.Build();
app.UseContext();
app.UseKnownExceptionHandler();
//app.UseKnownExceptionHandler();
app.UseKnownExceptionHandler(context =>
{
if (context.Request.Path.StartsWithSegments("/service"))
{
return new KnownExceptionHandleMiddlewareOptions()
{
KnownExceptionStatusCode = HttpStatusCode.BadRequest,
UnknownExceptionStatusCode = HttpStatusCode.BadGateway
};
}
return new KnownExceptionHandleMiddlewareOptions();
}
);
app.UseRouting();
app.MapControllers();
app.MapHealthChecks("/health");
Expand Down

0 comments on commit c9deee5

Please sign in to comment.