我幾乎每次在 ASP.NET 的教學場合裡都會提到在 ASP.NET MVC 專案中安裝 ELMAH (Error Logging Modules and Handlers) 的重要性,不僅僅是在開發環境或測試環境能夠收錄完整的錯誤訊息,即便在正式運行的網站也非常適合安裝 ELMAH 錯誤記錄模組。不過,當 ASP.NET MVC 網站的 web.config 設定為 <customError mode="On" /> 的情況下,由於 ASP.NET MVC 專案預設都會套用 HandleErrorAttribute 全域動作方法 (Global Action Filter),因此網站執行過程任何的例外都會被過濾掉,若不做特殊的設定還無法透過 ELMAH 取得錯誤紀錄,本篇文章將分享如何有效率的解決這個問題。
依照我個人習慣,我通常會在 ASP.NET 專案中選擇安裝 ELMAH on XML Log 這個 NuGet 套件,這將會讓 ELMAH 自動安裝到 ASP.NET 專案之中 (無論 ASP.NET MVC 或 ASP.NET Web Form 都可以用),並且預設會將所有收集到的錯誤儲存成 XML 格式並置於專案的 ~\App_Data\Elmah.Errors 目錄下。如下圖是安裝 NuGet 套件時的畫面:
由於 ELMAH 是利用 HTTP Modules 取得任何 Web 應用程式執行過程中丟出的例外狀況 (Exceptions),因此它可以通用於任何 ASP.NET 相關的執行環境,包括 ASP.NET Web Form 或 ASP.NET MVC 都可以正常支援。不過,如果你從應用程式中實作 try/catch 將例外狀況「吃」掉的話,ELMAH 當然是無法取得任何錯誤紀錄的。而在 ASP.NET MVC 之中,由於預設都會套用 HandleErrorAttribute 全域動作方法 (Global Action Filter),如下圖示:
而且照理來說,本來也就應該在 ASP.NET MVC 套用自訂的錯誤頁面,但是在這種情況下,由於 ASP.NET MVC 已經處理過所有例外狀況,所以 ELMAH 是無法取得任何錯誤紀錄的。
請注意:若要在 ASP.NET MVC 中顯示自訂錯誤頁面,必須將 web.config 裡的 <customError mode="On" /> 設定的 mode 屬性設定為 On 或 RemoteOnly 才會有效果,如下圖範例:
為了要讓這種情況下也能讓 ELMAH 妥善記錄所有紀錄,一般來說就是要自訂一個 例外動作過濾器 (Exception Action Filter) 並載入到 ASP.NET MVC 的 GlobalFilterCollection 之中,如下程式所示:
using Elmah;
using System.Web;
using System.Web.Mvc;
namespace MvcApplication1
{
public class ElmahHandledErrorLoggerFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
if (context.ExceptionHandled)
ErrorSignal.FromCurrentContext().Raise(context.Exception);
}
}
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
// 必須置於第一順位
filters.Add(new ElmahHandledErrorLoggerFilter());
// 預設的 Exception Action Filter
filters.Add(new HandleErrorAttribute());
}
}
}
如此一來就能順利地收錄到 ASP.NET MVC 執行過程中所發生的完整例外狀況。
事實上,還有另外一個好用的 NuGet 套件要介紹給大家,它就是:Elmah.MVC
安裝完 Elmah.MVC 套件後,它會幫你新增一個 Elmah.Mvc.dll 組件並加入專案參考外,它只會幫你修正 web.config 裡的設定,你原本的 ASP.NET MVC 專案連一行程式都不用改,ELMAH 就可以如預期的收到完整的例外狀況,非常的理想。
安裝時 Elmah.MVC 套件幫你修正 web.config 的內容,除了 ELMAH 的標準設定外,它還另外幫你新增了 5 個 appSettings 的設定,這可是 Elmah.MVC 這套件才有的好用設定,如下圖示:
這 5 個 appSettings 設定都非常實用,不但可以讓你的 ELMAH 更符合 ASP.NET MVC 風格,而且還能簡化原本 ELMAH 的設定,以下是這幾個參數的說明:
- elmah.mvc.disableHandler
- 設定是否停用 ELMAH.MVC Handler (就是顯示 Elmah 錯誤訊息的頁面)
- elmah.mvc.disableHandleErrorFilter
- 設定是否停用預設的 HandleErrorAttribute 例外動作過濾器
- elmah.mvc.requiresAuthentication
- 是否啟用 ELMAH 的身分驗證功能,如果啟用的話,進入 ELMAH 頁面則必須先登入網站
- elmah.mvc.allowedRoles
- 設定有哪些 ASP.NET 角色才能夠開啟 ELMAH 頁面 (基本授權機制)
- 預設的 * 代表所有角色,也就只要有登入網站 (FormsAuthentication) 就可以存取
- elmah.mvc.route
- 設定預設對外的 ELMAH Handler 會用哪一個路由名稱
- 預設的 elmah 就代表 ELMAH Handler 的 URL 是:
http://localhost/elmah
- 強烈建議修改這個參數值,變更為一個不容易記憶的網址,例如:ThatIsMyErrorHandler
那麼 ELMAH Handler 的 URL 就會變成:http://localhost/ThatIsMyErrorHandler
在安裝好 Elmah.MVC 套件後,預設還是會有一個空的 <elmah></elmah> 區段設定,如下圖示:
若你要將 ELMAH 開放遠端存取,則可以考慮修改 web.config 裡 <elmah> 區段的內容,如下圖示:
<elmah>
<security allowRemoteAccess="1" />
</elmah>
請注意:安裝 ELMAH 之後,若開放遠端存取,又沒有做好存取控制 (Access Control) 的話,將會帶來極大資安風險,請務必做好完善的存取控制,例如限制 IP 存取或限定特定 ASP.NET 角色才能存取該頁面等等。
相關連結