2016-03-09 13 views
6

Szablon kontroler WebAPI w MVC6/WebAPI realizuje akcję, która zwraca kolekcję dla metody GET jak ten:Wracając błędzie ciąg od MVC6 kontrolera/WepApi

[HttpGet] 
public IEnumerable<MyEntity> Get() 
{ 
    //my code to return entities 
} 

Zakładając, że mój kod, aby powrócić wynik Zgłasza wyjątek, w jaki sposób zwrócę komunikat o błędzie do konsumenta?

O ile zauważyłem, wyjątek spowodowałby HTTP 500. To dobrze, ale chciałbym przekazać dzwoniącemu wiadomość informującą go, co poszło nie tak. Z powodu sygnatury akcji szablonu nie mogę wychwycić wyjątku i zwrócić niektórych instancji Http *** lub ObjectResult.

+0

Prosze zapoznać się z odpowiedziami na [to] (http://stackoverflow.com/q/31054012/5233410) Pytanie – Nkosi

Odpowiedz

10

Musisz samemu dodać fragment kodu, który poradzi sobie z błędami i zwróci wiadomość.

Jedną z opcji jest użycie filtru wyjątków i dodanie go globalnie lub na wybranych kontrolerach, chociaż to podejście obejmowałoby tylko wyjątki wynikające z metod działania kontrolera. Na przykład następujący filtr zwróci obiekt json tylko wtedy, gdy żądanie akceptować był application/json (W przeciwnym razie byłoby to niech wyjątek przechodzić przez które na przykład mogą być obsługiwane przez globalną stronę błędu):

public class CustomJSONExceptionFilter : ExceptionFilterAttribute 
{  
    public override void OnException(ExceptionContext context) 
    { 
     if (context.HttpContext.Request.GetTypedHeaders().Accept.Any(header => header.MediaType == "application/json")) 
     { 
      var jsonResult = new JsonResult(new { error = context.Exception.Message }); 
      jsonResult.StatusCode = Microsoft.AspNetCore.Http.StatusCodes.Status500InternalServerError; 
      context.Result = jsonResult; 
     } 
    } 
} 

services.AddMvc(opts => 
{ 
    //Here it is being added globally. 
    //Could be used as attribute on selected controllers instead 
    opts.Filters.Add(new CustomJSONExceptionFilter()); 
}); 

Inną opcją można zmienić podpis, aby zwiększyć elastyczność odpowiedzi. Wtedy możesz obsłużyć błąd jak zwykle, a następnie zwrócić komunikat przyjazny dla użytkownika.

public IActionResult Get() { 
    try { 
     IEnumerable<MyEntity> result; 
     //...result populated 
     return new HttpOkObjectResult(result); 
    } catch (Exception ex) { 
     //You should handle the error 
     HandleError(ex);//the is not an actual method. Create your own. 
     //You could then create your own error so as not to leak 
     //internal information. 
     var error = new 
      { 
       message = "Enter you user friendly error message", 
       status = Microsoft.AspNetCore.Http.StatusCodes.Status500InternalServerError 
      }; 
     Context.Response.StatusCode = error.status;    
     return new ObjectResult(error); 
    } 
} 
+1

Wraz z podanym linkiem można wykonać trzy możliwe sposoby. Zobaczę, co pasuje najlepiej. Przyjmuję twoją odpowiedź! – NicolasR

1

Tak samo, jak w przypadku każdego uruchomionego programu.

try { 
    ... 
} catch (Exception e) { 
    return errorMessageView; 
} 

Alternatywnie można użyć HandleErrorAttribute.

+0

Dzięki, ale myślę, że nie był” wystarczająco jasne. Piszę API, więc nie chcę zwrócić widoku. Klient powinien sprawdzić Http OK (200) lub 500 (błąd wewnętrzny). W przypadku, gdy klient ma 500, powinien być w stanie wyświetlić komunikat o błędzie. Jak uzyskać ten komunikat o błędzie z obsługi wyjątku do klienta? Wyszukiwanie HandleErrorAttribute Znalazłem wyjątek HttpResponseException, ale wydaje mi się, że nie jest to obsługiwane w MVC 6. – NicolasR

+0

możesz zwrócić JSON '{'result': 'error', 'status', 500}'? – will

+0

Tylko wtedy, gdy zmienię instrukcję return, ale to wydaje się nienaturalne, ponieważ szablon kontrolera zawsze tworzy działania Get z zwracanymi kolekcjami. Z tego, co sugerowali inni, wynika, że ​​najlepiej jest pozwolić wyjątkowi upaść i wdrożyć oprogramowanie pośredniczące z filtrem lub błędem. – NicolasR

3

zmienić metodę wyglądać

[HttpGet] 
[ResponseType(typeof(IEnumerable<MyEntity>))] 
public IHttpActionResult Get() 
{ 
    //when ok 
    return Ok(response); // response is your IEnumerable<MyEntity> 

    //when error 
    throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.WhateverStatusCodeSuitable) 
      { 
       ReasonPhrase = "your message" 
      }); 

} 
+2

Wygląda ładnie, ale jak wyjaśniono w tym poście http://stackoverflow.com/questions/31054012/asp-net-5-mvc-6-equivalent-of-httpexception?lq=1 wyjątek HttpResponseException nie jest już dostępny. – NicolasR

0

Mona poeksperymentować z wyjątkami, ale mam wrażenie, że nie powinniśmy myśleć, że jak dłużej. To wydaje się być Zen MVC6:

[HttpGet("{id}")] 
    [ProducesResponseType(typeof(IEnumerable<string>), 200)] 
    [ProducesResponseType(typeof(void), 404)] 
    public IActionResult Get(int id) 
    { 
     Product product = null; 
     if (!this.productRepository.TryGet(id, out product)) 
     { 
      return NotFound(); 
     } 

     return Ok(product); 
    } 
+0

Jeśli tylko znaleziono lub nie znaleziono, to dobrze.Ale co ze wszystkimi faktycznymi wyjątkami, które zdarzają się w realistycznych scenariuszach, takich jak zepsuta baza danych, niedostępne usługi zagnieżdżone i, nie zapomnij, błędy wprowadzone przez programistów. Zgadzam się, że IActionResult dałoby mi swobodę zwracania tego, co jest potrzebne, ale to oznaczałoby, że musiałem wychwycić wyjątki w każdej metodzie sterownika, aby przekonwertować ją na coś w stylu "Wystąpił błąd, skonsultuj się ..." (jako minimum). – NicolasR

+0

Niezależnie od tego, czy ci się to podoba, czy nie, wszystkie te wyjątki są przekształcane w wyniki HTTP jednej lub drugiej formy. To, IMO, jest po prostu uchwyceniem tego paradygmatu, zamiast dawania złudzenia, że ​​jakiś wyjątek jest faktycznie przekazywany klientowi. –

+0

Zgadzam się z tobą na temat paradygmatu i używam kodu takiego, jaki opublikowałeś w większości moich metod. Z drugiej strony spójrz na drugi fragment kodu w odpowiedzi Nkosiego. Naprawdę nie chcę mieć tego rodzaju kodu w każdym z moich kontrolerów. Mój problem polega na tym, że domyślna procedura obsługi wyjątku zwraca kod 500 do klienta bez żadnego błędu. Właśnie dlatego podoba mi się rozwiązanie CustomExceptionFilter. – NicolasR