ASP.NET MVC Ajax Xử lý lỗi


117

Làm cách nào để xử lý các ngoại lệ được đưa ra trong bộ điều khiển khi jquery ajax gọi một hành động?

Ví dụ: tôi muốn một mã javascript toàn cục được thực thi trên bất kỳ loại ngoại lệ máy chủ nào trong khi gọi ajax sẽ hiển thị thông báo ngoại lệ nếu ở chế độ gỡ lỗi hoặc chỉ là thông báo lỗi bình thường.

Về phía máy khách, tôi sẽ gọi một hàm về lỗi ajax.

Ở phía máy chủ, Tôi có cần viết một bộ lọc hành động tùy chỉnh không?


8
Xem bài đăng của beckelmans để biết một ví dụ điển hình. Câu trả lời của Darins cho bài đăng này là tốt nhưng không đặt mã trạng thái chính xác để xảy ra lỗi.
Dan

6
Đáng buồn là liên kết mà bây giờ bị phá vỡ
Chris Nevill

1
Dưới đây là liên kết trên máy Wayback: web.archive.org/web/20111011105139/http://beckelman.net/post/...
BruceHill

Câu trả lời:


161

Nếu máy chủ gửi một số mã trạng thái khác với 200, thì lệnh gọi lại lỗi sẽ được thực thi:

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

và để đăng ký một trình xử lý lỗi chung, bạn có thể sử dụng $.ajaxSetup()phương pháp:

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

Một cách khác là sử dụng JSON. Vì vậy, bạn có thể viết một bộ lọc hành động tùy chỉnh trên máy chủ để bắt ngoại lệ và chuyển chúng thành phản hồi 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
        };
    }
}

và sau đó trang trí hành động bộ điều khiển của bạn với thuộc tính này:

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

và cuối cùng gọi nó:

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

1
Cảm ơn vì điều này, Cái sau là những gì tôi đang tìm kiếm. Vì vậy, đối với ngoại lệ mvc asp.net, có cách nào cụ thể mà tôi cần ném nó để nó có thể bị trình xử lý lỗi jquery bắt không?
Shawn Mclean

1
@Lol coder, bất kể bạn ném một ngoại lệ như thế nào bên trong hành động của bộ điều khiển, máy chủ sẽ trả về mã trạng thái 500 và lệnh errorgọi lại sẽ được thực thi.
Darin Dimitrov

Cảm ơn, hoàn hảo, đúng như những gì tôi đang tìm kiếm.
Shawn Mclean

1
Mã Trạng thái 500 sẽ không sai chứ? Để trích dẫn chương này broadcast.oreilly.com/2011/06/… : "Không nhận ra rằng lỗi 4xx có nghĩa là tôi đã làm sai và 5xx có nghĩa là bạn đã làm sai" - nơi tôi là khách hàng và bạn là máy chủ.
Chris Nevill

Câu trả lời này vẫn hợp lệ cho các phiên bản mới hơn của ASPNET?
gog

73

Sau khi googling, tôi viết một phân phối Ngoại lệ đơn giản dựa trên Bộ lọc Hành động 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);
        }
    }
}

và viết trong global.ascx:

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

và sau đó viết tập lệnh này trên bố cục hoặc trang Chính:

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

Cuối cùng bạn nên bật tùy chỉnh lỗi. và sau đó tận hưởng nó :)


Tôi có thể thấy lỗi trong Firebug nhưng nó không chuyển hướng đến trang Lỗi.?
user2067567

1
Cảm ơn vì điều đó! nên được đánh dấu là câu trả lời IMO như lọc của nó đối với các yêu cầu ajax và kế thừa lớp đúng hơn là những gì mà kế thừa HandleErrorAttribute
mtbennett

2
Câu trả lời tuyệt vời! : D
Leniel Maccaferri

1
Tôi nghĩ rằng "Request.IsAjaxRequest ()" đôi khi không đáng tin cậy.
Will Huang

Đối với cấu hình gỡ lỗi, nó luôn hoạt động nhưng không hoạt động luôn trong cấu hình Phát hành & trả về html thay vào đó có ai có giải pháp cho trường hợp như vậy không?
Hitendra

9

Thật không may, không có câu trả lời nào là tốt cho tôi. Đáng ngạc nhiên là giải pháp đơn giản hơn nhiều. Trở lại từ bộ điều khiển:

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

Và xử lý nó như lỗi HTTP tiêu chuẩn trên máy khách theo ý muốn.


@Will Huang: tên của trường hợp ngoại lệ
schmendrick

Tôi phải bỏ đối số đầu tiên int. Ngoài ra, khi tôi làm điều này, kết quả được chuyển cho ajax successtrình xử lý chứ không phải errortrình xử lý. Đây có phải là hành vi dự kiến?
Jonathan Wood

4

Tôi đã thực hiện một giải pháp nhanh chóng vì tôi thiếu thời gian và nó hoạt động tốt. Mặc dù tôi nghĩ lựa chọn tốt hơn là sử dụng Bộ lọc ngoại lệ, có lẽ giải pháp của tôi có thể giúp ích trong trường hợp cần một giải pháp đơn giản.

Tôi đã làm như sau. Trong phương pháp bộ điều khiển, tôi trả về một JsonResult có thuộc tính "Thành công" bên trong Dữ liệu:

    [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 }, };
    }

Sau đó trong cuộc gọi ajax, tôi chỉ yêu cầu thuộc tính này để biết liệu tôi có ngoại lệ hay không:

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

Hi vọng điêu nay co ich. Chúc bạn code vui vẻ! : P


4

Đồng ý với câu trả lời của aleho, đây là một ví dụ đầy đủ. Nó hoạt động giống như một sự quyến rũ và siêu đơn giản.

Mã điều khiển

[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);
        }
    }
}

Mã Javascript trong chế độ xem

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

Hy vọng điều này sẽ giúp người khác!


0

Để xử lý lỗi từ lệnh gọi ajax ở phía máy khách, bạn chỉ định một chức năng cho errortùy chọn của lệnh gọi ajax.

Để đặt mặc định trên toàn cầu, bạn có thể sử dụng chức năng được mô tả tại đây: http://api.jquery.com/jQuery.ajaxSetup .


Một câu trả lời mà tôi đã đưa ra cách đây hơn 4 năm bỗng nhiên bị bỏ phiếu? Bất cứ ai quan tâm để cung cấp cho một lý do tại sao?
Brian Ball

1
Liên hệ với SOF và yêu cầu DBA của họ truy vấn xem ai đã bỏ phiếu phản đối. Tiếp theo, hãy nhắn tin cho cá nhân đó để họ có thể giải thích. Không chỉ ai cũng có thể đưa ra lý do tại sao.
JoshYates1980,
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.