# 如何在 ASP.NET MVC 4 套用 ELMAH 錯誤紀錄模組

我幾乎每次在 ASP.NET 的教學場合裡都會提到在 ASP.NET MVC 專案中安裝 [ELMAH](https://code.google.com/p/elmah/) (Error Logging Modules and Handlers) 的重要性，不僅僅是在開發環境或測試環境能夠收錄完整的錯誤訊息，即便在正式運行的網站也非常適合安裝 [ELMAH](https://code.google.com/p/elmah/) 錯誤記錄模組。不過，當 ASP.NET MVC 網站的 web.config 設定為 **<customError mode="On" />** 的情況下，由於 ASP.NET MVC 專案預設都會套用 HandleErrorAttribute 全域動作方法 (Global Action Filter)，因此網站執行過程任何的例外都會被過濾掉，若不做特殊的設定還無法透過 ELMAH 取得錯誤紀錄，本篇文章將分享如何有效率的解決這個問題。

依照我個人習慣，我通常會在 ASP.NET 專案中選擇安裝 [ELMAH on XML Log](http://nuget.org/packages/elmah.xml) 這個 NuGet 套件，這將會讓 [ELMAH](https://code.google.com/p/elmah/) 自動安裝到 ASP.NET 專案之中 (無論 ASP.NET MVC 或 ASP.NET Web Form 都可以用)，並且預設會將所有收集到的錯誤儲存成 XML 格式並置於專案的 **~\\App\_Data\\Elmah.Errors** 目錄下。如下圖是安裝 NuGet 套件時的畫面：

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/13d88695c2beaa3a6367-image_1881.png)

由於 [ELMAH](https://code.google.com/p/elmah/) 是利用 HTTP Modules 取得任何 Web 應用程式執行過程中丟出的例外狀況 (Exceptions)，因此它可以通用於任何 ASP.NET 相關的執行環境，包括 ASP.NET Web Form 或 ASP.NET MVC 都可以正常支援。不過，如果你從應用程式中實作 try/catch 將例外狀況「吃」掉的話，[ELMAH](https://code.google.com/p/elmah/) 當然是無法取得任何錯誤紀錄的。而在 ASP.NET MVC 之中，由於預設都會套用 **HandleErrorAttribute** 全域動作方法 (Global Action Filter)，如下圖示：

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/9228033ce47e2803fda0-image_1882.png)

而且照理來說，本來也就應該在 ASP.NET MVC 套用自訂的錯誤頁面，但是在這種情況下，由於 ASP.NET MVC 已經處理過所有例外狀況，所以 [ELMAH](https://code.google.com/p/elmah/) 是無法取得任何錯誤紀錄的。

**請注意**：若要在 ASP.NET MVC 中顯示自訂錯誤頁面，必須將 web.config 裡的 **<customError mode="On" />** 設定的 **mode** 屬性設定為 **On** 或 **RemoteOnly** 才會有效果，如下圖範例：

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/cbd4f3ee09399b766d93-image_1883.png)

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/adff17b78983e689290a-image_1884.png)

為了要讓這種情況下也能讓 [ELMAH](https://code.google.com/p/elmah/) 妥善記錄所有紀錄，一般來說就是要自訂一個 **例外動作過濾器** (Exception Action Filter) 並載入到 ASP.NET MVC 的 GlobalFilterCollection 之中，如下程式所示：

```csharp
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](http://nuget.org/packages/Elmah.MVC)

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/4387f64f7093b290bcbe-image_1885.png)

安裝完 [Elmah.MVC](http://nuget.org/packages/Elmah.MVC) 套件後，它會幫你新增一個 **Elmah.Mvc.dll** 組件並加入專案參考外，它只會幫你修正 web.config 裡的設定，你原本的 ASP.NET MVC 專案連一行程式都不用改，ELMAH 就可以如預期的收到完整的例外狀況，非常的理想。

安裝時 [Elmah.MVC](http://nuget.org/packages/Elmah.MVC) 套件幫你修正 web.config 的內容，除了 [ELMAH](https://code.google.com/p/elmah/) 的標準設定外，它還另外幫你新增了 5 個 appSettings 的設定，這可是 [Elmah.MVC](http://nuget.org/packages/Elmah.MVC) 這套件才有的好用設定，如下圖示：

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/dd49a85bc46e0d66a82e-image_1886.png)

這 5 個 appSettings 設定都非常實用，不但可以讓你的 [ELMAH](https://code.google.com/p/elmah/) 更符合 ASP.NET MVC 風格，而且還能簡化原本 [ELMAH](https://code.google.com/p/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**](http://localhost/ThatIsMyErrorHandler)**

在安裝好 [Elmah.MVC](http://nuget.org/packages/Elmah.MVC) 套件後，預設還是會有一個空的 <elmah></elmah> 區段設定，如下圖示：

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/1f5b78afa29b3c74ea3d-image_1887.png)

若你要將 ELMAH 開放**遠端存取**，則可以考慮修改 web.config 裡 <elmah> 區段的內容，如下圖示：

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/a7af6f0bacd8fa9ca1c4-image_1888.png)

```xml
  <elmah>
    <security allowRemoteAccess="1" />
  </elmah>
```

**請注意**：安裝 ELMAH 之後，若開放遠端存取，又沒有做好存取控制 (Access Control) 的話，將會帶來**極大資安風險**，請務必做好完善的**存取控制**，例如限制 IP 存取或限定特定 ASP.NET 角色才能存取該頁面等等。

**相關連結**

-   [alexanderbeletsky/elmah.mvc · GitHub](https://github.com/alexanderbeletsky/elmah.mvc)
-   [ASP.NET session hijacking with Google and ELMAH](http://www.troyhunt.com/2012/01/aspnet-session-hijacking-with-google.html)
-   [elmah (官網) - Error Logging Modules and Handlers for ASP.NET - Google Project Hosting](https://code.google.com/p/elmah/)
-   [How to get ELMAH to work with ASP.NET MVC \[HandleError\] attribute?](http://stackoverflow.com/questions/766610/how-to-get-elmah-to-work-with-asp-net-mvc-handleerror-attribute/5936867#5936867)
-   [如何在 ASP.NET Web API 套用 ELMAH 錯誤紀錄模組](/post/2013/01/01/ASPNET-Web-API-and-ELMAH-Integration.aspx)
