2012-07-06 40 views
27

Tôi đã cố gắng trả lại lỗi cho cuộc gọi tới bộ điều khiển như được thông báo trong This link để khách hàng có thể thực hiện hành động thích hợp. Bộ điều khiển được gọi là javascript qua jquery AJAX. Tôi chỉ nhận được đối tượng Json nếu tôi không đặt trạng thái thành lỗi. Đây là mẫu mãTrả về JSON có mã trạng thái lỗi MVC

if (response.errors.Length > 0) 
    Response.StatusCode = (int)HttpStatusCode.BadRequest; 
return Json(response); 

tôi nhận được Json nếu tôi không đặt statusCode. Nếu tôi đặt mã trạng thái, tôi nhận lại mã trạng thái nhưng không nhận được đối tượng lỗi Json.

Cập nhật Tôi muốn gửi đối tượng Lỗi dưới dạng JSON để có thể xử lý lỗi gọi lại của ajax.

Trả lời

26

Tôi tìm thấy giải pháp here

tôi đã phải tạo ra một bộ lọc hành động để ghi đè lên hành vi mặc định của MVC

Dưới đây là lớp ngoại lệ của tôi

class ValidationException : ApplicationException 
{ 
    public JsonResult exceptionDetails; 
    public ValidationException(JsonResult exceptionDetails) 
    { 
     this.exceptionDetails = exceptionDetails; 
    } 
    public ValidationException(string message) : base(message) { } 
    public ValidationException(string message, Exception inner) : base(message, inner) { } 
    protected ValidationException(
    System.Runtime.Serialization.SerializationInfo info, 
    System.Runtime.Serialization.StreamingContext context) 
     : base(info, context) { } 
} 

Lưu ý rằng tôi có constructor mà khởi JSON của tôi. Dưới đây là bộ lọc hành động

public class HandleUIExceptionAttribute : FilterAttribute, IExceptionFilter 
{ 
    public virtual void OnException(ExceptionContext filterContext) 
    { 
     if (filterContext == null) 
     { 
      throw new ArgumentNullException("filterContext"); 
     } 
     if (filterContext.Exception != null) 
     { 
      filterContext.ExceptionHandled = true; 
      filterContext.HttpContext.Response.Clear(); 
      filterContext.HttpContext.Response.TrySkipIisCustomErrors = true; 
      filterContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError; 
      filterContext.Result = ((ValidationException)filterContext.Exception).myJsonError; 
     } 
    } 

Bây giờ tôi có bộ lọc hành động, tôi sẽ trang trí điều khiển của tôi với các thuộc tính lọc

[HandleUIException] 
public JsonResult UpdateName(string objectToUpdate) 
{ 
    var response = myClient.ValidateObject(objectToUpdate); 
    if (response.errors.Length > 0) 
    throw new ValidationException(Json(response)); 
} 

Khi lỗi được ném lọc hành động mà thực hiện IExceptionFilter được gọi và Tôi lấy lại Json trên máy khách về lỗi gọi lại.

+10

Trong trường hợp người đọc đang nghĩ "Có phải tất cả những gì cần thiết không?", Câu trả lời là "không". - Tôi đã ở trong tình trạng tương tự như @Sarath và muốn trả lại mã lỗi HTTP và một số dữ liệu JSON mô tả lỗi. Nó bật ra tôi chỉ có thể sử dụng các dòng nơi phản ứng đã được xóa, lỗi tùy chỉnh IIS được bỏ qua và mã trạng thái được ngồi. Tôi đặt 3 dòng đó vào Action của mình trên Controller, và sau 3 dòng đó, tôi vừa trả về dữ liệu JSON của mình như bình thường. Làm việc như người ở. –

+6

Thực ra đó là sự thật, nhưng để có thể tái sử dụng, bạn sẽ muốn làm như câu trả lời cho biết thay vì sao chép/dán cùng một mã vào mỗi hành động. – Hades

+0

Nếu tôi đặt 'StatusCode = 500' thì nó bỏ qua JsonResponse của tôi và thay vào đó trả về" Trang không thể được hiển thị vì đã xảy ra lỗi máy chủ nội bộ ". Không chắc chắn nếu điều này là do sự khác biệt trong đường ống OWIN hoặc cái gì. – AaronLS

4

Bạn phải trả lại JSON lỗi phản đối chính mình sau khi cài đặt StatusCode, như vậy ...

if (BadRequest) 
{ 
    Dictionary<string, object> error = new Dictionary<string, object>(); 
    error.Add("ErrorCode", -1); 
    error.Add("ErrorMessage", "Something really bad happened"); 
    return Json(error); 
} 

Một cách khác là phải có một JsonErrorModel và cư nó

public class JsonErrorModel 
{ 
    public int ErrorCode { get; set;} 

