【问题标题】:Asp.Net Show Default Error Page that works with $ajaxAsp.Net 显示与 $ajax 一起使用的默认错误页面
【发布时间】:2019-03-16 14:57:21
【问题描述】:

我有一个混合的 asp.net 网络表单/mvc 应用程序。当发生 500 错误时,我想执行以下操作:

  1. 如果错误发生在 Web 表单上,则显示自定义 *.aspx 页面。
  2. 如果错误发生在返回视图的控制器操作中,则显示自定义 mvc 视图。
  3. 如果错误发生在响应 $ajax 请求的控制器操作中,则显示用 javascript 构建的自定义消息。 这第三项是我遇到问题的地方。

在所有情况下,我都希望只记录一次错误。我在 global.asax Application_OnError 事件过程中记录 Web 表单错误。对于我的 mvc 控制器,我已将此调用添加到 Application_Start 事件过程:

GlobalFilters.Filters.Add(new HandleErrorAttribute());

然后创建了一个基类,应用程序中的所有控制器都从该基类派生。在这个基类中,我在 OnException 事件过程中记录错误。错误记录工作正常。

对于第 1 项,自定义 *.aspx 页面,我将其添加到我的 web.config 中,它成功地将所有 webforms 错误重定向到我的自定义错误页面:

<customErrors mode="On" defaultRedirect="MyFolder/MyDefaultErrorPage.aspx" 

对于第 2 项,自定义 mvc 视图,我发现我需要在 web.config 的 httpErrors 元素中捕获 IIS 错误。这成功地将所有控制器错误重定向到我的自定义错误视图:

    <httpErrors errorMode="Custom" existingResponse="Replace">
  <clear />
  <error statusCode="500" path="/MyFolder/MyErrorView" responseMode="Redirect"/>
</httpErrors>

上述所有方法都可以正常工作,但不幸的是,拦截 IIS 500 错误的第 2 项导致所有 $ajax 调用返回成功:事件处理程序而不是错误:事件处理程序,即使控制器操作抛出例外。例如,我从 javascript 调用控制器操作:

$.ajax({
            type: "GET",
            url: '/MyFolder/MyControllerAction',
            success: function (data) {
                do_something(data);
            },
            error: function (XMLHttpRequest, ajaxOptions, ex) {
                show_error_message(XMLHttpRequest, ex); 
            }

问题在于,当 MyControllerAction 抛出异常时,调用的是“success:”事件处理程序,而不是“error:”事件处理程序。如果我从 web.config 中删除拦截 IIS 500 错误的节点,我会在 $ajax 调用中点击所需的“错误:”事件处理程序,但它显示默认的 IIS 500 错误页面,而不是我的自定义错误页面。

有没有什么方法可以为我的所有控制器错误显示自定义错误页面并且仍然有错误:当我从 javascript 执行 $ajax 调用时事件处理程序触发?

更新:如果我创建一个派生自 HandleErrorAttribute 的自定义类并在 GlobalFilters.Filters.Add() 中使用它,我就会成功。这会导致“错误:”事件在我的 javascript $ajax 调用中触发。问题是 XMLHttpRequest.responseText 不包含我的自定义消息(它只是说“页面无法显示,因为发生了内部服务器错误。”)。如果有任何方法可以将自定义消息传递给返回到 $.ajax 调用的 XMLHttpRequest.responseText?

public class MyCustomHandleErrorAttribute : HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        if(filterContext.HttpContext.Request.IsAjaxRequest()
            && filterContext.Exception != null)
        {
            //500 is needed so that $ajax "error:" event handler is hit, instead of "success:"
            filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

            filterContext.Result = new JsonResult
            {
                JsonRequestBehavior = JsonRequestBehavior.AllowGet,
                Data = new
                {
                    Message = "Custom message will go here"
                }
            };

            //this stops Application_OnError from firing
            filterContext.ExceptionHandled = true;
        }
        else
        {
            filterContext.Result = new ContentResult()
            {
                Content = "<html><body>Custom message will go here</body></html>",
                ContentType = "text/html"
            };
            filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.OK;
            filterContext.ExceptionHandled = true;
        }
    }

【问题讨论】:

    标签: javascript asp.net asp.net-mvc error-handling


    【解决方案1】:

    总结一下:当服务器发生运行时错误时,我希望能够将自定义错误消息传递给 $ajax 事件处理程序(我不想要默认的 IIS 错误消息),并且我想要要触发的 $ajax "error:" 函数(不是 "success:" 函数)。

    上述问题中概述的自定义 HandleErrorAttribute 有效,但还需要进行两项更改才能覆盖默认的 IIS 错误消息:

    1. 将此行添加到自定义属性中 OnException 过程中的第一个“if”块(处理 ajax 错误的“if”块):

      filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;

    2. 将此添加到 web.config 中的 httpErrors 标记:

      errorMode="Custom" existingResponse="PassThrough"

    existingResponse 的值也可以是“Auto”

    我的最终自定义属性如下所示:

    public class MyCustomHandleErrorAttribute : HandleErrorAttribute
    {
        public override void OnException(ExceptionContext filterContext)
        {
            //log the error
            if (filterContext.Exception != null)
            {
                //note that Application_Error makes the same call for errors it handles.
                //this method and Application_Error are the only two places in the application where errors are handled.
                MyErrorLogger(filterContext.Exception.GetBaseException());
            }
    
            if (filterContext.HttpContext.Request.IsAjaxRequest()
                && filterContext.Exception != null)
            {
                //this is an error from a $ajax call.
                //500 is needed so that $ajax "error:" function is hit, instead of "success:"
                filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
    
                filterContext.Result = new JsonResult()
                {
                    Data = new 
                    {
                        MyCustomMessage="A custom error message",
                        IsException = true
                    }
                };
    
                //this stops Application_OnError from firing
                filterContext.ExceptionHandled = true;
    
                //this stops the web site from using the default IIS 500 error. 
                //in addition must set existingResponse="PassThrough" or "Auto" in web.config httpErrors element.
                filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
            }
            else
            {
                //this is an error in a controller method that returns a view
                filterContext.Result = new RedirectToRouteResult(
                    new System.Web.Routing.RouteValueDictionary
                    {
                        {"action", "Error500" },
                        {"controller", "Error" },
                        { "Message", "My custom message here."}
                    });
                filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.OK;
                filterContext.ExceptionHandled = true;
            }
        }
    }
    

    上面创建的自定义错误消息在客户端解析为 "error:" 函数的 "XMLHttpRequest.responseText" 参数中的 JSON 对象:

    error: function (XMLHttpRequest, ajaxOptions, ex) {
        alert(jQuery.parseJSON(XMLHttpRequest.responseText).MyCustomMessage);
            }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-01
      • 2020-07-24
      • 2011-10-04
      • 2013-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多