2015-07-20 16 views
13

Sto costruendo un client API HTTP usando RestSharp e ho notato che quando il server restituisce un codice di errore HTTP (401 non autorizzato, 404 non trovato, errore interno del server 500, ecc.) Il RestClient.Execute() non lancia un eccezione - invece ottengo uno RestResponse valido con una proprietà n. .Data. Non voglio controllare manualmente ogni possibile codice di errore HTTP nel mio client API: RestSharp fornisce un modo migliore per trasmettere questi errori alla mia applicazione client?Come gestire in modo idioma i codici di errore HTTP quando si utilizza RestSharp?

Un po 'più in dettaglio. RestSharp espone una proprietà Response.ErrorException - se la chiamata RestClient.Execute<T>() causa un'eccezione, verrà esposta tramite la proprietà ErrorException anziché essere generata. La loro documentazione include il seguente esempio:

// TwilioApi.cs 
public class TwilioApi { 
    const string BaseUrl = "https://api.twilio.com/2008-08-01"; 

    public T Execute<T>(RestRequest request) where T : new() 
    { 
    var client = new RestClient(); 
    client.BaseUrl = BaseUrl; 
    client.Authenticator = new HttpBasicAuthenticator(_accountSid, _secretKey); 
    request.AddParameter("AccountSid", _accountSid, ParameterType.UrlSegment); // used on every request 
    var response = client.Execute<T>(request); 

    if (response.ErrorException != null) 
    { 
     const string message = "Error retrieving response. Check inner details for more info."; 
     var twilioException = new ApplicationException(message, response.ErrorException); 
     throw twilioException; 
    } 
    return response.Data; 
    } 

} 

ho adottato quel modello nel mio codice, ma il mio server API restituisce un 401 Unauthorized e tuttavia la proprietà ErrorException è ancora nulla. I può vedere RestResponse debug watch Codice di stato non autorizzato e messaggio di errore nelle proprietà RestResponse.StatusCode e RestResponse.StatusDescription - ma sono confuso sul motivo per cui una risposta non autorizzata non comporterà il popolamento del campo ErrorException.

risposta

0

Dovrebbe essere sufficiente controllare un codice di successo e generare o segnalare l'errore se si ottiene un altro codice oltre al successo. Questo di solito significa controllare lo stato HTTP 200 dopo ogni richiesta. Se crei una nuova risorsa, dovresti aspettarti lo stato 201.

Con la maggior parte delle API/framework, è molto insolito vedere qualsiasi altro codice di stato tranne questi se non è andato storto niente.

17

Ho riscontrato questo stesso problema durante il tentativo di creare un gestore di errori generico per un client WebAPI RestSharp. Trovati questi metodi di estensione:

public static class RestSharpExtensionMethods 
{ 
    public static bool IsSuccessful(this IRestResponse response) 
    { 
     return response.StatusCode.IsSuccessStatusCode() 
      && response.ResponseStatus == ResponseStatus.Completed; 
    } 

    public static bool IsSuccessStatusCode(this HttpStatusCode responseCode) 
    { 
     int numericResponse = (int)responseCode; 
     return numericResponse >= 200 
      && numericResponse <= 399; 
    } 
} 

abbia presentato una richiesta che richiede la risposta da deserializzati:

public async Task<ResponseModel<TResponse>> PerformRequestAsync<TResponse>(IRestRequest request) 
{ 
    var response = await _client.ExecuteTaskAsync<ResponseModel<TResponse>>(request); 
    ResponseModel<TResponse> responseData; 

    if (response.IsSuccessful()) 
    { 
     responseData = response.Data; 
    } 
    else 
    { 
     string resultMessage = HandleErrorResponse<TResponse>(request, response); 

     responseData = new ResponseModel<TResponse>   
     { 
      Success = false, 
      ResultMessage = resultMessage 
     }; 
    } 

    return responseData; 
} 

Tuttavia, durante i test, ho trovato che quando avevo alcun errore manipolazioni configurato per quel caso, my web serivce ha restituito una pagina 404 in formato HTML quando è stato richiesto un URL non mappato. Ciò ha causato la proprietà response.ErrorException per contenere la seguente stringa:

