ASP.NET Web API 예외 처리
이 문서에서는 ASP.NET Web API 오류 및 예외 처리에 대해 설명합니다.
HttpResponseException
Web API 컨트롤러가 catch되지 않은 예외를 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 컨트롤러에 필터를 전역적으로 적용하려면 필터의 instance 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 instance 만든 다음 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를 사용할 때의 장점 중 하나는 강력한 형식의 다른 모델과 동일한 콘텐츠 협상 및 serialization 프로세스를 거치는 것입니다.
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;
}
}