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