2012-07-06 46 views
27

我試圖按照 This link中的建議將錯誤返回給控制器的調用,以便客戶端可以採取適當的措施。 控制器通過jquery AJAX通過javascript調用。只有當我沒有將狀態設置爲錯誤時,我纔會返回Json對象。 下面是示例代碼返回帶有錯誤狀態碼MVC的JSON

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

我得到JSON的,如果我不設置的StatusCode。 如果我設置了狀態碼,我會返回狀態碼,但不會返回Json錯誤對象。

更新 我想發送一個Error對象作爲JSON,以便它可以處理ajax的錯誤回調。

回答

26

我找到了解決辦法here

我不得不創建一個動作過濾器來覆蓋MVC

這裏的默認行爲是我的異常類

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) { } 
} 

請注意,我有構造函數初始化我的JSON。這裏是動作過濾器

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

現在,我有行動過濾器,我來裝飾我的控制器與過濾器屬性

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

當錯誤被拋出的動作過濾器,它實現個IExceptionFilter被調用和我在錯誤回調中返回客戶端上的Json。

+10

如果讀者認爲「所有必要?」,答案是「否」。 - 我和@Sarath處於相同的情況,並希望返回一個HTTP錯誤代碼和一些描述錯誤的JSON數據。事實證明,我可以只使用清除響應的行,IIS自定義錯誤將被跳過,並且狀態碼已被佔用。我將這3行放在我的控制器的Action中,在這3行之後,我只是像往常一樣返回我的JSON數據。像魅力一樣工作。 – 2013-02-10 16:17:02

+6

事實確實如此,但爲了可重複使用,您可能希望按照答案的指示進行操作,而不是將相同的代碼複製/過濾到每個操作中。 – Hades 2013-06-06 15:35:39

+0

如果我設置了'StatusCode = 500',那麼它會忽略我的JsonResponse,而是返回「頁面無法顯示,因爲發生了內部服務器錯誤。」。不知道這是由於OWIN管道中的差異還是由於什麼。 – AaronLS 2016-04-21 19:36:33

4

你必須返回設置的StatusCode後JSON錯誤對象自己,像這樣......

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

另一種方法是有一個JsonErrorModel和填充它

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 
} 

看看答案here以及

+4

我已經有響應對象的錯誤。問題是我得到「錯誤的請求」,而不是JSON對象。如果我沒有設置狀態,我會得到帶有錯誤的JSON,但客戶端並不知道它是一個異常情況。 – Sarath 2012-07-06 22:50:52

+0

@Sarath檢查答案中的鏈接。你需要在jQuery – 2012-07-07 14:55:05

+1

中使用ajax方法的error屬性,我所面臨的問題是如果我設置了狀態,那麼在響應中我不會返回JSON。你指出的答案是我到底在做什麼。問題是如果我設置響應狀態我沒有得到JSON。 – Sarath 2012-07-07 19:48:58

4

您需要決定是否想要「HTTP級別錯誤」(即哪些錯誤代碼適用)或「應用程序級別錯誤」(即w你自定義的JSON響應是爲了)。

如果錯誤代碼設置爲非2xx(成功範圍),則使用HTTP的大多數高級對象都不會查看響應流。在你的情況下,你明確地設置錯誤代碼爲失敗(我認爲403或500)並強制XMLHttp對象忽略響應的主體。

修復 - 處理客戶端的錯誤條件或不設置錯誤代碼並返回帶有錯誤信息的JSON(詳見Sbossb回覆)。

+1

感謝您的回覆。客戶如何知道有一個例外,我沒有設置狀態碼? – Sarath 2012-07-06 22:47:29

+0

@Sarath,與你現在在服務器端(假設JavaScript客戶端)正在做同樣的檢查'response.errors && response.errors.length> 0'。 – 2012-07-06 22:51:32

+2

@Alexi是的。但我想隱式通知客戶發生錯誤。也就是說,我想處理這個失敗的Ajax調用回調而不是成功的回調,然後查找errors.length。 – Sarath 2012-07-06 23:00:42

17

這個問題有一個非常優雅的解決方案,只需通過網站配置您的網站。配置:

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

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

+1

BOOM!我正在尋找的答案。它在本地很好,但不在遠程服務器上。我知道這可以通過一些配置設置來完成。乾杯! – ThiagoPXP 2015-12-08 07:40:06

+0

絕對試試這個,如果它在當地工作但不是天藍色! – Icycool 2017-01-06 20:29:30

+0

對於問題是,我在本地(開發)機器中獲取StatusCode和Json響應,但從生產中運行它時,我只是獲取StatusCode。 這個解決方案是最簡單的解決方案。 – Vikneshwar 2018-01-18 05:14:40

2

如果你的需求是不一樣複雜薩拉特的你可以逃脫的東西更簡單:

[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

最巧妙的解決方案,我發現是創建自己的JsonResult,它擴展了原始實現並允許指定一個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); 
    } 
} 

你可以在你的控制器動作,然後用這個像這樣:從理查德·加賽德答案

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

大廈,這裏的ASP.Net Core版本

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

然後在你的控制器,作爲回報如下:

// 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

謝謝你。 – aman 2018-01-30 15:39:40