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

MVC中Global.asax.cs的Application_Error在IIS发布后日志异常问题

问题分析与解决方案

这个问题我之前也碰到过,本质是IIS发布后ASP.NET的默认错误处理逻辑和你自定义的Application_Error发生了冲突,具体原因和解决办法如下:

问题根源

当你本地调试(VS F5)时,Web.config里的<customErrors>默认是mode="RemoteOnly"或mode="Off",这时候ASP.NET不会触发内置的MVC错误处理逻辑,原始异常会直接传递到你的Application_Error方法,所以能正常记录Exception XYZ。

但发布到IIS后,默认的<customErrors>配置通常是mode="On",这时候ASP.NET MVC会自动启用内置的错误处理机制:它会在你的Application_Error执行之前先捕获异常,然后尝试自动渲染错误视图,并且默认把HandleErrorInfo作为模型传递给视图。而你的错误视图期望的是MyWebsite.Models.Services.ErrorModel,这就抛出了类型不匹配的InvalidOperationException——更糟的是,这个新异常会覆盖掉原始的Exception XYZ,导致你日志里记录的是这个类型错误,而非真正的业务异常。

哪怕你没手动注册HandleErrorAttribute,MVC在customErrors开启时也会自动触发这套逻辑,这就是问题的核心。

解决办法

要确保原始异常被正确记录,同时避免模型类型不匹配的问题,你需要完全接管错误处理流程,阻止MVC的内置逻辑介入:

1. 调整Web.config的<customErrors>配置

在Web.config的<system.web>节点下,修改配置让ASP.NET不要自动渲染错误视图,而是交给我们的Application_Error处理:

<system.web>
  <customErrors mode="On" redirectMode="ResponseRewrite" defaultRedirect="~/Services/Error" />
</system>

redirectMode="ResponseRewrite"会避免客户端跳转,而是直接在当前请求上下文渲染错误页,同时保证我们能捕获到原始异常。

2. 修改Application_Error方法,优先获取原始异常并手动渲染视图

原来的Response.RedirectToRoute会触发新的请求,容易让MVC的内置逻辑再次介入。我们改成直接调用控制器的Action,并传递自定义模型:

protected void Application_Error()
{
    // 穿透HttpUnhandledException,获取真正的原始异常
    Exception originalException = Server.GetLastError();
    if (originalException is HttpUnhandledException httpEx)
    {
        originalException = httpEx.InnerException;
    }

    // 记录原始异常(这时候就能正确记录Exception XYZ了)
    _logger.Error("something bad happened", originalException);

    // 清除错误,阻止后续内置逻辑处理
    Server.ClearError();

    // 手动构建路由上下文,传递自定义模型
    var routeData = new RouteData();
    routeData.Values.Add("controller", "Services");
    routeData.Values.Add("action", "Error");
    // 把自定义模型通过路由数据传递
    routeData.Values.Add("errorModel", new ErrorModel 
    { 
        Message = "An unexpected error occurred. Please try again later." 
    });

    // 直接调用控制器执行Action,避免跳转导致的模型替换
    IController controller = new ServicesController();
    controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}

3. 调整ServicesController的Error方法

让它能接收我们传递的自定义模型:

public ActionResult Error(ErrorModel errorModel = null)
{
    // 如果没有传递模型(比如极端情况),使用默认值
    var model = errorModel ?? new ErrorModel{ Message = "nothing really happened go to bed" };
    return View(model);
}

4. 禁用MVC默认的HandleErrorAttribute

检查项目的App_Start/FilterConfig.cs文件,如果有如下代码,注释掉它,彻底禁用MVC的内置错误处理过滤器:

// filters.Add(new HandleErrorAttribute()); // 注释掉这行

验证效果

做完以上修改后,发布到IIS再访问/general视图,日志里应该能正确记录Exception XYZ,同时错误视图也能正常显示自定义的ErrorModel内容,不会再出现模型类型不匹配的异常。

内容的提问来源于stack exchange,提问作者joym8

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:30:01