﻿# 如何在 ASP.NET Web API 套用 ELMAH 錯誤紀錄模組

每個網站必備的 [ELMAH](http://code.google.com/p/elmah/) (Error Logging Modules and Handlers) 模組，在使用 [ASP.NET Web API](http://www.asp.net/web-api) 時卻無法自動套用，也就是說 [ASP.NET Web API](http://www.asp.net/web-api) 執行的過程中發生任何例外，預設都不會自動寫入 [ELMAH](http://code.google.com/p/elmah/) 指定的儲存區。那是因為 [ASP.NET Web API](http://www.asp.net/web-api) 的主要用途是用來回應呼叫 RESTful API 的用戶端要求，為了不讓用戶端得到不符合 JSON 或 XML 格式的訊息內容，因此所有例外都會被 ApiController 基底類別給攔截，如果我們想在 [ASP.NET Web API](http://www.asp.net/web-api) 實作錯誤紀錄，則必須透過 Action Filter 來設定。

為了讓全站所有 [ASP.NET Web API](http://www.asp.net/web-api) 控制器都能自動取得執行過程中的錯誤紀錄，我們先來定義一個 **例外過濾器** (Exception Filters)，比較簡單的作法是直接繼承 [ExceptionFilterAttribute](http://msdn.microsoft.com/en-us/library/system.web.http.filters.exceptionfilterattribute\(v=vs.108\).aspx) 屬性類別，並且取名為 **ElmahErrorAttribute** 以便記憶，程式碼如下：

```csharp
using System.Web.Http.Filters;

    public class ElmahErrorAttribute : ExceptionFilterAttribute
    {
        public override void OnException(HttpActionExecutedContext actionExecutedContext)
        {
            if (actionExecutedContext.Exception != null)
                Elmah.ErrorSignal.FromCurrentContext().Raise(actionExecutedContext.Exception);

            base.OnException(actionExecutedContext);
        }
    }
```

重點就在於以下這行，將 **例外過濾器** 取得的例外，寫入到 Elmah 裡：  
**請注意**: Elmah.ErrorSignal.FromCurrentContext().Raise(…) 是 **[ELMAH 1.2](http://code.google.com/p/elmah/)** 之後才提供的 API  ([文件庫](http://code.google.com/p/elmah/wiki/WebBase))

-   Elmah.ErrorSignal.FromCurrentContext().Raise(actionExecutedContext.Exception);

接著我們開啟 **App\_Start\\WebApiConfig.cs** 類別，在 WebApiConfig 類別的 Register 方法開頭的地方，將 ElmahErrorAttribute 註冊到 **全域動作過濾器** (Global Action Filter) 裡，範例如下：

```csharp
public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Filters.Add(
            new ElmahErrorAttribute()
        );

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}
```

如此一來，日後若 [ASP.NET Web API](http://www.asp.net/web-api) 再遇到錯誤，就可以從 [ELMAH](http://code.google.com/p/elmah/) 查出完整的錯誤訊息與堆疊追蹤資訊了！

有時候遇到比較小的案子，為了方便起見，我會把 ElmahErrorAttribute 類別直接跟 WebApiConfig 放在同一個 C# 檔案裡，以方便管理：

```csharp
using System.Web.Http;
using System.Web.Http.Filters;

namespace MvcApplication1
{
    public class ElmahErrorAttribute : ExceptionFilterAttribute
    {
        public override void OnException(HttpActionExecutedContext actionExecutedContext)
        {
            if (actionExecutedContext.Exception != null)
                Elmah.ErrorSignal.FromCurrentContext().Raise(actionExecutedContext.Exception);

            base.OnException(actionExecutedContext);
        }
    }

    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Filters.Add(
                new ElmahErrorAttribute()
            );

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }
}
```

**相關連結**

-   [ASP.NET Web API and ELMAH Integration](http://www.tugberkugurlu.com/archive/asp-net-web-api-and-elmah-integration)
-   [Exception Handling in ASP.NET Web API](http://www.asp.net/web-api/overview/web-api-routing-and-actions/exception-handling)
-   [ASP.NET Web API](http://www.asp.net/web-api)
-   [elmah - Error Logging Modules and Handlers for ASP.NET](http://code.google.com/p/elmah/)
-   [如何偵錯--ELMAH 絕妙的偵錯工具安全架設於ASP.NET MVC](http://demo.tc/Post/606)
-   [Introductory article for ELMAH by Simone Busoli](http://code.google.com/p/elmah/wiki/DotNetSlackersArticle)
-   [NuGet Gallery | ELMAH 1.2.2](http://nuget.org/packages/elmah)
-   [Huan-Lin 學習筆記: ASP.NET Web API Exception Filter](http://huan-lin.blogspot.tw/2013/01/aspnet-web-api-exception-filter.html)
