ASP.NET MVC Web API–obsługa błędów

W poprzednim poście pisałem o podstawach Web API. Dzisiaj zajmiemy się obsługą błędów. Sprawdźmy najpierw, co stanie się, gdy nasz kontroler (patrz poprzedni wpis), zwróci jakiś wyjątek np.:

public Person GetPersonById(int id)
{
  if(id<=0)
      throw new ArgumentOutOfRangeException();
  return _personRepository.GetPersonById(id);
}

Po wpisaniu adresu “http://localhost:40521/api/persons/-1”, zostanie zwrócony internal error (kod 500) oraz następująca wiadomość:

<Error><Message>An error has occurred.</Message><ExceptionMessage>Specified argument was out of the range of valid values.</ExceptionMessage><ExceptionType>System.ArgumentOutOfRangeException</ExceptionType><StackTrace>   at MvcApplication7.Controllers.PersonsController.GetPersonById(Int32 id) in c:\projects\Microsoft\CQRS II\Source\MvcApplication7\MvcApplication7\Controllers\ValuesController.cs:line 74
   at lambda_method(Closure , Object , Object[] )
   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.&lt;&gt;c__DisplayClass13.&lt;GetExecutor&gt;b__c(Object instance, Object[] methodParameters)
   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)
   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.&lt;&gt;c__DisplayClass5.&lt;ExecuteAsync&gt;b__4()
   at System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1 func, CancellationToken cancellationToken)</StackTrace></Error>

Nie jest to zbytnio trafne i lepiej zwrócić np. kod 404 Not Found, gdy dana osoba nie zostanie znaleziona w repozytorium. Można posłużyć się wyjątkiem HttpResponseException:

public Person GetPersonById(int id)
{
  if(id<=0)
      throw new HttpResponseException(HttpStatusCode.NotFound);
  return _personRepository.GetPersonById(id);
}

Za pomocą HttpResponseException możemy zwracać konkretny status HTTP. Zaglądając do dokumentacji dowiemy się, że wyjątek posiada konstruktor, który również posiada jako argument wejściowy pewną strukturę HttpResponseMessage:

public HttpResponseException(
    HttpResponseMessage response
)

Pozwala to zdefiniować dodatkowe dane takie jak np. zawartość zwrotnego pakietu.

Możliwe jest również zwrócenie HttpResponseMessage jako rezultat akcji:

public HttpResponseMessage GetPersonById(int id)
{
  if (id <= 0)
      return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Nie znaleziono danej osoby w repozytorium.");

  return  Request.CreateResponse(HttpStatusCode.OK,_personRepository.GetPersonById(id));
}

W celu stworzenia obiektu, zwykle korzysta się z metod pomocniczych takich jak CreateErrorResponse czy CreateResponse. Komunikat błędu zostanie zwrócony w zależności od tego, jaki format został określony w zapytaniu HTTP. W IE zwykle jest to JSON:

{"Message":"Nie znaleziono danej osoby w repozytorium."}

Z kolei w Chrome, XML:

<Error>
<Message>Nie znaleziono danej osoby w repozytorium.</Message>
</Error>

Ponadto, łatwo  skorzystać z dobrodziejstw walidacji i ModelState. Rozważmy przykład:

[HttpPost]
public HttpResponseMessage AddPerson(Person person)
{
  if (!ModelState.IsValid)
      return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);

  _personRepository.AddPerson(person);
  return Request.CreateResponse(HttpStatusCode.OK);
}

Wszelkie błędy związane z walidacją, zostaną automatycznie przekazane w odpowiedzi.

Warto wspomnieć na zakończenie, że nic nie stoi na przeszkodzie, aby skorzystać z metod pomocniczych (CreateResponse, CreateErrorResponse) i wynik przekazać do opisanego wcześniej HttpResponseException.

2 thoughts on “ASP.NET MVC Web API–obsługa błędów”

  1. Hej,
    MAm takie pytanie do tej metody:

    public HttpResponseMessage GetPersonById(int id)
    {
    if (id <= 0)
    return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Nie znaleziono danej osoby w repozytorium.");

    return Request.CreateResponse(HttpStatusCode.OK,_personRepository.GetPersonById(id));
    }

    id <=0 zwroci 404 i komunikat "Nie znaleziono.,.."

    id =999999 (nie ma takiego w bazie) zwroci 200 i ?? "Nie znaleziono…." ?

Leave a Reply

Your email address will not be published.