【问题标题】:ASP.NET MVC Ajax Error handlingASP.NET MVC Ajax 错误处理
【发布时间】:2011-06-10 02:45:58
【问题描述】:

jquery ajax 调用动作时如何处理控制器中抛出的异常?

例如,我想要一个全局 javascript 代码,该代码在 ajax 调用期间在任何类型的服务器异常上执行,如果处于调试模式或只是正常的错误消息,则会显示异常消息。

在客户端,我会调用一个关于ajax错误的函数。

在服务器端,我是否需要编写自定义操作过滤器?

【问题讨论】:

标签: asp.net-mvc jquery asp.net-mvc-3


【解决方案1】:

如果服务器发送了一些不同于 200 的状态码,则执行错误回调:

$.ajax({
    url: '/foo',
    success: function(result) {
        alert('yeap');
    },
    error: function(XMLHttpRequest, textStatus, errorThrown) {
        alert('oops, something bad happened');
    }
});

要注册一个全局错误处理程序,您可以使用$.ajaxSetup() 方法:

$.ajaxSetup({
    error: function(XMLHttpRequest, textStatus, errorThrown) {
        alert('oops, something bad happened');
    }
});

另一种方法是使用 JSON。因此,您可以在服务器上编写一个自定义操作过滤器来捕获异常并将它们转换为 JSON 响应:

public class MyErrorHandlerAttribute : FilterAttribute, IExceptionFilter
{
    public void OnException(ExceptionContext filterContext)
    {
        filterContext.ExceptionHandled = true;
        filterContext.Result = new JsonResult
        {
            Data = new { success = false, error = filterContext.Exception.ToString() },
            JsonRequestBehavior = JsonRequestBehavior.AllowGet
        };
    }
}

然后用这个属性装饰你的控制器动作:

[MyErrorHandler]
public ActionResult Foo(string id)
{
    if (string.IsNullOrEmpty(id))
    {
        throw new Exception("oh no");
    }
    return Json(new { success = true });
}

最后调用它:

$.getJSON('/home/foo', { id: null }, function (result) {
    if (!result.success) {
        alert(result.error);
    } else {
        // handle the success
    }
});

【讨论】:

  • 谢谢你,后者正是我要找的。那么对于 asp.net mvc 异常,是否有一种特定的方式我需要抛出它,以便它可以被 jquery 错误处理程序捕获?
  • @Lol 编码器,无论您如何在控制器操作中抛出异常,服务器都会返回 500 状态码并执行 error 回调。
  • 谢谢,完美,正是我想要的。
  • 状态码 500 会不会有点错误?引用这个小伙子broadcast.oreilly.com/2011/06/…:“没有意识到 4xx 错误意味着我搞砸了,5xx 意味着你搞砸了”——我是客户端,你是服务器。
  • 这个答案对新版本的 ASPNET 仍然有效吗?
【解决方案2】:

谷歌搜索后,我编写了一个基于 MVC Action Filter 的简单异常处理:

public class HandleExceptionAttribute : HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAjaxRequest() && filterContext.Exception != null)
        {
            filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            filterContext.Result = new JsonResult
            {
                JsonRequestBehavior = JsonRequestBehavior.AllowGet,
                Data = new
                {
                    filterContext.Exception.Message,
                    filterContext.Exception.StackTrace
                }
            };
            filterContext.ExceptionHandled = true;
        }
        else
        {
            base.OnException(filterContext);
        }
    }
}

并写入 global.ascx:

 public static void RegisterGlobalFilters(GlobalFilterCollection filters)
 {
      filters.Add(new HandleExceptionAttribute());
 }

然后在布局或母版页上编写此脚本:

<script type="text/javascript">
      $(document).ajaxError(function (e, jqxhr, settings, exception) {
                       e.stopPropagation();
                       if (jqxhr != null)
                           alert(jqxhr.responseText);
                     });
</script>

最后你应该打开自定义错误。 然后享受它:)

【讨论】:

  • 我可以在 Firebug 中看到错误,但它没有重定向到错误页面。?
  • 谢谢!应将 IMO 标记为答案,因为它对 ajax 请求进行过滤并继承正确的类,而不是 HandleErrorAttribute 继承的内容
  • 我认为“Request.IsAjaxRequest()”有时并不那么可靠。
  • 对于调试配置,它总是有效,但在发布配置中并不总是有效并返回 html,而不是有人有解决这种情况的方法吗?
【解决方案3】:

不幸的是,这两个答案都不适合我。令人惊讶的是,解决方案要简单得多。从控制器返回:

return new HttpStatusCodeResult(HttpStatusCode.BadRequest, e.Response.ReasonPhrase);

