文章出處

女朋友不是想拋就拋,但異常卻可以,不信請往下看。

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

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

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

如果不拋異常,就得這么寫:

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

而且通常在這樣的情況下,還需要記錄日志,于是代碼變成:

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

如果拋異常呢,代碼就可以這么寫:

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

代碼顯得更簡潔,更具表達力,而且記錄錯誤日志可以在Application_Error中統一處理:

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格式的返回結果。

于是要想實現“想拋就拋”,就必須解決:如何在Application_Error中統一處理ajax請求處理過程中產生的異常,并將之轉換成json格式的響應內容返回給客戶端。

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

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客戶端收到的結果如下:

 從此,可以盡情地拋異常了。


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()