ASP.NET Core异常处理:全局错误处理策略
引言
在Web应用开发中,异常处理是保证系统稳定性和用户体验的关键环节。ASP.NET Core提供了强大的异常处理机制,能够帮助开发者构建健壮的应用程序。本文将深入探讨ASP.NET Core的全局异常处理策略,从基础配置到高级定制,为您提供完整的解决方案。
异常处理的重要性
异常处理不仅仅是捕获错误,更是:
- 用户体验保障:向用户展示友好的错误信息
- 系统稳定性:防止未处理异常导致应用崩溃
- 安全考虑:避免敏感信息泄露
- 调试辅助:提供详细的错误日志和诊断信息
ASP.NET Core异常处理中间件
1. 开发者异常页面(Developer Exception Page)
在开发环境中,ASP.NET Core提供了详细的错误信息展示:
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
2. 异常处理中间件(Exception Handler)
生产环境应该使用异常处理中间件:
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
全局异常处理配置
基本配置示例
var builder = WebApplication.CreateBuilder(args);
// 添加异常处理服务
builder.Services.AddExceptionHandler(options =>
{
options.ExceptionHandlingPath = "/Error";
options.AllowStatusCode404Response = true;
});
var app = builder.Build();
// 配置异常处理中间件
app.UseExceptionHandler("/Error");
高级配置选项
app.UseExceptionHandler(new ExceptionHandlerOptions
{
ExceptionHandlingPath = "/api/error",
ExceptionHandler = async context =>
{
var exceptionHandler = context.Features.Get<IExceptionHandlerPathFeature>();
var exception = exceptionHandler?.Error;
// 自定义异常处理逻辑
await HandleExceptionAsync(context, exception);
}
});
自定义异常处理策略
1. 创建自定义异常处理器
public class CustomExceptionHandler : IExceptionHandler
{
private readonly ILogger<CustomExceptionHandler> _logger;
public CustomExceptionHandler(ILogger<CustomExceptionHandler> logger)
{
_logger = logger;
}
public async ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
CancellationToken cancellationToken)
{
_logger.LogError(exception, "An unexpected error occurred");
var problemDetails = new ProblemDetails
{
Status = StatusCodes.Status500InternalServerError,
Title = "Server error",
Detail = exception.Message,
Instance = httpContext.Request.Path
};
httpContext.Response.StatusCode = problemDetails.Status.Value;
await httpContext.Response.WriteAsJsonAsync(problemDetails, cancellationToken);
return true;
}
}
2. 注册自定义处理器
builder.Services.AddExceptionHandler<CustomExceptionHandler>();
异常处理流程图
异常分类处理策略
1. 业务异常处理
public class BusinessExceptionHandler : IExceptionHandler
{
public ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
CancellationToken cancellationToken)
{
if (exception is BusinessException businessException)
{
httpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
var response = new
{
Code = businessException.ErrorCode,
Message = businessException.Message,
Details = businessException.Details
};
return new ValueTask<bool>(httpContext.Response.WriteAsJsonAsync(response));
}
return new ValueTask<bool>(false);
}
}
2. 验证异常处理
public class ValidationExceptionHandler : IExceptionHandler
{
public ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
CancellationToken cancellationToken)
{
if (exception is ValidationException validationException)
{
httpContext.Response.StatusCode = StatusCodes.Status422UnprocessableEntity;
var errors = validationException.Errors
.GroupBy(e => e.PropertyName)
.ToDictionary(
g => g.Key,
g => g.Select(e => e.ErrorMessage).ToArray()
);
var response = new
{
Title = "Validation failed",
Status = 422,
Errors = errors
};
return new ValueTask<bool>(httpContext.Response.WriteAsJsonAsync(response));
}
return new ValueTask<bool>(false);
}
}
全局异常处理最佳实践
1. 分层处理策略
| 层级 | 处理方式 | 适用场景 |
|---|---|---|
| 控制器层 | Try-Catch | 业务逻辑异常 |
| 中间件层 | 异常处理中间件 | 全局未处理异常 |
| 应用层 | 全局异常过滤器 | 应用级别异常 |
2. 错误响应标准化
public class ErrorResponse
{
public string Type { get; set; }
public string Title { get; set; }
public int Status { get; set; }
public string Detail { get; set; }
public string Instance { get; set; }
public Dictionary<string, string[]> Errors { get; set; }
public static ErrorResponse FromException(Exception exception, HttpContext context)
{
return new ErrorResponse
{
Type = exception.GetType().Name,
Title = "An error occurred",
Status = StatusCodes.Status500InternalServerError,
Detail = exception.Message,
Instance = context.Request.Path,
Errors = new Dictionary<string, string[]>()
};
}
}
3. 日志记录策略
public class LoggingExceptionHandler : IExceptionHandler
{
private readonly ILogger<LoggingExceptionHandler> _logger;
public LoggingExceptionHandler(ILogger<LoggingExceptionHandler> logger)
{
_logger = logger;
}
public ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
CancellationToken cancellationToken)
{
// 根据不同异常类型记录不同级别的日志
switch (exception)
{
case BusinessException businessException:
_logger.LogWarning(businessException, "Business exception occurred");
break;
case ValidationException validationException:
_logger.LogInformation(validationException, "Validation failed");
break;
default:
_logger.LogError(exception, "Unhandled exception occurred");
break;
}
return new ValueTask<bool>(false);
}
}
高级异常处理场景
1. 异步操作异常处理
public static class AsyncExceptionHandling
{
public static async Task<T> WithExceptionHandlingAsync<T>(
Func<Task<T>> operation,
Action<Exception> onError = null)
{
try
{
return await operation();
}
catch (Exception ex)
{
onError?.Invoke(ex);
throw;
}
}
}
2. 断路器模式集成
public class CircuitBreakerExceptionHandler : IExceptionHandler
{
private readonly CircuitBreaker _circuitBreaker;
public CircuitBreakerExceptionHandler(CircuitBreaker circuitBreaker)
{
_circuitBreaker = circuitBreaker;
}
public ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
CancellationToken cancellationToken)
{
if (exception is TimeoutException || exception is HttpRequestException)
{
_circuitBreaker.RecordFailure();
httpContext.Response.StatusCode = StatusCodes.Status503ServiceUnavailable;
return new ValueTask<bool>(httpContext.Response.WriteAsJsonAsync(new
{
Message = "Service temporarily unavailable",
RetryAfter = 30
}));
}
return new ValueTask<bool>(false);
}
}
性能优化考虑
异常处理性能对比表
| 处理方式 | 性能影响 | 内存占用 | 适用场景 |
|---|---|---|---|
| Try-Catch | 低 | 低 | 局部异常处理 |
| 中间件 | 中 | 中 | 全局异常处理 |
| 过滤器 | 中高 | 中 | 控制器级别 |
| 自定义处理器 | 高 | 高 | 复杂业务逻辑 |
优化建议
- 避免过度使用异常:使用返回码代替异常进行流程控制
- 使用ValueTask:减少异步操作的开销
- 缓存错误响应:对常见错误响应进行缓存
- 批量处理:对验证错误等进行批量处理
安全考虑
1. 信息泄露防护
public class SecureExceptionHandler : IExceptionHandler
{
public ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
CancellationToken cancellationToken)
{
// 在生产环境中隐藏敏感信息
var errorMessage = httpContext.RequestServices.GetRequiredService<IWebHostEnvironment>().IsDevelopment()
? exception.Message
: "An error occurred. Please try again later.";
httpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
return new ValueTask<bool>(httpContext.Response.WriteAsJsonAsync(new
{
Message = errorMessage
}));
}
}
2. 错误响应安全头
app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
context.Response.Headers.Add("X-Frame-Options", "DENY");
context.Response.Headers.Add("Content-Security-Policy", "default-src 'self'");
// 异常处理逻辑
});
});
测试策略
单元测试示例
[Test]
public async Task CustomExceptionHandler_ShouldHandleBusinessException()
{
// Arrange
var handler = new CustomExceptionHandler();
var context = new DefaultHttpContext();
var exception = new BusinessException("Test error");
// Act
var result = await handler.TryHandleAsync(context, exception, CancellationToken.None);
// Assert
Assert.IsTrue(result);
Assert.AreEqual(StatusCodes.Status400BadRequest, context.Response.StatusCode);
}
集成测试示例
[Fact]
public async Task GlobalExceptionHandler_ShouldReturnProperResponse()
{
// Arrange
var factory = new WebApplicationFactory<Program>()
.WithWebHostBuilder(builder =>
{
builder.ConfigureServices(services =>
{
services.AddExceptionHandler<CustomExceptionHandler>();
});
});
var client = factory.CreateClient();
// Act
var response = await client.GetAsync("/api/test/throw");
// Assert
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
Assert.Contains("error", content);
}
总结
ASP.NET Core的异常处理机制提供了灵活而强大的工具来构建健壮的应用程序。通过合理配置全局异常处理策略,您可以:
- 提升用户体验:提供友好的错误信息
- 增强系统稳定性:防止未处理异常导致应用崩溃
- 改善可维护性:统一的错误处理逻辑
- 加强安全性:防止敏感信息泄露
记住,良好的异常处理不仅仅是技术实现,更是对用户体验和系统稳定性的重要保障。根据您的具体需求选择合适的异常处理策略,并始终在生产环境中进行充分的测试。
通过本文介绍的策略和最佳实践,您将能够构建出更加健壮和可靠的ASP.NET Core应用程序。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



