想拋就拋:Application_Error中統一處理ajax請求執行中拋出的異常

女友不是想拋就拋,但異常卻能夠,不信請往下看。html

今天在MVC Controller中寫代碼時,糾結了一下:ajax

public async Task<ActionResult> Save(int? postId)
{
    if(!IsOwner(postId.Value, userId))
    {                    
        //拋不拋異常呢?
    }
}

在這個地方要不要拋異常呢?json

若是不拋異常,就得這麼寫:app

public async Task<ActionResult> Save(int? postId)
{
    if(!IsOwner(postId.Value, userId))
    {
        return Json(new {
            isSuccess = false,
            message = "嘗試執行未經受權的操做" });
    }
}

並且一般在這樣的狀況下,還須要記錄日誌,因而代碼變成:async

if(!IsOwner(postId.Value, userId))
{
    Logger.Default.Info("UnauthorizedSave", "...");
    return Json(new {
        isSuccess = false,
        message = "嘗試執行未經受權的操做" });
}

若是拋異常呢,代碼就能夠這麼寫:post

if(IsOwner(postId.Value, userId))
{                    
    throw new UnauthorizedAccessException();
}

代碼顯得更簡潔,更具表達力,並且記錄錯誤日誌能夠在Application_Error中統一處理:url

protected void Application_Error(Object sender, EventArgs e)
{
    var lastError = Server.GetLastError();
    if (lastError != null)
    {                
        Logger.Default.Error("Application_Error", lastError);               
        Response.StatusCode = 500;
        Server.ClearError();
    }
}

但這會帶來一個問題,客戶端收到的將是自定義500錯誤頁面的html代碼,不只沒有具體的錯誤信息,並且在ajax回調時還要額外處理,而一般咱們最期待的是一個json格式的返回結果。spa

因而要想實現「想拋就拋」,就必須解決:如何在Application_Error中統一處理ajax請求處理過程當中產生的異常,並將之轉換成json格式的響應內容返回給客戶端。日誌

分解一下,就變成了2個問題:code

1)如何在Application_Error中判斷一個請求是不是ajax請求?

今天上午經過MVC的擴展方法IsAjaxRequest解決了,詳見如何在Global.asax中判斷是不是ajax請求

if ((new HttpRequestWrapper(Request)).IsAjaxRequest())
{
} 

2)如何生成json格式的響應內容並返回給客戶端?

這個能夠經過Json.NET+Response.Write來解決,代碼以下:

Response.Clear();
Response.ContentType = "application/json; charset=utf-8";
Response.Write(Newtonsoft.Json.JsonConvert.SerializeObject(
    new { isSuccess = false, message = lastError.Message }));
Response.Flush();

最終實現「想拋就拋」的代碼以下:

protected void Application_Error(Object sender, EventArgs e)
{
    var lastError = Server.GetLastError();
    if (lastError != null)
    {           
        CNBlogs.Infrastructure.Logging.Logger.Default.Error("Application_Error", lastError);

        if(Request != null && (new HttpRequestWrapper(Request)).IsAjaxRequest())
        {                    
            Response.Clear();
            Response.ContentType = "application/json; charset=utf-8";
            Response.Write(Newtonsoft.Json.JsonConvert.SerializeObject(
                new { isSuccess = false, message = lastError.Message }));
            Response.Flush();
            Server.ClearError();
            return;
        }

        Response.StatusCode = 500;
        Server.ClearError();
    }
}

ajax客戶端收到的結果以下:

 今後,能夠盡情地拋異常了。

相關文章
相關標籤/搜索