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.<>c__DisplayClass13.<GetExecutor>b__c(Object instance, Object[] methodParameters) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.<>c__DisplayClass5.<ExecuteAsync>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.
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…." ?
Racja, ale to byl tylko przyklad, jak widac nie najlepszy:)