ASP.NET Web API 心得筆記 (6) 例外處理(Exception Handling)

HttpResponseException

如果 Web API 的 controller 擲出一個例外(exception),會發生什麼事?預設下,最常是會把例外轉譯為一個 HTTP 狀態碼 500 (Internal Server Error) 回應。

HttpResponseException 型別是一個特別情況。你能指定此例外的建構式,這個例外能回傳任何 HTTP 狀態碼。例如,下面例子,如果 id 參數不存在,會回傳 404 (Not Found) 狀態碼。


Function GetContact(id As Integer) As Contact
    Dim contact As Contact = _repository.GetContactById(id)
    If contact Is Nothing Then
        Throw New HttpResponseException(System.Net.HttpStatusCode.NotFound)
    End If
    Return contact
End Function

想要對回應取得更多控制,你也能建構回應的訊息 (HttpResponseMessage 型別),然後包含在 HttpResponseException 裡:


Function GetContact(id As Integer) As Contact
    Dim contact As Contact = _repository.GetContactById(id)
    If contact Is Nothing Then
        ' Throw New HttpResponseException(System.Net.HttpStatusCode.NotFound)
        Dim msg As New HttpResponseMessage(System.Net.HttpStatusCode.NotFound)
        msg.Content = New StringContent(
            String.Format("無法找到連絡人ID = {0}", id))
        msg.ReasonPhrase = "未發現連絡人"
        Throw New HttpResponseException(msg)
    End If
    Return contact
End Function

例外過濾 (Exception Filters)

你可以透過撰寫例外過濾(Exception Filter)來自己處理 Web API 的例外。當一個 controller 方法擲出任何未處理的例外,它並不是 HttpResponseException 例外,例外過濾被會執行。HttpResponseException 型別是一種特別情況,因為它是特別設計來回傳 HTTP 回應。

例外過濾實作 System.Web.Http.Filters.IExceptionFilter 介面。不管如何,只需要繼承 System.Web.Http.Filters.ExceptionFilterAttribute 類別然後覆寫(override) OnException 方法。

新增一個新目錄,命名為 Filters,然後在 Filters 目錄內新增一個 Class 命名為 LogExceptionFilter


圖一:新增目錄

LogExceptionFilter.vb 程式碼內容:


Imports System.Diagnostics
Imports System.Web.Http.Filters

''' <summary>
''' 繼承 ExceptionFilterAttribute,且覆寫 OnException 方法
''' </summary>
Public Class LogExceptionFilter
    Inherits ExceptionFilterAttribute

    Public Overrides Sub OnException(actionExecutedContext As HttpActionExecutedContext)
        ' 增加二行 Trace 程式碼
        Trace.TraceError("例外: {0}", actionExecutedContext.Exception.Message)
        Trace.TraceError("請求 URI: {0}", actionExecutedContext.Request.RequestUri)
        MyBase.OnException(actionExecutedContext)
    End Sub
End Class

你也能自行控制 HTTP 回應讓 Client 接收。在 HttpActionExecutedContext 參數去異動或設定 Result 屬性。我們新增一個 NotImplExceptionFilter 類別,一樣繼承 ExceptionFilterAttribute 類別及覆寫 OnException 方法。


Imports System.Diagnostics
Imports System.Net
Imports System.Net.Http
Imports System.Web.Http.Filters

''' <summary>
''' 繼承 ExceptionFilterAttribute,且覆寫 OnException 方法
''' 回應 HTTP 狀態碼 501
''' </summary>
Public Class NotImplExceptionFilter
    Inherits ExceptionFilterAttribute

    Public Overrides Sub OnException(actionExecutedContext As HttpActionExecutedContext)
        If actionExecutedContext.Result Is Nothing Then
            actionExecutedContext.Result = New HttpResponseMessage()
        End If

        ' HttpStatusCode.NotImplemented = 501
        actionExecutedContext.Result.StatusCode = HttpStatusCode.NotImplemented
        actionExecutedContext.Result.Content = New StringContent("方法未執行")

        MyBase.OnException(actionExecutedContext)
    End Sub
End Class

註冊例外過濾

有二種方法可以去註冊例外過濾。

第一,你可以註冊到全域的 GlobalConfiguration.Configuration.Filters 集合。當發生未處理的例外,例外過濾集合中會作用在所有 Web API controller action。(例外型別 HttpResponseException 也會被執行)。我們必須在 Global.asax 檔的 Application_Start 註冊它。


' … 略 …

Public Class WebApiApplication
    Inherits System.Web.HttpApplication

    ' … 略 …
 
    ''' <summary>
    ''' 註冊 Exception Filter 至組態
    ''' </summary>
    ''' <param name="config">HTTP 組態屬性</param>
    Shared Sub ConfigureApi(config As HttpConfiguration)
        config.Filters.Add(New LogExceptionFilter)
    End Sub

    Sub Application_Start()
     ' 進行註冊
        ConfigureApi(GlobalConfiguration.Configuration)

        ' … 略 …
    End Sub
End Class

第二,你可以註冊例外過濾至指定的 action 方法,透過指定屬性的方式。例如以下範例:


<NotImplExceptionFilter>
Function GetContact(id As Integer) As Contact
    Dim contact As Contact = _repository.GetContactById(id)
    If contact Is Nothing Then
        Throw New NotImplementedException("此方法未執行!")
    End If
    Return contact
End Function

例外過濾在 ASP.NET Web API 與 ASP.NET MVC 類似。不管如何,它他分布在不同命名空間裡。特別說明,HandleErrorAttribute 類別使用在  ASP.NET MVC,無法拿來處理 Web API controller 的例外。


沒有留言:

張貼留言

感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。