ASP.NET Web API中的例外狀況處理
本文說明 ASP.NET Web API中的錯誤和例外狀況處理。
HttpResponseException
如果 Web API 控制器擲回未攔截的例外狀況,會發生什麼事? 根據預設,大部分的例外狀況都會轉譯成狀態碼為 500、內部伺服器錯誤的 HTTP 回應。
HttpResponseException類型是特殊案例。 這個例外狀況會傳回您在例外狀況建構函式中指定的任何 HTTP 狀態碼。 例如,如果 id 參數無效,下列方法會傳回 404, Not Found。
public Product GetProduct(int id)
{
Product item = repository.Get(id);
if (item == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return item;
}
若要進一步控制回應,您也可以建構整個回應訊息,並將其包含在 HttpResponseException 中:
public Product GetProduct(int id)
{
Product item = repository.Get(id);
if (item == null)
{
var resp = new HttpResponseMessage(HttpStatusCode.NotFound)
{
Content = new StringContent(string.Format("No product with ID = {0}", id)),
ReasonPhrase = "Product ID Not Found"
};
throw new HttpResponseException(resp);
}
return item;
}
例外狀況篩選條件
您可以藉由撰寫例外狀況篩選來自訂 Web API 如何處理 例外狀況。 當控制器方法擲回 任何不是HttpResponseException 例外狀況的未處理例外狀況時,就會執行例外狀況篩選。 HttpResponseException類型是特殊案例,因為它專為傳回 HTTP 回應而設計。
例外狀況篩選準則會實 作 System.Web.Http.Filters.IExceptionFilter 介面。 撰寫例外狀況篩選的最簡單方式是衍生自 System.Web.Http.Filters.ExceptionFilterAttribute 類別,並覆寫 OnException 方法。
注意
ASP.NET Web API中的例外狀況篩選類似于 ASP.NET MVC 中的篩選準則。 不過,它們會分別宣告在個別的命名空間和函式中。 特別是,MVC 中使用的 HandleErrorAttribute 類別不會處理 Web API 控制器擲回的例外狀況。
以下是將 NotImplementedException 例外狀況轉換成 HTTP 狀態碼 501、未實作的篩選:
namespace ProductStore.Filters
{
using System;
using System.Net;
using System.Net.Http;
using System.Web.Http.Filters;
public class NotImplExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is NotImplementedException)
{
context.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented);
}
}
}
}
HttpActionExecutedCoNtext物件的Response屬性包含將傳送給用戶端的 HTTP 回應訊息。
註冊例外狀況篩選
有數種方式可以註冊 Web API 例外狀況篩選︰
- 透過動作
- 透過控制器
- 全域
若要將篩選套用至特定動作,請在動作中新增篩選來做為屬性︰
public class ProductsController : ApiController
{
[NotImplExceptionFilter]
public Contact GetContact(int id)
{
throw new NotImplementedException("This method is not implemented");
}
}
若要將篩選套用至控制器上的所有動作,請將篩選新增為控制器類別的屬性:
[NotImplExceptionFilter]
public class ProductsController : ApiController
{
// ...
}
若要全域將篩選套用至所有 Web API 控制器,請將篩選的實例新增至 GlobalConfiguration.Configuration.Filters 集合。 此集合中的例外狀況篩選會套用至任何 Web API 控制器動作。
GlobalConfiguration.Configuration.Filters.Add(
new ProductStore.NotImplExceptionFilterAttribute());
如果您使用 「ASP.NET MVC 4 Web 應用程式」 專案範本來建立專案,請將 Web API 組態程式碼放在 類別內 WebApiConfig
,其位於 App_Start 資料夾中:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Filters.Add(new ProductStore.NotImplExceptionFilterAttribute());
// Other configuration code...
}
}
HttpError
HttpError物件提供一致的方式來傳迴響應本文中的錯誤資訊。 下列範例示範如何在回應本文中使用 HttpError 傳回 HTTP 狀態碼 404 (找不到) 。
public HttpResponseMessage GetProduct(int id)
{
Product item = repository.Get(id);
if (item == null)
{
var message = string.Format("Product with id = {0} not found", id);
return Request.CreateErrorResponse(HttpStatusCode.NotFound, message);
}
else
{
return Request.CreateResponse(HttpStatusCode.OK, item);
}
}
CreateErrorResponse 是 System.Net.Http.HttpRequestMessageExtensions 類別中定義的擴充方法。 在內部,CreateErrorResponse會建立HttpError實例,然後建立包含HttpError的HttpResponseMessage。
在此範例中,如果 方法成功,它會在 HTTP 回應中傳回產品。 但如果找不到要求的產品,HTTP 回應就會在要求本文中包含 HttpError 。 回應看起來可能如下所示:
HTTP/1.1 404 Not Found
Content-Type: application/json; charset=utf-8
Date: Thu, 09 Aug 2012 23:27:18 GMT
Content-Length: 51
{
"Message": "Product with id = 12 not found"
}
請注意,此範例中的 HttpError 已序列化為 JSON。 使用 HttpError 的優點之一是,它會經歷與任何其他強型別模型相同的 內容交涉 和序列化程式。
HttpError 和模型驗證
針對模型驗證,您可以將模型狀態傳遞至 CreateErrorResponse,以在回應中包含驗證錯誤:
public HttpResponseMessage PostProduct(Product item)
{
if (!ModelState.IsValid)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
// Implementation not shown...
}
此範例可能會傳回下列回應:
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
Content-Length: 320
{
"Message": "The request is invalid.",
"ModelState": {
"item": [
"Required property 'Name' not found in JSON. Path '', line 1, position 14."
],
"item.Name": [
"The Name field is required."
],
"item.Price": [
"The field Price must be between 0 and 999."
]
}
}
如需模型驗證的詳細資訊,請參閱ASP.NET Web API中的模型驗證。
搭配 HttpResponseException 使用 HttpError
上述範例會從控制器動作傳回 HttpResponseMessage 訊息,但您也可以使用 HttpResponseException 傳回 HttpError。 這可讓您在正常成功案例中傳回強型別模型,同時如果發生錯誤,仍會傳回 HttpError :
public Product GetProduct(int id)
{
Product item = repository.Get(id);
if (item == null)
{
var message = string.Format("Product with id = {0} not found", id);
throw new HttpResponseException(
Request.CreateErrorResponse(HttpStatusCode.NotFound, message));
}
else
{
return item;
}
}
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應