    public string ErrorMessage { get; set; } 
} 

public ActionResult SomeMethod() 
{ 

    if (BadRequest) 
    { 
     var error = new JsonErrorModel 
     { 
      ErrorCode = -1, 
      ErrorMessage = "Something really bad happened" 
     }; 

     return Json(error); 
    } 

    //Return valid response 
} 

Hãy nhìn vào câu trả lời here cũng như

+4

Tôi đã gặp lỗi trong đối tượng phản hồi. Vấn đề là tôi nhận được "Yêu cầu không hợp lệ" chứ không phải đối tượng JSON. Nếu tôi không thiết lập trạng thái tôi nhận được JSON có lỗi nhưng khách hàng không biết rằng đó là một điều kiện ngoại lệ. – Sarath

+0

@Sarath Kiểm tra liên kết trong câu trả lời. Bạn cần phải sử dụng thuộc tính lỗi của phương thức ajax trong JQuery –

+1

vấn đề mà tôi đang gặp phải là trên phản hồi, tôi không nhận lại JSON nếu tôi đặt trạng thái. Câu trả lời bạn chỉ là chính xác tôi đang làm gì. Vấn đề là nếu tôi đặt trạng thái phản hồi, tôi không nhận được JSON. – Sarath

4

Bạn cần quyết định xem bạn có muốn "lỗi cấp HTTP" không (là mã lỗi nào) hoặc "lỗi cấp ứng dụng" (w mũ đáp ứng JSON tùy chỉnh của bạn là dành cho).

Hầu hết các đối tượng cấp cao sử dụng HTTP sẽ không bao giờ xem xét luồng phản hồi nếu mã lỗi được đặt thành thứ không phải là 2xx (phạm vi thành công). Trong trường hợp của bạn, bạn đang thiết lập rõ ràng mã lỗi thành thất bại (tôi nghĩ 403 hoặc 500) và buộc đối tượng XMLHttp bỏ qua phần thân của phản hồi.

Để khắc phục - xử lý các điều kiện lỗi về phía máy khách hoặc không đặt mã lỗi và trả về JSON với thông tin lỗi (xem trả lời Sbossb để biết chi tiết).

+1

Cảm ơn bạn đã trả lời ur. Làm cách nào để khách hàng biết rằng có một ngoại lệ, tôi không đặt mã trạng thái? – Sarath

+0

@Sarath, Kiểm tra tương tự 'response.errors && response.errors.length> 0' như bạn hiện đang làm ở phía máy chủ (giả sử trình khách JavaScript). –

+2

@Alexi Có. Nhưng tôi muốn ngầm thông báo cho khách hàng rằng đã xảy ra lỗi. Đó là để nói rằng tôi muốn xử lý tình trạng này trên callback thất bại của cuộc gọi ajax thay vì gọi lại thành công và sau đó tìm lỗi.length. – Sarath

17

Có một giải pháp rất thanh lịch cho vấn đề này, chỉ cần định cấu hình trang web của bạn qua web.cấu hình:

<system.webServer> 
    <httpErrors errorMode="DetailedLocalOnly" existingResponse="PassThrough"/> 
</system.webServer> 

Nguồn: https://serverfault.com/questions/123729/iis-is-overriding-my-response-content-if-i-manually-set-the-response-statuscode

+1

BOOM! Câu trả lời tôi đang tìm kiếm. Nó làm việc tốt cho tôi tại địa phương nhưng không phải trong máy chủ từ xa. Tôi biết nó có thể được thực hiện với một số cài đặt cấu hình. Chúc mừng! – ThiagoPXP

+0

Chắc chắn thử điều này nếu nó hoạt động ở địa phương nhưng không phải là xanh! – Icycool

+0

Đối với vấn đề là, tôi đã nhận được StatusCode và Json Response trong máy cục bộ (dev), nhưng trong khi chạy nó từ sản xuất, tôi đã nhận được chỉ là StatusCode. Giải pháp này là bằng cách dễ dàng nhất. – Vikneshwar

2

Và nếu nhu cầu của bạn không phải là phức tạp như Sarath của bạn có thể nhận được ngay với một cái gì đó thậm chí đơn giản hơn:

[MyError] 
public JsonResult Error(string objectToUpdate) 
{ 
    throw new Exception("ERROR!"); 
} 

public class MyErrorAttribute : FilterAttribute, IExceptionFilter 
{ 
    public virtual void OnException(ExceptionContext filterContext) 
    { 
     if (filterContext == null) 
     { 
     throw new ArgumentNullException("filterContext"); 
     } 
     if (filterContext.Exception != null) 
     { 
     filterContext.ExceptionHandled = true; 
     filterContext.HttpContext.Response.Clear(); 
     filterContext.HttpContext.Response.TrySkipIisCustomErrors = true; 
     filterContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError; 
     filterContext.Result = new JsonResult() { Data = filterContext.Exception.Message }; 
     } 
    } 
} 
6

Các giải pháp thú vị nhất tôi đã tìm thấy là tạo JsonResult của riêng bạn để mở rộng triển khai ban đầu và cho phép bạn chỉ định một HttpStatusCode:

public class JsonHttpStatusResult : JsonResult 
{ 
    private readonly HttpStatusCode _httpStatus; 

