The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

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

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

為了讓全站所有 ASP.NET Web API 控制器都能自動取得執行過程中的錯誤紀錄,我們先來定義一個 例外過濾器 (Exception Filters),比較簡單的作法是直接繼承 ExceptionFilterAttribute 屬性類別,並且取名為 ElmahErrorAttribute 以便記憶,程式碼如下:

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 之後才提供的 API  (文件庫)

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

 

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

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 再遇到錯誤,就可以從 ELMAH 查出完整的錯誤訊息與堆疊追蹤資訊了!

 

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

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 }
            );
        }
    }
}

 

相關連結