并根据需要在客户端将其作为标准 HTTP 错误处理。

【讨论】:

  • @Will Huang:异常实例的名称
  • 我必须将第一个参数转换为int。此外,当我这样做时,结果将传递给ajax success 处理程序,而不是error 处理程序。这是预期的行为吗?
【解决方案4】:

我做了一个快速的解决方案,因为我没有时间而且效果很好。虽然我认为更好的选择是使用异常过滤器,但如果需要一个简单的解决方案,我的解决方案可能会有所帮助。

我做了以下事情。在控制器方法中,我返回了一个 JsonResult,其中包含一个属性“成功”的数据:

    [HttpPut]
    public JsonResult UpdateEmployeeConfig(EmployeConfig employeToSave) 
    {
        if (!ModelState.IsValid)
        {
            return new JsonResult
            {
                Data = new { ErrorMessage = "Model is not valid", Success = false },
                ContentEncoding = System.Text.Encoding.UTF8,
                JsonRequestBehavior = JsonRequestBehavior.DenyGet
            };
        }
        try
        {
            MyDbContext db = new MyDbContext();

            db.Entry(employeToSave).State = EntityState.Modified;
            db.SaveChanges();

            DTO.EmployeConfig user = (DTO.EmployeConfig)Session["EmployeLoggin"];

            if (employeToSave.Id == user.Id)
            {
                user.Company = employeToSave.Company;
                user.Language = employeToSave.Language;
                user.Money = employeToSave.Money;
                user.CostCenter = employeToSave.CostCenter;

                Session["EmployeLoggin"] = user;
            }
        }
        catch (Exception ex) 
        {
            return new JsonResult
            {
                Data = new { ErrorMessage = ex.Message, Success = false },
                ContentEncoding = System.Text.Encoding.UTF8,
                JsonRequestBehavior = JsonRequestBehavior.DenyGet
            };
        }

        return new JsonResult() { Data = new { Success = true }, };
    }

稍后在 ajax 调用中,我只是要求这个属性知道我是否有异常:

$.ajax({
    url: 'UpdateEmployeeConfig',
    type: 'PUT',
    data: JSON.stringify(EmployeConfig),
    contentType: "application/json;charset=utf-8",
    success: function (data) {
        if (data.Success) {
            //This is for the example. Please do something prettier for the user, :)
            alert('All was really ok');                                           
        }
        else {
            alert('Oups.. we had errors: ' + data.ErrorMessage);
        }
    },
    error: function (request, status, error) {
       alert('oh, errors here. The call to the server is not working.')
    }
});

希望这会有所帮助。快乐的代码! :P

【讨论】:

    【解决方案5】:

    与 aleho 的回应一致,这是一个完整的示例。它就像一个魅力,超级简单。

    控制器代码

    [HttpGet]
    public async Task<ActionResult> ChildItems()
    {
        var client = TranslationDataHttpClient.GetClient();
        HttpResponseMessage response = await client.GetAsync("childItems);
    
        if (response.IsSuccessStatusCode)
            {
                string content = response.Content.ReadAsStringAsync().Result;
                List<WorkflowItem> parameters = JsonConvert.DeserializeObject<List<WorkflowItem>>(content);
                return Json(content, JsonRequestBehavior.AllowGet);
            }
            else
            {
                return new HttpStatusCodeResult(response.StatusCode, response.ReasonPhrase);
            }
        }
    }
    

    视图中的Javascript代码

    var url = '@Html.Raw(@Url.Action("ChildItems", "WorkflowItemModal")';
    
    $.ajax({
        type: "GET",
        dataType: "json",
        url: url,
        contentType: "application/json; charset=utf-8",
        success: function (data) {
            // Do something with the returned data
        },
        error: function (xhr, status, error) {
            // Handle the error.
        }
    });
    

    希望这对其他人有帮助!

    【讨论】:

      【解决方案6】:

      为了在客户端处理来自 ajax 调用的错误,您可以为 ajax 调用的error 选项分配一个函数。

      要全局设置默认值,您可以使用此处描述的函数: http://api.jquery.com/jQuery.ajaxSetup.

      【讨论】:

      • 我 4 年前给出的答案突然被否决了?有人愿意给出原因吗?
      • 联系 SOF 并让他们的 DBA 查询谁投了反对票。接下来,给那个人发消息,以便他们解释。不是每个人都能给出原因。
      猜你喜欢
      • 1970-01-01
      • 2010-09-16
      • 2018-02-27
      • 2014-03-26
      • 2012-10-04
      • 1970-01-01
      • 2020-10-31
      • 2013-02-24
      • 2012-03-16
      相关资源
      最近更新 更多