    public JsonHttpStatusResult(object data, HttpStatusCode httpStatus) 
    { 
     Data = data; 
     _httpStatus = httpStatus; 
    } 

    public override void ExecuteResult(ControllerContext context) 
    { 
     context.RequestContext.HttpContext.Response.StatusCode = (int)_httpStatus; 
     base.ExecuteResult(context); 
    } 
} 

Sau đó bạn có thể sử dụng trong hành động điều khiển của bạn như sau:

if(thereWereErrors) 
{ 
    var errorModel = new { error = "There was an error" }; 
    return new JsonHttpStatusResult(errorModel, HttpStatusCode.InternalServerError); 
} 
3

xây dựng trên câu trả lời từ Richard Garside, đây là phiên bản ASP.Net Lõi

public class JsonErrorResult : JsonResult 
{ 
    private readonly HttpStatusCode _statusCode; 

    public JsonErrorResult(object json) : this(json, HttpStatusCode.InternalServerError) 
    { 
    } 

    public JsonErrorResult(object json, HttpStatusCode statusCode) : base(json) 
    { 
     _statusCode = statusCode; 
    } 

    public override void ExecuteResult(ActionContext context) 
    { 
     context.HttpContext.Response.StatusCode = (int)_statusCode; 
     base.ExecuteResult(context); 
    } 

    public override Task ExecuteResultAsync(ActionContext context) 
    { 
     context.HttpContext.Response.StatusCode = (int)_statusCode; 
     return base.ExecuteResultAsync(context); 
    } 
} 

Sau đó, trong điều khiển của bạn, trở lại như sau:

// Set a json object to return. The status code defaults to 500 
return new JsonErrorResult(new { message = "Sorry, an internal error occurred."}); 

// Or you can override the status code 
return new JsonErrorResult(new { foo = "bar"}, HttpStatusCode.NotFound); 
+1

Cảm ơn vì điều này. – aman

Các vấn đề liên quan