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

发布至Azure后Global.asax的Application_Error错误处理失效问题

问题背景

我在Global.asax中添加了如下全局错误处理通用代码:

protected void Application_Error(object sender, EventArgs e)
{
    var exception = Server.GetLastError();

    // 读取当前请求的控制器、Action名称
    var requestControllerName = Convert.ToString(HttpContext.Current.Request.RequestContext?.RouteData?.Values["controller"]);
    var requestActionName = Convert.ToString(HttpContext.Current.Request.RequestContext?.RouteData?.Values["action"]);

    var errorArea = "Errors";
    var errorController = "Error";
    var errorAction = "Index";

    // 弹窗类错误走专属错误页
    if ((ControllerActionForPopupError.ErrorPopupController.Contains(requestControllerName)) & (ControllerActionForPopupError.ErrorPopupAction.Contains(requestActionName)))
    {
        errorAction = "ShowErrorPopUp";
    }

    var pathToViewFile = $"~/Areas/{errorArea}/Views/{errorController}/{errorAction}.cshtml";

    var controller = new ErrorController();
    var routeData = new RouteData { DataTokens = { { "area", errorArea } }, Values = { { "controller", errorController }, { "action", errorAction } } };
    var controllerContext = new ControllerContext(new HttpContextWrapper(HttpContext.Current), routeData, controller);
    controller.ControllerContext = controllerContext;

    var sw = new StringWriter();
    var razorView = new RazorView(controller.ControllerContext, pathToViewFile, "", false, null);
    var model = new ViewDataDictionary(new HandleErrorInfo(exception, requestControllerName, requestActionName));
    var viewContext = new ViewContext(controller.ControllerContext, razorView, model, new TempDataDictionary(), sw);

    // 冗余Render调用1
    razorView.Render(viewContext, sw);

    // 生成错误日志编号
    var randomNo = new Random(Guid.NewGuid().GetHashCode());
    var logNo = randomNo.Next(1, 10000000);

    // 冗余Render调用2
    razorView.Render(viewContext, sw);

    string errorLogMsg = string.Empty;
    if (exception.InnerException != null)
    {
        errorLogMsg = string.Format(ErrorLog.ErrorLogMsg, logNo, Session[SessionVariableNames.UserName], requestControllerName, requestActionName, exception.InnerException);
    }
    else
    {
        errorLogMsg = string.Format(ErrorLog.ErrorLogMsg, logNo, Session[SessionVariableNames.UserName], requestControllerName, requestActionName, exception);
    }

    if (Response.StatusCode == (int)HamaspikData.Utility.Enums.ErrorStatusCode.Success)
    {
        if (exception.Message.Contains(ErrorLog.SessionTimeOutErr) || exception.Message.Contains(ErrorLog.ModuleListNotReturnErr))
        {
            Response.StatusCode = (int)HamaspikData.Utility.Enums.ErrorStatusCode.UnassignedError;
        }
        else
        {
            Response.StatusCode = new HttpException(null, exception).GetHttpCode();
        }
    }

    // 赋值错误提示信息
    if (exception.Message.Contains(ErrorLog.PageNotFoundErr))
    {
        viewContext.ViewBag.ErrorMessage = string.Format(ErrorLog.PageNotFoundMsg, logNo);
    }
    else
    {
        if (exception.Message.Contains(ErrorLog.SessionTimeOutErr))
        {
            viewContext.ViewBag.ErrorMessage = ErrorLog.TimeoutMessage;
        }
        else if (exception.Message.Contains(ErrorLog.ModuleListNotReturnErr))
        {
            viewContext.ViewBag.ErrorMessage = ErrorLog.ModuleListNotReturnMessage;
        }
        else
        {
            viewContext.ViewBag.ErrorMessage = string.Format(ErrorLog.Message, logNo);
        }
    }

    viewContext.ViewBag.ErrorStatusCode = Response.StatusCode.ToString();

    Logger.globalException(errorLogMsg);
    razorView.Render(viewContext, sw);
    HttpContext.Current.Response.Write(sw);
    Server.ClearError();
    HttpContext.Current.Response.End();
}

Web.config相关配置如下:

<customErrors mode="Off">

上述错误处理逻辑在常规Web托管环境、本地IIS发布场景下均可正常运行,但部署到Azure站点后无法正常生效,两种环境的运行效果如下:

  • Azure发布后运行效果:
    Azure发布后错误页面效果
  • IIS发布后运行效果:
    IIS发布后自定义错误页面效果
排查修复方案

按优先级从高到低依次排查处理:

  1. 配置IIS透传自定义错误响应(最常见原因)
    当前只关闭了ASP.NET层级的customErrors,但Azure App Service托管的IIS默认会拦截所有非200状态码的响应,替换成平台自带的默认错误页,本地IIS默认配置没有开启这个拦截规则所以能正常运行。
    在Web.config的<system.webServer>节点下添加如下配置,让IIS直接返回应用生成的响应内容,不要做替换:

    <system.webServer>
      <httpErrors existingResponse="PassThrough" />
    </system.webServer>
    

    也可以在代码里输出响应前加一行Response.TrySkipIisCustomErrors = true;,显式告知IIS跳过自定义错误替换,双保险兼容性更好。

  2. 删除冗余的视图Render调用
    代码里前后共调用了三次razorView.Render(viewContext, sw),前两次调用时还没给ViewBag赋值错误信息、状态码,会把未填充完整的视图内容提前写入输出流,还会造成内容重复渲染。本地IIS可能因为输出缓冲策略问题没有暴露异常,Azure环境下缓冲规则不同,很容易导致响应格式异常被IIS拦截。删掉前两次多余的Render调用,只保留最后赋值完所有视图数据、写完日志后的那一次Render即可。

  3. 排查错误处理逻辑本身的运行异常
    代码里直接读取Session[SessionVariableNames.UserName],如果错误发生时Session还未初始化、或者Azure环境下Session状态配置有问题,这里会抛出空引用或会话不可用异常,直接中断整个错误处理流程,最终就会显示Azure默认错误页。

    • 先给Session访问逻辑加空值判断,避免非预期异常
    • 可以给整个Application_Error内部逻辑加一层try/catch,把错误处理过程本身抛出的异常输出到Azure应用日志,快速定位问题
    • 打开Azure门户的Kudu控制台,进入site/wwwroot目录,确认~/Areas/Errors/Views/Error/路径下的所有cshtml视图文件都已正确部署,漏传视图文件也会导致Render失败。
  4. 核对环境版本一致性
    确认Azure站点配置的.NET Framework/.NET版本和本地发布的目标版本一致,版本不匹配会导致Razor视图渲染、路由解析逻辑出现非预期异常,中断错误处理流程。


内容的提问来源于stack exchange,提问作者Prabhat-VS

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 10:15:29