Riferimento all'entità non dichiarata 'nbsp'. Linea n, posizione m.

Come apparentemente RestSharp ha cercato di analizzare la risposta come XML, anche se il tipo di contenuto era text/html. Forse presenterò un problema con RestSharp per questo.

Ovviamente nella produzione non si dovrebbe mai ottenere un 404 quando si chiama il proprio servizio, ma voglio che questo cliente sia completo e riusabile.

Quindi ci sono due soluzioni che posso pensare:

  • Controllare il codice di stato e mostrare la descrizione
  • assicurarsi che il servizio restituisce un oggetto di errore che è possibile analizzare

L'ex è fatto abbastanza facilmente. In HandleErrorResponse() Costruisco il messaggio risultato (utente presentabile) e stringa di errore (loggable) in base al valore numerico del codice di stato:

public string HandleErrorResponse(IRestRequest request, IRestResponse response) 
{ 
    string statusString = string.Format("{0} {1} - {2}", (int)response.StatusCode, response.StatusCode, response.StatusDescription); 
    string errorString = "Response status: " + statusString; 

    string resultMessage = ""; 
    if (!response.StatusCode.IsScuccessStatusCode()) 
    { 
     if (string.IsNullOrWhiteSpace(resultMessage)) 
     { 
      resultMessage = "An error occurred while processing the request: " 
          + response.StatusDescription; 
     } 
    } 
    if (response.ErrorException != null) 
    { 
     if (string.IsNullOrWhiteSpace(resultMessage)) 
     { 
      resultMessage = "An exception occurred while processing the request: " 
          + response.ErrorException.Message; 
     } 
     errorString += ", Exception: " + response.ErrorException; 
    } 

    // (other error handling here) 

    _logger.ErrorFormat("Error response: {0}", errorString); 

    return resultMessage; 
} 

Ora, come le mie risposte API sempre sono avvolti in un ResponseModel<T> del mio fare, io può set up an exception filter and a NotFound route per restituire un modello di risposta analizzabile con il messaggio di errore o di eccezione nel ResultMessage proprietà:

public class HandleErrorAttribute : ExceptionFilterAttribute 
{ 
    public override void OnException(HttpActionExecutedContext context) 
    { 
     // (log context.Exception here) 

     context.Response = context.Request.CreateResponse(HttpStatusCode.InternalServerError, new ResponseModel<object> 
     { 
      Success = false, 
      ResultMessage = "An exception occurred while processing the request: " + context.Exception.Message 
     }); 
    } 
} 

e:

public class ErrorController : ApiController 
{ 
    public HttpResponseMessage Handle404() 
    { 
     const string notFoundString = "The requested resource could not be found"; 

     var responseMessage = Request.CreateResponse(HttpStatusCode.NotFound, new ResponseModel<object> 
     { 
      Success = false, 
      ResultMessage = notFoundString 
     }); 

     responseMessage.ReasonPhrase = notFoundString; 

     return responseMessage; 
    } 
} 

In questo modo la risposta dal mio servizio può sempre essere analizzato da RestSharp, e posso usare il metodo di registrazione generico:

public string HandleErrorResponse<TResponseModel>(IRestRequest request, IRestResponse<<ResponseModel<TResponseModel>> response) 

E registrare la risposta effettiva a // (other error handling here), se disponibile:

if (response.Data != null && !string.IsNullOrWhiteSpace(response.Data.ResultMessage)) 
{ 
    resultMessage = response.Data.ResultMessage; 
    errorString += string.Format(", Service response: \"{0}\"", response.Data.ResultMessage); 
} 
0

RestSharp ha aggiunto la proprietà booleana IRestResponse.IsSuccessful che copre il tuo caso d'uso. Non sono riuscito a trovare alcuna documentazione che si riferisca a questa proprietà, ma here's the line that defines the property's method.

Interessante notare che RestSharp considera i codici 200-299 per avere successo, mentre CodeCaster considera i codici 200-399 per avere successo.