2016-03-09 9 views
6

Il controller WebAPI modello in MVC6/WebAPI implementa un'azione che restituisce una collezione per il metodo Get in questo modo:Tornando stringa di errore dal regolatore/WepApi MVC6

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

Supponendo che il mio codice per restituire il risultato genera eccezione, come dovrei restituire un messaggio di errore al consumatore?

Per quanto ho notato un'eccezione si tradurrebbe in HTTP 500. Questo va bene, ma vorrei dare al chiamante un messaggio che gli dice cosa è andato storto. A causa della firma dell'azione del modello, non riesco a rilevare l'eccezione e restituire qualche istanza di Http *** o ObjectResult.

+0

Dai un'occhiata alla le risposte a [questo] (http://stackoverflow.com/q/31054012/5233410) domanda – Nkosi

risposta

10

Sarà necessario aggiungere un pezzo di codice per gestire gli errori e restituire un messaggio.

Un'opzione consiste nell'utilizzare un filtro di eccezione e aggiungerlo a livello globale o su controller selezionati, sebbene questo approccio riguardi solo le eccezioni provenienti dai metodi di azione del controllore. Per esempio il seguente filtro restituirà un oggetto JSON solo quando la richiesta di accettare era application/json (In caso contrario, avrebbe lasciato l'eccezione passare attraverso il quale ad esempio potrebbe essere trattato dalla pagina di errore globale):

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()); 
}); 

Un'altra opzione È possibile modificare la firma per rendere più flessibile la risposta. Quindi è possibile gestire l'errore come si farebbe normalmente e quindi restituire un messaggio di errore facile da usare.

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

Insieme al link che hai fornito che rende tre possibili modi per farlo. Vedrò cosa si adatta meglio. Accetterò la tua risposta! – NicolasR

1

Proprio come si farebbe per mantenere in esecuzione qualsiasi programma.

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

In alternativa è possibile utilizzare HandleErrorAttribute.

+0

Grazie, ma penso che non ero' t abbastanza chiaro. Sto scrivendo un'API quindi non voglio restituire una vista. Il client dovrebbe verificare Http OK (200) o 500 (errore interno). Nel caso in cui il client abbia 500, dovrebbe essere in grado di visualizzare un messaggio di errore. Come ottengo questo messaggio di errore dal gestore di eccezioni al client? Ricerca di HandleErrorAttribute Ho trovato HttpResponseException ma questo sembra non essere supportato in MVC 6. – NicolasR

+0

puoi restituire JSON '{'result': 'error', 'status', 500}'? – will

+0

Solo quando cambio la dichiarazione di ritorno ma non mi sembra naturale perché il modello di controller crea sempre le azioni con le collezioni di ritorno. Da quello che altri hanno suggerito, sembra che il modo migliore sia far passare l'eccezione e implementare un filtro o un middleware di errore. – NicolasR

3

cambiare il metodo per assomigliare

[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

Sembra carino ma come spiegato in questo post http://stackoverflow.com/questions/31054012/asp-net-5-mvc-6-equivalent-of-httpexception?lq=1 HttpResponseException non è più disponibile. – NicolasR

0

Si può pasticciare con le eccezioni, ma ho l'impressione che non dovremmo pensare più così. Questo sembra essere lo zen di 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

Se fosse solo trovato o non trovato, allora ok.Ma che dire di tutte le eccezioni reali che accadono in scenari realistici come database rotti, servizi nidificati non disponibili e, non dimenticare, bug introdotti dai programmatori. Sono d'accordo che IActionResult mi darebbe la libertà di restituire tutto ciò che è necessario, ma ciò significherebbe che dovevo rilevare eccezioni in ogni metodo del controller solo per convertirlo in qualcosa come "Si è verificato un errore, si prega di consultare ..." (come minimo). – NicolasR

+0

Che ti piaccia o no, tutte queste eccezioni vengono trasformate in risultati HTTP di un modulo o di un altro. Questo, IMO, sta semplicemente catturando quel paradigma piuttosto che dare l'illusione che qualche eccezione venga effettivamente restituita al cliente. –

+0

Sono d'accordo con te sul paradigma e uso il codice come hai postato nella maggior parte dei miei metodi. Dall'altra parte, dai un'occhiata al secondo frammento di codice nella risposta di Nkosi. Non voglio davvero avere quel tipo di codice in ciascuno dei miei controller. Il mio problema è che il gestore di eccezioni predefinito restituisce solo il codice 500 al client senza alcun testo di errore. Questo è il motivo per cui mi piace la soluzione CustomExceptionFilter. – NicolasR