refit/Refit/ApiException.cs

241 строка
9.0 KiB
C#
Исходник Обычный вид История

using System.Net;
2017-06-21 18:58:02 +03:00
using System.Net.Http;
using System.Net.Http.Headers;
namespace Refit
{
/// <summary>
/// Represents an error that occured while sending an API request.
/// </summary>
2018-10-06 02:22:52 +03:00
[Serializable]
2017-06-21 18:58:02 +03:00
public class ApiException : Exception
{
/// <summary>
/// HTTP response status code.
/// </summary>
2018-01-28 20:50:46 +03:00
public HttpStatusCode StatusCode { get; }
/// <summary>
/// The reason phrase which typically is sent by the server together with the status code.
/// </summary>
2020-11-26 00:52:29 +03:00
public string? ReasonPhrase { get; }
/// <summary>
/// HTTP response headers.
/// </summary>
2018-01-28 20:50:46 +03:00
public HttpResponseHeaders Headers { get; }
/// <summary>
/// The HTTP method used to send the request.
/// </summary>
2018-01-28 20:50:46 +03:00
public HttpMethod HttpMethod { get; }
/// <summary>
/// The <see cref="System.Uri"/> used to send the HTTP request.
/// </summary>
2020-11-26 00:52:29 +03:00
public Uri? Uri => RequestMessage.RequestUri;
/// <summary>
/// The HTTP Request message used to send the request.
/// </summary>
2018-01-28 20:50:46 +03:00
public HttpRequestMessage RequestMessage { get; }
/// <summary>
/// HTTP response content headers as defined in RFC 2616.
/// </summary>
2020-11-26 00:52:29 +03:00
public HttpContentHeaders? ContentHeaders { get; private set; }
/// <summary>
/// HTTP Response content as string.
/// </summary>
2020-11-26 00:52:29 +03:00
public string? Content { get; private set; }
/// <summary>
/// Does the response have content?
/// </summary>
2017-06-21 18:58:02 +03:00
public bool HasContent => !string.IsNullOrWhiteSpace(Content);
/// <summary>
/// Refit settings used to send the request.
/// </summary>
2020-11-26 00:52:29 +03:00
public RefitSettings RefitSettings { get; }
2017-06-21 18:58:02 +03:00
/// <summary>
/// Initializes a new instance of the <see cref="ApiException"/> class.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="httpMethod">The HTTP method.</param>
/// <param name="content">The content.</param>
/// <param name="statusCode">The status code.</param>
/// <param name="reasonPhrase">The reason phrase.</param>
/// <param name="headers">The headers.</param>
/// <param name="refitSettings">The refit settings.</param>
/// <param name="innerException">The inner exception.</param>
2023-11-27 01:50:46 +03:00
protected ApiException(
HttpRequestMessage message,
HttpMethod httpMethod,
string? content,
HttpStatusCode statusCode,
string? reasonPhrase,
HttpResponseHeaders headers,
RefitSettings refitSettings,
Exception? innerException = null
)
: this(
CreateMessage(statusCode, reasonPhrase),
message,
httpMethod,
content,
statusCode,
reasonPhrase,
headers,
refitSettings,
innerException
) { }
/// <summary>
/// Initializes a new instance of the <see cref="ApiException"/> class.
/// </summary>
/// <param name="exceptionMessage">The exception message.</param>
/// <param name="message">The message.</param>
/// <param name="httpMethod">The HTTP method.</param>
/// <param name="content">The content.</param>
/// <param name="statusCode">The status code.</param>
/// <param name="reasonPhrase">The reason phrase.</param>
/// <param name="headers">The headers.</param>
/// <param name="refitSettings">The refit settings.</param>
/// <param name="innerException">The inner exception.</param>
2023-11-27 01:50:46 +03:00
protected ApiException(
string exceptionMessage,
HttpRequestMessage message,
HttpMethod httpMethod,
string? content,
HttpStatusCode statusCode,
string? reasonPhrase,
HttpResponseHeaders headers,
RefitSettings refitSettings,
Exception? innerException = null
)
: base(exceptionMessage, innerException)
2017-06-21 18:58:02 +03:00
{
2018-01-28 20:50:46 +03:00
RequestMessage = message;
2017-06-21 18:58:02 +03:00
HttpMethod = httpMethod;
StatusCode = statusCode;
ReasonPhrase = reasonPhrase;
Headers = headers;
RefitSettings = refitSettings;
Content = content;
2017-06-21 18:58:02 +03:00
}
/// <summary>
/// Get the deserialized response content as nullable <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">Type to deserialize the content to</typeparam>
/// <returns>The response content deserialized as <typeparamref name="T"/></returns>
2023-11-27 01:50:46 +03:00
public async Task<T?> GetContentAsAsync<T>() =>
HasContent
? await RefitSettings.ContentSerializer
.FromHttpContentAsync<T>(new StringContent(Content!))
.ConfigureAwait(false)
: default;
2017-06-21 18:58:02 +03:00
/// <summary>
/// Create an instance of <see cref="ApiException"/>.
/// </summary>
/// <param name="message">The HTTP Request message used to send the request.</param>
/// <param name="httpMethod">The HTTP method used to send the request.</param>
/// <param name="response">The HTTP Response message.</param>
/// <param name="refitSettings">Refit settings used to sent the request.</param>
/// <param name="innerException">Add an inner exception to the <see cref="ApiException"/>.</param>
/// <returns>A newly created <see cref="ApiException"/>.</returns>
2017-06-21 18:58:02 +03:00
#pragma warning disable VSTHRD200 // Use "Async" suffix for async methods
2023-11-27 01:50:46 +03:00
public static Task<ApiException> Create(
HttpRequestMessage message,
HttpMethod httpMethod,
HttpResponseMessage response,
RefitSettings refitSettings,
Exception? innerException = null
)
#pragma warning restore VSTHRD200 // Use "Async" suffix for async methods
{
var exceptionMessage = CreateMessage(response.StatusCode, response.ReasonPhrase);
2023-11-27 01:50:46 +03:00
return Create(
exceptionMessage,
message,
httpMethod,
response,
refitSettings,
innerException
);
}
/// <summary>
/// Create an instance of <see cref="ApiException"/> with a custom exception message.
/// </summary>
/// <param name="exceptionMessage">A custom exception message.</param>
/// <param name="message">The HTTP Request message used to send the request.</param>
/// <param name="httpMethod">The HTTP method used to send the request.</param>
/// <param name="response">The HTTP Response message.</param>
/// <param name="refitSettings">Refit settings used to sent the request.</param>
/// <param name="innerException">Add an inner exception to the <see cref="ApiException"/>.</param>
/// <returns>A newly created <see cref="ApiException"/>.</returns>
#pragma warning disable VSTHRD200 // Use "Async" suffix for async methods
2023-11-27 01:50:46 +03:00
public static async Task<ApiException> Create(
string exceptionMessage,
HttpRequestMessage message,
HttpMethod httpMethod,
HttpResponseMessage response,
RefitSettings refitSettings,
Exception? innerException = null
)
2017-06-21 18:58:02 +03:00
#pragma warning restore VSTHRD200 // Use "Async" suffix for async methods
{
2023-11-27 01:50:46 +03:00
var exception = new ApiException(
exceptionMessage,
message,
httpMethod,
null,
response.StatusCode,
response.ReasonPhrase,
response.Headers,
refitSettings,
innerException
);
2017-06-21 18:58:02 +03:00
if (response.Content == null)
{
2017-06-21 18:58:02 +03:00
return exception;
}
2017-06-21 18:58:02 +03:00
2018-01-28 20:50:46 +03:00
try
{
exception.ContentHeaders = response.Content.Headers;
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
exception.Content = content;
2023-11-27 01:50:46 +03:00
if (
response.Content.Headers?.ContentType?.MediaType?.Equals(
"application/problem+json"
) ?? false
)
{
2023-11-27 01:50:46 +03:00
exception = ValidationApiException.Create(exception);
}
2017-06-21 18:58:02 +03:00
response.Content.Dispose();
2018-01-28 20:50:46 +03:00
}
catch
{
2023-11-27 01:50:46 +03:00
// NB: We're already handling an exception at this point,
// so we want to make sure we don't throw another one
2017-06-21 18:58:02 +03:00
// that hides the real error.
}
return exception;
}
2020-11-26 00:52:29 +03:00
static string CreateMessage(HttpStatusCode statusCode, string? reasonPhrase) =>
2018-01-14 22:58:24 +03:00
$"Response status code does not indicate success: {(int)statusCode} ({reasonPhrase}).";
2017-06-21 18:58:02 +03:00
}
}