이 문서에서는 ASP.NET Web API의 오류 및 예외 처리에 대해 설명합니다.
HttpResponseException (HTTP 응답 예외)
Web API 컨트롤러에서 잡히지 않은 예외를 throw하면 어떻게 되나요? 기본적으로 대부분의 예외는 상태 코드 500, 내부 서버 오류가 있는 HTTP 응답으로 변환됩니다.
HttpResponseException 형식은 특수한 경우입니다. 이 예외는 예외 생성자에서 지정한 HTTP 상태 코드를 반환합니다. 예를 들어 ID 매개 변수가 유효하지 않으면 다음 메서드는 404를 반환합니다.
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 예외가 아닌 처리되지 않은 예외를 throw할 때 실행됩니다. HttpResponseException 형식은 HTTP 응답을 반환하기 위해 특별히 설계되었기 때문에 특별한 경우입니다.
예외 필터는 System.Web.Http.Filters.IExceptionFilter 인터페이스를 구현합니다. 예외 필터를 작성하는 가장 간단한 방법은 System.Web.Http.Filters.ExceptionFilterAttribute 클래스에서 파생되고 OnException 메서드를 재정의하는 것입니다.
메모
ASP.NET Web API의 예외 필터는 ASP.NET MVC의 예외 필터와 비슷합니다. 그러나 별도의 네임스페이스에 선언되고 별도로 함수됩니다. 특히 MVC에서 사용되는 HandleErrorAttribute 클래스는 Web API 컨트롤러에서 throw된 예외를 처리하지 않습니다.
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 API 구성 코드를 App_Start 폴더에 있는 클래스 내에 WebApiConfig 배치합니다.
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;
}
}