ASP.NET MVC Ajax错误处理


117

当jquery ajax调用动作时,如何处理控制器中引发的异常?

例如,我想要一个全局javascript代码,该代码将在ajax调用期间在任何类型的服务器异常上执行,如果在调试模式下则显示异常消息,或者仅显示普通错误消息。

在客户端,我将在ajax错误上调用一个函数。

在服务器端,我是否需要编写自定义actionfilter?


8
参见beckelmans帖子中的一个很好的例子。Darins对此帖子的回答是好的,但请不要为错误设置正确的状态代码。

6
令人遗憾的是,现在该链接已断开
克里斯·内维尔

1
这是
Wayback

Answers:


161

如果服务器发送了一些不同于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
    }
});

1
谢谢,这是我一直在寻找的。因此,对于asp.net mvc异常,有没有一种特定的方法需要我将其抛出,以便它可以被jquery错误处理程序捕获?
肖恩·麦克林

1
@Lol编码器,无论您如何在控制器操作内引发异常,服务器都将返回500状态代码并执行error回调。
Darin Dimitrov

谢谢,完美,正是我想要的。
肖恩·麦克林

1
状态码500会不会是错误的?引用这一章的broadcast.oreilly.com/2011/06/…:“未能意识到4xx错误意味着我搞砸了,而5xx意味着您搞砸了”-我是客户端,而您是服务器。
克里斯·内维尔

这个答案对新版本的ASPNET仍然有效吗?
gog 2015年

73

谷歌搜索后,我基于MVC操作筛选器编写了一个简单的异常处理:

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中看到错误,但是它没有重定向到“错误”页面。
user2067567 2013年

1
谢谢你!应该将其标记为答案IMO,因为它对ajax请求进行了过滤,并继承了正确的类,而不是HandleErrorAttribute继承的类
mtbennett 2013年

2
很棒的答案!:D
Leniel Maccaferri 2014年

1
我认为“ Request.IsAjaxRequest()”有时不太可靠。
黄将

对于调试配置,它始终可以工作,但在发布配置中却不能始终工作并返回html,而有人在这种情况下有解决方法吗?
希滕德拉

9

不幸的是,没有一个答案对我有好处。令人惊讶的是,解决方案要简单得多。从控制器返回:

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

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


@Will Huang:异常实例的名称
schmendrick

我必须将第一个论点投给int。另外,当我这样做时,结果将传递给ajax success处理程序,而不是error处理程序。这是预期的行为吗?
乔纳森·伍德

4

我做了一个快速的解决方案,因为我没有时间,而且还可以。尽管我认为更好的选择是使用异常过滤器,但是在需要简单解决方案的情况下,也许我的解决方案可以提供帮助。

我做了以下。在控制器方法中,我返回了一个JsonResult,其数据内部具有属性“ Success”:

    [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


4

与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.
    }
});

希望这对别人有帮助!


0

为了处理客户端上来自ajax调用的错误,可以将一个函数分配给errorajax调用的选项。

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


我4年前给出的答案突然遭到了否决?有人在乎为什么吗?
Brian Ball

1
请与SOF联系,并要求其DBA查询谁给了否定票。接下来,向个人发送消息,以便他们进行解释。不仅任何人都可以给出原因。
JoshYates1980 '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.