发布至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发布后运行效果:

- IIS发布后运行效果:

按优先级从高到低依次排查处理:
配置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跳过自定义错误替换,双保险兼容性更好。删除冗余的视图Render调用
代码里前后共调用了三次razorView.Render(viewContext, sw),前两次调用时还没给ViewBag赋值错误信息、状态码,会把未填充完整的视图内容提前写入输出流,还会造成内容重复渲染。本地IIS可能因为输出缓冲策略问题没有暴露异常,Azure环境下缓冲规则不同,很容易导致响应格式异常被IIS拦截。删掉前两次多余的Render调用,只保留最后赋值完所有视图数据、写完日志后的那一次Render即可。排查错误处理逻辑本身的运行异常
代码里直接读取Session[SessionVariableNames.UserName],如果错误发生时Session还未初始化、或者Azure环境下Session状态配置有问题,这里会抛出空引用或会话不可用异常,直接中断整个错误处理流程,最终就会显示Azure默认错误页。- 先给Session访问逻辑加空值判断,避免非预期异常
- 可以给整个Application_Error内部逻辑加一层try/catch,把错误处理过程本身抛出的异常输出到Azure应用日志,快速定位问题
- 打开Azure门户的Kudu控制台,进入
site/wwwroot目录,确认~/Areas/Errors/Views/Error/路径下的所有cshtml视图文件都已正确部署,漏传视图文件也会导致Render失败。
核对环境版本一致性
确认Azure站点配置的.NET Framework/.NET版本和本地发布的目标版本一致,版本不匹配会导致Razor视图渲染、路由解析逻辑出现非预期异常,中断错误处理流程。
内容的提问来源于stack exchange,提问作者Prabhat-VS

