ASP.NET MVC 錯誤處理

  • 1142
  • 0

ASP.NET MVC 錯誤處理

Handling Exceptions

這篇整理得很好:http://iamlevi.net/asp-net-mvc-4-ways-handle-exceptions/

常見的5種方法:

  1. Writing try..catch
  2. Override OnException method inside the Controller
  3. Using the HandleError attribute
  4. Extending the HandleError attribute
  5. Handle all errors inside Global.asax

作者結論:There is no good or bad way to handle exceptions inside ASP.NET MVC 4. Each implementation has some good and bad sides.

這裡面我最想跳過的方法是try..catch,就像作者說的,缺點是到處都是try..catch,寫起來就煩阿~

第3點最簡單,但卻無法紀錄Error Log. (所以才有第4點阿~)

以上都有2種範例:轉到Error Page(ActionResult),或者回傳Json資料告訴前端(Ajax呼叫之類的...)發生錯誤了。

在範例中,作者沒有寫到Error Log作法,如Nlog, Log4NET, Enterprise Library Logging Application Block 之類,

若大家有興趣,<ASP.NET MVC 4 網站開發美學> 這本書第八章有介紹Elmah, Nlog,大家可以參考一下,或者網路上也有很多資源可以找找。

 

在那篇文章中,「Override OnException method inside the Controller 」這方法會先判斷Exception是否有被處理,若沒被處理過,就用自己設定的錯誤處理方式(紀錄Log、轉到指定頁面、JsonResult 處理....)。

若之前沒有在Web.config 加上 <customErrors mode="On">,錯誤處理會正常執行,但若加上了<customErrors mode="On">,表示exception在OnException method 之前就已經被捕捉到,所以判斷

   1: if (filterContext.ExceptionHandled)

都永遠是true。

所以若要自訂的OnException 發生作用,記得要拿掉<customErrors> 項目。

 

404 Error 處理

在保哥那本<ASP.NET MVC4開發實戰>書中,有提到找不到Action時的處理方式:複寫Controller 的HandleUnknownAction()

不過這個方法只限定Action找不到時才會有用... 若連Controller name都有錯,還是會出現預設的404錯誤頁面:

404


在網路上大部分介紹404處理方式,大都是在web.config加上<customErrors> 項目。

   1: <customErrors mode="On">
   2:   <error redirect="~/Error/Error404" statusCode="404" />
   3: </customErrors>

但用這方法,就會跟上面自訂的 OnException() 不和...

 

所以,若要自訂OnException() ,又不想加上<customErrors> 項目,但卻要處理404錯誤...

請參考下面那篇文章,在Global.asax加上Application_Error()

注意,原始範例中並沒有 Response.ContentType = "text/html"; 這行,那導致404錯誤頁面會以Source Code-純文字Html原始碼方式輸出。

不過討論中有人回覆加上這行就解決了~

http://stackoverflow.com/questions/5226791/custom-error-pages-on-asp-net-mvc3/5229581#5229581

   1: protected void Application_Error()
   2: {
   3:     var exception = Server.GetLastError();
   4:     var httpException = exception as HttpException;
   5:     Response.Clear();
   6:     Server.ClearError();
   7:     var routeData = new RouteData();
   8:     routeData.Values["controller"] = "Error";
   9:     routeData.Values["action"] = "Error";
  10:     routeData.Values["exception"] = exception;
  11:     Response.ContentType = "text/html";
  12:     Response.StatusCode = 500;
  13:     if (httpException != null)
  14:     {
  15:         Response.StatusCode = httpException.GetHttpCode();
  16:         switch (Response.StatusCode)
  17:         {
  18:             case 404:
  19:                 routeData.Values["action"] = "PageNotFound";
  20:                 break;
  21:         }
  22:     }
  23:  
  24:     IController errorsController = new NetFlow2.Controllers.ErrorController();
  25:     var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
  26:     errorsController.Execute(rc);
  27: }

 

補充一下:

這兩天開發時,發現網址打錯,竟然不會導到自訂的錯誤頁面,而是秀出跟HttpNotFound()一樣的錯誤頁面:

Snap1

開了Nlog、Elma的記錄檔,都沒有任何資料...

找了好久,我才想到Error錯誤頁面也有套用Layout,而前幾天剛好在Layout上加了一個ViewData[“使用者”].toString(),當自訂的錯誤頁面套用Layout時,因為ViewData[“使用者”]是null,所以toString()時發生了錯誤!

唉,寫程式習慣不好,又沒辦法一步一步偵錯找出問題,真的只能用猜的...

 

番外篇:

之前MVC4 由Template 產生出來的Controller,常常可以看到類似這樣一段程式:


if data == null)
{
    return HttpNotFound();
}

那時沒有好好讀書,也傻傻的這樣用下去...

當找不到資料時,噴給User看的話結果就是:

Snap1

 

這樣一定不行的,使用者一看到這鬼畫面,馬上就會打來K人!

所以現學現賣,加個錯誤處理[HandleError],想讓畫面導到Error Page,「友善地」告訴使用者系統有問題找不到資料,看他們打來罵人會不會溫柔點~


public ActionResult Index()
{
    if data == null)
    {
        return HttpNotFound();
    }
}

結果呢...當找不到資料時,還是一樣的錯誤畫面!

這時...若你跟我一樣疑惑,請打自己兩巴掌!清醒點後,再打開MSDN查說明文件。

[HandleError]  是拿來處理錯誤的,也就是當例外發生時,才會有作用。HttpNotFound() 只會回傳一個HttpNotFoundResult 物件(外加把HTTP status code設定為404),又不是丟回錯誤例外,當然不會轉到Error Page!

結論是...大家應該自己寫個Method(),取代HttpNotFound(),當找不到資料時,轉到自訂的訊息頁面。或者寫個錯誤訊息(如使用 ModelState.AddModelError),回到前端畫面通知使用者。(若不想改HttpNotFound(),應該也可以在IIS設定,當捕捉到404錯誤時,要轉到哪個頁面...)