using System; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; namespace RestEase { /// /// Exception thrown when a bad API response is received /// public class ApiException : Exception { /// /// Gets the method used to make the request which failed /// public HttpMethod RequestMethod { get; } /// /// Gets the URI to which the request which failed wras made /// public Uri RequestUri { get; } /// /// Gets the HTTP status code received /// public HttpStatusCode StatusCode { get; } /// /// Gets the ReasonPhrase associated with the response /// public string ReasonPhrase { get; } /// /// Gets the headers associated with the response /// public HttpResponseHeaders Headers { get; } /// /// Gets the content headers associated with the response /// public HttpContentHeaders? ContentHeaders { get; } /// /// Gets the content associated with the response, if any /// public string? Content { get; } /// /// Gets a value indicating whether any content is associated with the response /// public bool HasContent => !string.IsNullOrWhiteSpace(this.Content); /// /// Initialises a new instance of the class with the given /// /// Request which triggered the exception /// provided by the /// String content, as read from , if there is a response content public ApiException(HttpRequestMessage request, HttpResponseMessage response, string? contentString) : this(request.Method, request.RequestUri, response.StatusCode, response.ReasonPhrase, response.Headers, response.Content?.Headers, contentString) { } /// /// Initialises a new instance of the class with the given components /// /// used to make the request which failed /// to which the request which failed was made /// returned by the endpoint /// provided by /// s associated with the response /// associated with the response content, if there is a response content /// String content, as read from , if there is a response content public ApiException( HttpMethod requestMethod, Uri requestUri, HttpStatusCode statusCode, string reasonPhrase, HttpResponseHeaders headers, HttpContentHeaders? contentHeaders, string? contentString) : base($"{requestMethod} \"{requestUri}\" failed because response status code does not indicate success: {(int)statusCode} ({reasonPhrase}).") { this.RequestMethod = requestMethod; this.Data[nameof(this.RequestMethod)] = requestMethod.Method; this.RequestUri = requestUri; this.Data[nameof(this.RequestUri)] = requestUri; this.StatusCode = statusCode; this.Data[nameof(this.StatusCode)] = statusCode; this.ReasonPhrase = reasonPhrase; this.Data[nameof(this.ReasonPhrase)] = reasonPhrase; this.Headers = headers; this.ContentHeaders = contentHeaders; this.Content = contentString; } /// /// Create a new , by reading the response asynchronously content as a string /// /// Request which triggered the exception /// Response received from the /// A new created from the public static async Task CreateAsync(HttpRequestMessage request, HttpResponseMessage response) { if (response.Content == null) return new ApiException(request, response, null); string? contentString = null; try { using (var content = response.Content) { contentString = await content.ReadAsStringAsync().ConfigureAwait(false); } } catch { } // Don't want to hide the original exception with a new one return new ApiException(request, response, contentString); } } }