ASP.NET Core应用全局错误处理器配置异常问题排查
ASP.NET Core全局错误处理器排查问题
问题描述
正在为ASP.NET Core Web应用配置全局错误处理器,已在Startup.cs的Configure方法中根据环境配置了ErrorHandlerMiddleware,并编写了对应的ErrorController。启动时中间件的Invoke方法能被触发,但测试时主动触发的异常却未被该中间件处理,需排查原因。
当前配置
Startup.cs Configure方法
if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseMiddleware<ErrorHandlerMiddleware>(); }
ErrorHandlerMiddleware中间件
public class ErrorHandlerMiddleware { private readonly RequestDelegate _next; public ErrorHandlerMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext context) { try { await _next(context); } catch (Exception error) { var response = context.Response; response.ContentType = "application/json"; var responseModel = ErrorResponse<string>.Fail(error.Message); switch (error) { case ExceptionService e: response.StatusCode = (int)HttpStatusCode.BadRequest; break; case KeyNotFoundException e: response.StatusCode = (int)HttpStatusCode.NotFound; break; default: response.StatusCode = (int)HttpStatusCode.InternalServerError; break; } var result = JsonSerializer.Serialize(responseModel); var tempData = context.RequestServices.GetRequiredService<ITempDataProvider>().LoadTempData(context); tempData["Error_Message"] = error.Message.ToString(); tempData["Error_StackTrace"] = error.StackTrace.ToString(); tempData["Error_Source"] = error.Source.ToString(); tempData["Error_TargetSite"] = error.TargetSite.ToString(); if (error.InnerException != null) tempData["Error_InnerException"] = error.InnerException.ToString(); context.RequestServices.GetRequiredService<ITempDataProvider>().SaveTempData(context, tempData); context.Response.Redirect($"/Error?code={response.StatusCode}"); } } }
ErrorController错误控制器
public class ErrorController : Controller { private readonly IUnitOfWork _unitOfWork; private readonly UserManager<ApplicationUser> _userManager; private readonly IEmailService _emailService; private readonly AppConfiguration _appConfig; private readonly AppMailSettings _mailSettings; public ErrorController(IUnitOfWork unitOfWork, UserManager<ApplicationUser> userManager, IEmailService emailService, IOptions<AppConfiguration> appConfig, IOptions<AppMailSettings> mailSettings) { _unitOfWork = unitOfWork; _userManager = userManager; _emailService = emailService; _appConfig = appConfig.Value; _mailSettings = mailSettings.Value; } [AllowAnonymous] [Route("Error")] public async Task<IActionResult> Error(string code) { var Error_Message = TempData["Error_Message"]; var Error_StackTrace = TempData["Error_StackTrace"]; var Error_Source = TempData["Error_Source"] ; var Error_TargetSite = TempData["Error_TargetSite"]; ErrorViewModel model = new ErrorViewModel(); model.ErrorMessage = "Sorry, an application error occured. Our support team has been notified."; model.ErrorDateTime = DateTime.Now.ToString(); model.StackTrace = Error_StackTrace.ToString(); model.InnerException = TempData["Error_Message"].ToString(); model.Source = Error_Source.ToString(); model.TargetSite = Error_TargetSite.ToString(); var user = await _userManager.GetUserAsync(HttpContext.User); var baseUrl = "http://localhost:44350"; if (user != null) { model.UserId = user.Id; model.UserName = user.UserName; model.Role = user.UserType; var mailRequest = new MailRequest(); mailRequest.ToAddresses = new List<string> { "email@email.com", _mailSettings.ErrorEmailAddress }; mailRequest.Subject = "WFC Plus Error Report"; StringBuilder sb = new StringBuilder(); sb.AppendLine($"User: {model.UserName}"); sb.AppendLine($"Is Development: {model.IsDevelopment}"); mailRequest.Body = sb.ToString(); await _emailService.SendEmail(mailRequest); } return View(model); } }
排查步骤
- 确认运行环境:确保测试时处于非Development环境,可通过查看环境变量
ASPNETCORE_ENVIRONMENT的值,或在Startup中添加日志输出当前环境进行验证。 - 检查中间件注册顺序:全局异常中间件需要注册在所有业务中间件(如路由、MVC)之前,这样才能捕获后续中间件抛出的异常。确保
app.UseMiddleware<ErrorHandlerMiddleware>()在app.UseRouting()、app.UseEndpoints()等之前调用。 - 验证异常是否未被提前捕获:检查测试用的Action或业务逻辑中是否存在try-catch块捕获了异常但未重新抛出,这种情况会导致中间件无法感知异常。测试时可直接在Action中抛出未处理的异常:
throw new Exception("Test exception");。 - 排查其他中间件干扰:暂时注释非必要的第三方中间件或框架中间件,仅保留错误处理中间件和MVC相关配置,测试异常是否能被捕获,排除其他中间件提前处理异常的可能。
- 添加状态码错误处理逻辑:当前中间件仅捕获抛出的异常,对于未抛出异常但返回错误状态码(如404、500)的情况无法处理。可在
await _next(context)后添加状态码检查逻辑:if (context.Response.StatusCode >= 400 && !context.Response.HasStarted) { // 处理状态码错误,比如模拟异常或直接生成错误响应 var exception = new Exception($"Status code error: {context.Response.StatusCode}"); // 复用现有catch块的处理逻辑,或单独处理 } - 添加日志排查:在中间件的Invoke方法中注入
ILogger<ErrorHandlerMiddleware>,记录进入try块、离开try块以及进入catch块的信息,确认异常发生时是否进入了catch逻辑。例如:private readonly ILogger<ErrorHandlerMiddleware> _logger; public ErrorHandlerMiddleware(RequestDelegate next, ILogger<ErrorHandlerMiddleware> logger) { _next = next; _logger = logger; } public async Task Invoke(HttpContext context) { _logger.LogInformation("Entering ErrorHandlerMiddleware.Invoke"); try { await _next(context); _logger.LogInformation("Completed next middleware without exception"); } catch (Exception error) { _logger.LogError(error, "Exception caught in ErrorHandlerMiddleware"); // 原有处理逻辑 } } - 检查TempData配置:虽然这不会影响异常捕获,但如果TempData无法正常工作会导致ErrorController无法获取错误信息。确保应用已配置Session(若使用SessionTempDataProvider),或使用CookieTempDataProvider并配置了相应的Cookie选项。
内容的提问来源于stack exchange,提问作者Ryan
相关产品推荐
相关产品推荐

