diff --git a/src/Tingle.Extensions.Http/AbstractHttpApiClientOptions.cs b/src/Tingle.Extensions.Http/AbstractHttpApiClientOptions.cs index 9f0ff9f..8c04cb4 100644 --- a/src/Tingle.Extensions.Http/AbstractHttpApiClientOptions.cs +++ b/src/Tingle.Extensions.Http/AbstractHttpApiClientOptions.cs @@ -27,12 +27,44 @@ public abstract class AbstractHttpApiClientOptions /// or . /// Defaults to false. /// - public virtual bool IncludeHeadersInExceptionMessage { get; set; } = false; + [Obsolete("Use '" + nameof(IncludeResponseHeadersInExceptionMessage) + "' instead.")] + public virtual bool IncludeHeadersInExceptionMessage { get => IncludeResponseHeadersInExceptionMessage; set => IncludeResponseHeadersInExceptionMessage = value; } /// - /// Determines if the raw body should be included in the message when creating + /// Determines if the response body should be included in the message when creating /// via . /// Defaults to false. /// - public virtual bool IncludeRawBodyInExceptionMessage { get; set; } = false; + [Obsolete("Use '" + nameof(IncludeResponseBodyInExceptionMessage) + "' instead.")] + public virtual bool IncludeRawBodyInExceptionMessage { get => IncludeResponseBodyInExceptionMessage; set => IncludeResponseBodyInExceptionMessage = value; } + + /// + /// Determines if the request headers should be included in the message when creating + /// via + /// or . + /// Defaults to false. + /// + public virtual bool IncludeRequestHeadersInExceptionMessage { get; set; } = false; + + /// + /// Determines if the request body should be included in the message when creating + /// via . + /// Defaults to false. + /// + public virtual bool IncludeRequestBodyInExceptionMessage { get; set; } = false; + + /// + /// Determines if the response headers should be included in the message when creating + /// via + /// or . + /// Defaults to false. + /// + public virtual bool IncludeResponseHeadersInExceptionMessage { get; set; } = false; + + /// + /// Determines if the response body should be included in the message when creating + /// via . + /// Defaults to false. + /// + public virtual bool IncludeResponseBodyInExceptionMessage { get; set; } = false; } diff --git a/src/Tingle.Extensions.Http/ResourceResponse.cs b/src/Tingle.Extensions.Http/ResourceResponse.cs index 90f0874..37bc314 100644 --- a/src/Tingle.Extensions.Http/ResourceResponse.cs +++ b/src/Tingle.Extensions.Http/ResourceResponse.cs @@ -125,8 +125,13 @@ protected HttpApiResponseException CreateException(string messagePrefix, bool ap /// The appended message. protected string AppendHeaders(string message) { - string serialize() => System.Text.Json.JsonSerializer.Serialize(Headers, SC.Default.ResourceResponseHeaders); - return AppendIf(message, o => o.IncludeHeadersInExceptionMessage, serialize, "Headers:\n{0}"); + static string serialize(ResourceResponseHeaders headers) => System.Text.Json.JsonSerializer.Serialize(headers, SC.Default.ResourceResponseHeaders); + string serializeRequest() => serialize(new(Response.RequestMessage)); + string serializeResponse() => serialize(Headers); + + message = AppendIf(message, o => o.IncludeRequestHeadersInExceptionMessage, serializeRequest, "Request Headers:\n{0}"); + message = AppendIf(message, o => o.IncludeResponseHeadersInExceptionMessage, serializeResponse, "Response Headers:\n{0}"); + return message; } /// Append the raw body if present to an error message. @@ -134,8 +139,13 @@ protected string AppendHeaders(string message) /// The appended message. protected string AppendRawBody(string message) { - string serialize() => Response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); - return AppendIf(message, o => o.IncludeRawBodyInExceptionMessage, serialize, "Body:\n{0}"); + static string serialize(HttpContent content) => content.ReadAsStringAsync().GetAwaiter().GetResult(); + string serializeRequest() => serialize(Response.RequestMessage.Content); + string serializeResponse() => serialize(Response.Content); + + message = AppendIf(message, o => o.IncludeRequestBodyInExceptionMessage, serializeRequest, "Request Body:\n{0}"); + message = AppendIf(message, o => o.IncludeResponseBodyInExceptionMessage, serializeResponse, "Response Body:\n{0}"); + return message; } private string AppendIf(string message, Func evaluator, Func serialize, string format) diff --git a/src/Tingle.Extensions.Http/ResourceResponseHeaders.cs b/src/Tingle.Extensions.Http/ResourceResponseHeaders.cs index 724d9d6..5ecca33 100644 --- a/src/Tingle.Extensions.Http/ResourceResponseHeaders.cs +++ b/src/Tingle.Extensions.Http/ResourceResponseHeaders.cs @@ -9,6 +9,10 @@ public class ResourceResponseHeaders : Dictionary> /// The original HTTP response. public ResourceResponseHeaders(HttpResponseMessage response) : this(response.Headers.Concat(response.Content.Headers)) { } + /// Creates an instance of . + /// The original HTTP request. + public ResourceResponseHeaders(HttpRequestMessage response) : this(response.Headers.Concat(response.Content.Headers)) { } + /// Creates an instance of . /// The combined headers. public ResourceResponseHeaders(IEnumerable>> data) diff --git a/src/Tingle.Extensions.PushNotifications/IServiceCollectionExtensions.cs b/src/Tingle.Extensions.PushNotifications/IServiceCollectionExtensions.cs index 8b68580..e326ffa 100644 --- a/src/Tingle.Extensions.PushNotifications/IServiceCollectionExtensions.cs +++ b/src/Tingle.Extensions.PushNotifications/IServiceCollectionExtensions.cs @@ -74,8 +74,8 @@ private static IHttpClientBuilder AddNotifier(this IService return services.AddHttpApiClient(options => { // include error details in the exception - options.IncludeHeadersInExceptionMessage = true; - options.IncludeRawBodyInExceptionMessage = true; + options.IncludeResponseHeadersInExceptionMessage = true; + options.IncludeResponseBodyInExceptionMessage = true; configure?.Invoke(options); }); diff --git a/tests/Tingle.Extensions.Http.Tests/ResourceResponseTests.cs b/tests/Tingle.Extensions.Http.Tests/ResourceResponseTests.cs index 55191eb..4a206df 100644 --- a/tests/Tingle.Extensions.Http.Tests/ResourceResponseTests.cs +++ b/tests/Tingle.Extensions.Http.Tests/ResourceResponseTests.cs @@ -49,20 +49,26 @@ public void EnsureSuccess_Throws_Exception() { var response = new HttpResponseMessage(HttpStatusCode.NotFound); response.Headers.Date = new DateTimeOffset(DateTimeOffset.UtcNow.Date, TimeSpan.Zero); - response.Content = new StringContent("{\"status\":404}"); + response.Content = new StringContent("{\"status\":404}", System.Text.Encoding.UTF8, "application/json"); + response.RequestMessage = new HttpRequestMessage(HttpMethod.Get, "https://localhost") { Content = new StringContent("{\"action\":\"write\"}"), }; var options = new DummyHttpApiClientOptions { - IncludeHeadersInExceptionMessage = true, - IncludeRawBodyInExceptionMessage = true, + IncludeRequestHeadersInExceptionMessage = true, + IncludeRequestBodyInExceptionMessage = true, + + IncludeResponseHeadersInExceptionMessage = true, + IncludeResponseBodyInExceptionMessage = true, }; var rr = new ResourceResponse(response, options); Assert.Equal(HttpStatusCode.NotFound, rr.StatusCode); var message = "The HTTP request failed with code 404 (NotFound)\n" - + $"\nHeaders:\n{{\"Date\":[\"{response.Headers.Date:r}\"],\"Content-Type\":[\"text/plain; charset=utf-8\"]}}\n" - + "\nBody:\n{\"status\":404}"; + + "\nRequest Headers:\n{\"Content-Type\":[\"text/plain; charset=utf-8\"]}\n" + + $"\nResponse Headers:\n{{\"Date\":[\"{response.Headers.Date:r}\"],\"Content-Type\":[\"application/json; charset=utf-8\"]}}\n" + + "\nRequest Body:\n{\"action\":\"write\"}\n" + + "\nResponse Body:\n{\"status\":404}"; var ex = Assert.Throws(rr.EnsureSuccess); Assert.Equal(message, ex.Message);