﻿# 如何在 ASP.NET Web API 套用 ELMAH 錯誤紀錄模組 (2021 年版)

之前寫過好幾篇跟 ELMAH 相關的文章，其中 [如何在 ASP.NET MVC 4 套用 ELMAH 錯誤紀錄模組](/post/2013/03/12/ASPNET-MVC-4-and-ELMAH-Integration) 這篇還沒有過時，但剛在看 [如何在 ASP.NET Web API 套用 ELMAH 錯誤紀錄模組](/post/2013/01/01/ASPNET-Web-API-and-ELMAH-Integration) 這篇文章時發現，現在有更簡單的設定方法，所以特別撰文分享心得。

1.  安裝 [elmah](https://www.nuget.org/packages/elmah) 套件
    
    這個步驟將會安裝 ELMAH 核心的 [elmah.corelibrary](https://www.nuget.org/packages/elmah.corelibrary/) 套件，以及套用 ELMAH 必要的 `Web.config` 設定！
    
    ```bash
    Install-Package elmah
    ```
    
    預設套用的設定還不少，其中包含：
    
    三個 `<system.web>` 下的 `httpModules` 設定：
    
    ```xml
    <httpModules>
      <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
      <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
      <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />
    </httpModules>
    ```
    
    一個 `<system.webServer>` 下的 `validation` 設定：
    
    ```xml
    <validation validateIntegratedModeConfiguration="false" />
    ```
    
    三個 `<system.webServer>` 下的 `modules` 設定：
    
    ```xml
    <modules>
      <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" preCondition="managedHandler" />
      <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" preCondition="managedHandler" />
      <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" preCondition="managedHandler" />
    </modules>
    ```
    
    一個 `<elmah>` 自訂組態設定，預設會**使用記憶體來儲存錯誤記錄**以及**關閉遠端存取權限**：
    
    ```xml
    <configSections>
      <sectionGroup name="elmah">
        <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
        <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
        <section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
        <section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
      </sectionGroup>
    </configSections>
    
    <elmah>
      <!--
          See http://code.google.com/p/elmah/wiki/SecuringErrorLogPages for
          more information on remote access and securing ELMAH.
      -->
      <security allowRemoteAccess="false" />
    </elmah>
    ```
    
    一個 `<location>` 自訂路徑，設定 ELMAH 使用 `/elmah.axd` 路徑來查看錯誤記錄 (Web UI)：
    
    ```xml
    <location path="elmah.axd" inheritInChildApplications="false">
      <system.web>
        <httpHandlers>
          <add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
        </httpHandlers>
        <!--
          See http://code.google.com/p/elmah/wiki/SecuringErrorLogPages for
          more information on using ASP.NET authorization securing ELMAH.
    
        <authorization>
          <allow roles="admin" />
          <deny users="*" />
        </authorization>
        -->
      </system.web>
      <system.webServer>
        <handlers>
          <add name="ELMAH" verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" preCondition="integratedMode" />
        </handlers>
      </system.webServer>
    </location>
    ```
    
2.  安裝 [Elmah.Contrib.WebApi](https://www.nuget.org/packages/Elmah.Contrib.WebApi) 套件
    
    這個套件主要提供你兩個類別：[Elmah.Contrib.WebApi.ElmahHandleErrorApiAttribute](https://github.com/rdingwall/elmah-contrib-webapi/blob/master/src/Elmah.Contrib.WebApi/ElmahHandleErrorApiAttribute.cs) 與 [Elmah.Contrib.WebApi.ElmahExceptionLogger](https://github.com/rdingwall/elmah-contrib-webapi/blob/master/src/Elmah.Contrib.WebApi/ElmahExceptionLogger.cs)！
    
    ```powershell
    Install-Package Elmah.Contrib.WebApi
    ```
    
    其中 [Elmah.Contrib.WebApi.ElmahHandleErrorApiAttribute](https://github.com/rdingwall/elmah-contrib-webapi/blob/master/src/Elmah.Contrib.WebApi/ElmahHandleErrorApiAttribute.cs) 是一個 Action Filter (動作過濾器)，幫助你記錄 Action 執行過程中的例外，如果 Action 回應 HTTP 狀態碼為 `5xx` 的話，也會一併記錄到 ELMAH 之中。這個類別的用法，是在 `App_Start\WebApiConfig.cs` 的 `Register()` 方法中加入以下這行（你必須手動加入）：
    
    ```csharp
    config.Filters.Add(new ElmahHandleErrorApiAttribute());
    ```
    
    另一個 [Elmah.Contrib.WebApi.ElmahExceptionLogger](https://github.com/rdingwall/elmah-contrib-webapi/blob/master/src/Elmah.Contrib.WebApi/ElmahExceptionLogger.cs) 則是用來替 ASP.NET Web API 註冊全域的 ExceptionLogger，用以紀錄整個站台所有與 ASP.NET Web API 相關的例外狀況。這個類別的用法，是在 `App_Start\WebApiConfig.cs` 的 `Register()` 方法中加入以下這行（你必須手動加入）：
    
    ```csharp
    config.Services.Add(typeof(IExceptionLogger), new ElmahExceptionLogger());
    ```
    
    請記得引用兩個命名空間：
    
    ```csharp
    using System.Web.Http.ExceptionHandling;
    using Elmah.Contrib.WebApi;
    ```
    
    這兩個不同的類別，通常不會一起使用，但還是要看狀況判斷。因為 `ElmahHandleErrorApiAttribute` 主要針對 API Action 做紀錄，而 `ElmahExceptionLogger` 則是實作了 ASP.NET Web API 的全域錯誤處理機制，詳見 [Global Error Handling in ASP.NET Web API 2](https://learn.microsoft.com/en-us/aspnet/web-api/overview/error-handling/web-api-global-error-handling?WT.mc_id=DT-MVP-4015686) 官網文件說明。兩個都啟用的話，可能會重複記錄到相同的例外狀況。
    
3.  如果你想把例外狀況都儲存成 XML 檔案的話，可以安裝 [elmah.xml](https://www.nuget.org/packages/elmah.xml) 套件即可
    
    ```powershell
    Install-Package elmah.xml
    ```
    
    安裝這個套件的過程，會自動幫你建立一個 `App_Data\Elmah.Errors` 資料夾，並且幫你在 `Web.config` 加入一段 `<elmah>` 區段下的宣告：
    
    ```xml
    <errorLog type="Elmah.XmlFileErrorLog, Elmah" logPath="~/App_Data/Elmah.Errors" />
    ```
    
    > 嚴正提醒：如果不打算看 ELMAH 的 Log，就把 Log 關閉，不要將 Log 一直累積在伺服器上，否則資料量過大可能會影響主機效能。參見: [Windows 下的 TEMP 目錄中檔案過多會導致系統效能驟降](/post/2012/12/05/Too-many-files-on-Windows-TEMP-folder-will-cause-system-petformance-down)
    

### 範例程式

本文範例程式與 Git 變更記錄都放在這裡: [https://github.com/doggy8088/AspNetWebApiELMAH/commits/master](https://github.com/doggy8088/AspNetWebApiELMAH/commits/master)

另外，由於 ELMAH 還有很多內建的功能，完整的範例可以從 [sample web.config](https://app.assembla.com/spaces/elmah/subversion/source/HEAD/tags/REL-1.2/samples/web.config) 取得。這裡我覺得最強大的功能，應該非 `<errorFilter>` 莫屬，關於**錯誤過濾器**的設定方式，我再找時間跟大家分享！

### 相關連結

-   [ELMAH—Home](https://elmah.github.io/)
    
    ELMAH (Error Logging Modules and Handlers) is an application-wide error logging facility that is completely pluggable. It can be dynamically added to a running ASP.NET web application, or even all ASP.NET web applications on a machine, without any need for re-compilation or re-deployment.
    
    -   [sample web.config](https://app.assembla.com/spaces/elmah/subversion/source/HEAD/tags/REL-1.2/samples/web.config)
    -   [NuGet Gallery | elmah 1.2.2](https://www.nuget.org/packages/Elmah)

* * *

-   [rdingwall/elmah-contrib-webapi](https://github.com/rdingwall/elmah-contrib-webapi)
    
    Elmah.Contrib.WebApi provides an ASP.NET Web API exception filter, ElmahHandleErrorApiAttribute, for logging errors directly to ELMAH.
    
    -   [NuGet Gallery | Elmah.Contrib.WebApi 1.0.10.25](https://www.nuget.org/packages/Elmah.Contrib.WebApi)

* * *

-   [alexbeletsky/elmah-mvc](https://github.com/alexbeletsky/elmah-mvc)
    
    Painless integration of ELMAH into ASP.NET MVC application
    
    -   [NuGet Gallery | Elmah.MVC 2.1.2](https://www.nuget.org/packages/Elmah.MVC)

* * *

-   其他文章
    
    -   [如何在 ASP.NET Web API 套用 ELMAH 錯誤紀錄模組](/post/2013/01/01/ASPNET-Web-API-and-ELMAH-Integration)
    -   [如何在 ASP.NET MVC 4 套用 ELMAH 錯誤紀錄模組](/post/2013/03/12/ASPNET-MVC-4-and-ELMAH-Integration)
    -   [如何替 ELMAH 錯誤紀錄頁面加上 IP 來源限制存取設定 (IIS)](/post/2014/06/15/IP-Security-limit-on-ELMAH-in-IIS-7-and-above)
    -   [Global Error Handling in ASP.NET Web API 2](https://learn.microsoft.com/en-us/aspnet/web-api/overview/error-handling/web-api-global-error-handling?WT.mc_id=DT-MVP-4015686)
