2011-01-16 187 views
106

當jquery ajax調用操作時,如何處理控制器中拋出的異常?ASP.NET MVC Ajax錯誤處理

例如,我想要一個全局JavaScript代碼,它在ajax調用期間執行任何類型的服務器異常,如果在調試模式下或只是一個正常的錯誤消息,它會顯示異常消息。

在客戶端,我會調用ajax錯誤的函數。

在服務器端,我是否需要編寫自定義actionfilter?

+8

查看[beckelmans post](http://beckelman.net/post/2010/03/18/Handling-Errors-During-Ajax-Calls-With-ASPNET-MVC.aspx)就是一個很好的例子。達林斯對這篇文章的回答很好,但不要爲錯誤設置正確的狀態代碼。 – Dan

+6

不幸的是,現在鏈接已斷開 –

+1

這是鏈接在回機器上的鏈接:https://web.archive.org/web/20111011105139/http://beckelman.net/post/2010/03/18/Handling-Errors-期間-Ajax-Calls-With-ASPNET-MVC.aspx – BruceHill

回答

151

如果服務器發送超過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'回調。 –

+0

謝謝,完美,正是我在尋找的。 –

0

對於來自客戶端上的Ajax調用處理錯誤,分配的功能,Ajax調用的error選項。

要全局設置默認值,可以使用此處描述的函數: http://api.jquery.com/jQuery.ajaxSetup

+0

我4年前給出的答案突然得到了否決票?任何人都在乎給出一個理由? –

+1

聯繫SOF,並要求他們的DBA查詢誰給了反對票。接下來,消息,個人,他們可以解釋。不僅任何人都可以給出原因。 – JoshYates1980

69

谷歌搜索後,我寫了一個簡單的異常處理基於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> 

最後,你應該打開自定義錯誤。 ,然後享受它:)

+0

我可以在Firebug中看到錯誤,但它不會重定向到錯誤頁面。 – user2067567

+1

感謝您的支持!應該被標記爲答案IMO作爲其對ajax請求的過濾,並繼承正確的類而不是HandleErrorAttribute繼承 –

+2

精彩的回答! :D –

2

我做了一個快速的解決方案,因爲我時間不夠,它運作良好。雖然我認爲更好的選擇是使用異常過濾器,也許我的解決方案可以在需要簡單解決方案的情況下提供幫助。

我做了以下事情。在控制器方法我返回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

9

不幸的是,這兩個答案都不適合我。令人驚訝的是,解決方案要簡單得多。從控制器返回:

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

和處理它作爲客戶端的標準HTTP錯誤,只要你喜歡。

+0

代碼片段中的「e」是什麼意思? –

+0

@Will Huang:異常實例的名稱 – schmendrick

+0

我必須將第一個參數強制轉換爲int。另外,當我這樣做時,結果被傳遞給'ajax''成功'處理程序,而不是'error'處理程序。這是預期的行爲? –

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

希望這可以幫助其他人!