You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 17:14:55