提问人:Tiến Đạt Trương 提问时间:7/26/2023 最后编辑:Tiến Đạt Trương 更新时间:7/26/2023 访问量:58
在 Web API 中处理异常的灵活方法
Flexible way to handle exception in Web API
问:
我目前正在使用 .NET 6 制作 Web API。 下面的代码是我的异常处理程序类:
public class ExceptionsMiddleware
{
private readonly RequestDelegate requestDelegate;
private readonly ILogger<ExceptionsMiddleware> logger;
public ExceptionsMiddleware(RequestDelegate requestDelegate, ILogger<ExceptionsMiddleware> logger)
{
this.requestDelegate = requestDelegate;
this.logger = logger;
}
public async Task Invoke(HttpContext context)
{
try
{
await requestDelegate(context);
}
catch (Exception ex)
{
var response = context.Response;
response.ContentType = "application/json";
var errorMessage = ex.Message;
logger.LogError(ex, "Error occurred");
switch (ex)
{
case ApplicationException:
response.StatusCode = StatusCodes.Status400BadRequest;
break;
case KeyNotFoundException:
case ArgumentException:
case NullReferenceException:
response.StatusCode = StatusCodes.Status404NotFound;
break;
default:
response.StatusCode = StatusCodes.Status500InternalServerError;
errorMessage = "Error occurred";
break;
}
var result = System.Text.Json.JsonSerializer.Serialize(new { Message = errorMessage });
await response.WriteAsync(result);
}
}
}
在 Program.cs 类中:
app.UseMiddleware<ExceptionsMiddleware>();
这工作正常。但是,如果我想创建一个新的异常类型,我必须再次修改类,但是 SOLID 中的“O”原则不允许我这样做。ExceptionsMiddleware
因此,有没有其他解决方案? 先谢谢你。
答:
0赞
RJA
7/26/2023
#1
另一种解决方案是更早地处理预期的异常。控制者可以负责创建适当的响应(、、、等)。基于操作的结果,而不是在中间件中执行所有这些操作。然后,您可以使用异常处理中间件来处理意外异常。这是一个设计选择。Ok()
NotFound()
BadRequest()
0赞
EddieDemon
7/26/2023
#2
您可以做的是将 Exceptions 处理程序使用的 DI 容器中添加一个额外的服务。异常处理程序会将异常转发到子处理程序,子处理程序可以从泛型基添加。这就是我想出的。希望对你有所帮助!
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System.Text;
namespace Playground7;
internal static partial class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder();
// Add the handlers to the container.
// Made them transient since we expect nothing to happen, lowers memory load in the long run
// but makes the handling come slower.
// Please note how we add it as generic type "ExceptionHandler"
builder.Services.AddTransient<ExceptionHandler, InvalidCastExceptionHandler>();
builder.Services.AddTransient<ExceptionHandler, InvalidDataExceptionHandler>();
var app = builder.Build();
// Add the middleware to the pipeline.
app.UseMiddleware<ExceptionsMiddleware>();
// Throw the exception!
app.MapGet("/", () => { throw new InvalidCastException(); });
app.Run();
}
}
// Closed module
internal class ExceptionsMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<ExceptionsMiddleware> _logger;
private readonly IServiceProvider _services;
public ExceptionsMiddleware(RequestDelegate requestDelegate, ILogger<ExceptionsMiddleware> logger, IServiceProvider services)
{
_next = requestDelegate;
_logger = logger;
_services = services;
}
public async Task Invoke(HttpContext context)
{
try
{
// Await the rest of the pipeline...
await _next(context).ConfigureAwait(false);
}
catch (Exception ex)
{
// Create the type which we expect the handler to be.
// and add some generic sweetness.
var targetHandlerType = typeof(ExceptionHandler<>)
.MakeGenericType(ex.GetType());
// Search for that specific handler with our sweetened type.
var handler = _services
.GetServices<ExceptionHandler>() // See how we first get our base-base type.
.Where(h => targetHandlerType.IsAssignableFrom(h.GetType()))
.FirstOrDefault();
// No handler found, you could do something generic here...?
if (handler is null)
return;
// Open using external handlers.
handler.HandleBase(context, ex);
}
}
}
// Base class to add to the DI container.
internal abstract class ExceptionHandler
{
public abstract void HandleBase(HttpContext context, Exception exception);
}
// Base class for the handlers.
internal abstract class ExceptionHandler<TException> : ExceptionHandler where TException : Exception
{
protected abstract void Handle(HttpContext context, TException exception);
public override void HandleBase(HttpContext context, Exception exception)
{
Handle(context, (TException)exception);
}
}
// Handler for an InvalidCastException.
internal sealed class InvalidCastExceptionHandler : ExceptionHandler<InvalidCastException>
{
protected override void Handle(HttpContext context, InvalidCastException exception)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = 500;
context.Response.Body.Write(Encoding.UTF8.GetBytes($"{{\"error\":\"{exception.Message}\"}}"));
}
}
// Handler for a InvalidDataException.
internal sealed class InvalidDataExceptionHandler : ExceptionHandler<InvalidDataException>
{
protected override void Handle(HttpContext context, InvalidDataException exception)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = 500;
context.Response.Body.Write(Encoding.UTF8.GetBytes($"{{\"error\":\"{exception.Message}\"}}"));
}
}
internal sealed class ExceptionHandler2 : ExceptionHandler<Exception>
{
protected override void Handle(HttpContext context, Exception exception)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = 500;
context.Response.Body.Write(Encoding.UTF8.GetBytes($"{{\"error\":\"{exception.Message}\"}}"));
}
}
编辑:原始不允许处理。System.Exception
评论