From da033d22c9caf52a1ccab50cf373fd8c0a06e135 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Tue, 5 May 2026 11:32:37 +0100 Subject: [PATCH] remove temp class ClientBase --- SecurityService.Client/ClientBase.cs | 712 ------------------ .../SecurityServiceClient.cs | 15 +- 2 files changed, 2 insertions(+), 725 deletions(-) delete mode 100644 SecurityService.Client/ClientBase.cs diff --git a/SecurityService.Client/ClientBase.cs b/SecurityService.Client/ClientBase.cs deleted file mode 100644 index 2028cf2c..00000000 --- a/SecurityService.Client/ClientBase.cs +++ /dev/null @@ -1,712 +0,0 @@ -using SimpleResults; -using System; -using System.Collections.Generic; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Text; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; - -namespace SecurityService.Client -{ - public abstract class ClientBase - { - private readonly HttpClient HttpClient; - private readonly Func Serialise; - private readonly Func Deserialise; - - public ClientBase( - HttpClient httpClient, - Func serialise, - Func deserialise) - { - HttpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient)); - Serialise = serialise ?? throw new ArgumentNullException(nameof(serialise)); - Deserialise = deserialise ?? throw new ArgumentNullException(nameof(deserialise)); - } - - public Task> Get(string requestUri, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Get, requestUri, body: null, accessToken: null, additionalHeaders: null, cancellationToken); - - public Task> Get(string requestUri, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Get, requestUri, body: null, accessToken: null, additionalHeaders, cancellationToken); - - public Task> Get(string requestUri, string accessToken, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Get, requestUri, body: null, accessToken, additionalHeaders: null, cancellationToken); - - public Task> Get(string requestUri, string accessToken, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Get, requestUri, body: null, accessToken, additionalHeaders, cancellationToken); - - public Task Delete(string requestUri, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Delete, requestUri, body: null, accessToken: null, additionalHeaders: null, cancellationToken); - - public Task Delete(string requestUri, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Delete, requestUri, body: null, accessToken: null, additionalHeaders, cancellationToken); - - public Task Delete(string requestUri, string accessToken, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Delete, requestUri, body: null, accessToken, additionalHeaders: null, cancellationToken); - - public Task Delete(string requestUri, string accessToken, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Delete, requestUri, body: null, accessToken, additionalHeaders, cancellationToken); - - public Task Post(string requestUri, TRequest request, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Post, requestUri, request, accessToken: null, additionalHeaders: null, cancellationToken); - - public Task Post(string requestUri, TRequest request, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Post, requestUri, request, accessToken: null, additionalHeaders, cancellationToken); - - public Task Post(string requestUri, TRequest request, string accessToken, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Post, requestUri, request, accessToken, additionalHeaders: null, cancellationToken); - - public Task Post(string requestUri, TRequest request, string accessToken, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Post, requestUri, request, accessToken, additionalHeaders, cancellationToken); - - public Task Post(string requestUri, HttpContent content, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Post, requestUri, content, accessToken: null, additionalHeaders: null, cancellationToken); - - public Task Post(string requestUri, HttpContent content, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Post, requestUri, content, accessToken: null, additionalHeaders, cancellationToken); - - public Task Post(string requestUri, HttpContent content, string accessToken, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Post, requestUri, content, accessToken, additionalHeaders: null, cancellationToken); - - public Task Post(string requestUri, HttpContent content, string accessToken, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Post, requestUri, content, accessToken, additionalHeaders, cancellationToken); - - public Task Post(string requestUri, byte[] fileData, string fileName, List<(string field, string value)> formFields, string accessToken, CancellationToken cancellationToken = default) - => SendMultipartWithoutResponse(requestUri, fileData, fileName, formFields, accessToken, additionalHeaders: null, cancellationToken); - - public Task Post(string requestUri, byte[] fileData, string fileName, List<(string field, string value)> formFields, string accessToken, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendMultipartWithoutResponse(requestUri, fileData, fileName, formFields, accessToken, additionalHeaders, cancellationToken); - - public Task> Post(string requestUri, TRequest request, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Post, requestUri, request, accessToken: null, additionalHeaders: null, cancellationToken); - - public Task> Post(string requestUri, TRequest request, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Post, requestUri, request, accessToken: null, additionalHeaders, cancellationToken); - - public Task> Post(string requestUri, TRequest request, string accessToken, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Post, requestUri, request, accessToken, additionalHeaders: null, cancellationToken); - - public Task> Post(string requestUri, TRequest request, string accessToken, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Post, requestUri, request, accessToken, additionalHeaders, cancellationToken); - - public Task> Post(string requestUri, HttpContent content, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Post, requestUri, content, accessToken: null, additionalHeaders: null, cancellationToken); - - public Task> Post(string requestUri, HttpContent content, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Post, requestUri, content, accessToken: null, additionalHeaders, cancellationToken); - - public Task> Post(string requestUri, HttpContent content, string accessToken, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Post, requestUri, content, accessToken, additionalHeaders: null, cancellationToken); - - public Task> Post(string requestUri, HttpContent content, string accessToken, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Post, requestUri, content, accessToken, additionalHeaders, cancellationToken); - - public Task Put(string requestUri, TRequest request, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Put, requestUri, request, accessToken: null, additionalHeaders: null, cancellationToken); - - public Task Put(string requestUri, TRequest request, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Put, requestUri, request, accessToken: null, additionalHeaders, cancellationToken); - - public Task Put(string requestUri, TRequest request, string accessToken, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Put, requestUri, request, accessToken, additionalHeaders: null, cancellationToken); - - public Task Put(string requestUri, TRequest request, string accessToken, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Put, requestUri, request, accessToken, additionalHeaders, cancellationToken); - - public Task Put(string requestUri, HttpContent content, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Put, requestUri, content, accessToken: null, additionalHeaders: null, cancellationToken); - - public Task Put(string requestUri, HttpContent content, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Put, requestUri, content, accessToken: null, additionalHeaders, cancellationToken); - - public Task Put(string requestUri, HttpContent content, string accessToken, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Put, requestUri, content, accessToken, additionalHeaders: null, cancellationToken); - - public Task Put(string requestUri, HttpContent content, string accessToken, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Put, requestUri, content, accessToken, additionalHeaders, cancellationToken); - - public Task> Put(string requestUri, TRequest request, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Put, requestUri, request, accessToken: null, additionalHeaders: null, cancellationToken); - - public Task> Put(string requestUri, TRequest request, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Put, requestUri, request, accessToken: null, additionalHeaders, cancellationToken); - - public Task> Put(string requestUri, TRequest request, string accessToken, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Put, requestUri, request, accessToken, additionalHeaders: null, cancellationToken); - - public Task> Put(string requestUri, TRequest request, string accessToken, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Put, requestUri, request, accessToken, additionalHeaders, cancellationToken); - - public Task> Put(string requestUri, HttpContent content, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Put, requestUri, content, accessToken: null, additionalHeaders: null, cancellationToken); - - public Task> Put(string requestUri, HttpContent content, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Put, requestUri, content, accessToken: null, additionalHeaders, cancellationToken); - - public Task> Put(string requestUri, HttpContent content, string accessToken, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Put, requestUri, content, accessToken, additionalHeaders: null, cancellationToken); - - public Task> Put(string requestUri, HttpContent content, string accessToken, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Put, requestUri, content, accessToken, additionalHeaders, cancellationToken); - - public Task Patch(string requestUri, TRequest request, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Patch, requestUri, request, accessToken: null, additionalHeaders: null, cancellationToken); - - public Task Patch(string requestUri, TRequest request, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Patch, requestUri, request, accessToken: null, additionalHeaders, cancellationToken); - - public Task Patch(string requestUri, TRequest request, string accessToken, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Patch, requestUri, request, accessToken, additionalHeaders: null, cancellationToken); - - public Task Patch(string requestUri, TRequest request, string accessToken, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Patch, requestUri, request, accessToken, additionalHeaders, cancellationToken); - - public Task Patch(string requestUri, HttpContent content, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Patch, requestUri, content, accessToken: null, additionalHeaders: null, cancellationToken); - - public Task Patch(string requestUri, HttpContent content, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Patch, requestUri, content, accessToken: null, additionalHeaders, cancellationToken); - - public Task Patch(string requestUri, HttpContent content, string accessToken, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Patch, requestUri, content, accessToken, additionalHeaders: null, cancellationToken); - - public Task Patch(string requestUri, HttpContent content, string accessToken, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendWithoutResponse(HttpMethod.Patch, requestUri, content, accessToken, additionalHeaders, cancellationToken); - - public Task> Patch(string requestUri, TRequest request, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Patch, requestUri, request, accessToken: null, additionalHeaders: null, cancellationToken); - - public Task> Patch(string requestUri, TRequest request, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Patch, requestUri, request, accessToken: null, additionalHeaders, cancellationToken); - - public Task> Patch(string requestUri, TRequest request, string accessToken, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Patch, requestUri, request, accessToken, additionalHeaders: null, cancellationToken); - - public Task> Patch(string requestUri, TRequest request, string accessToken, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Patch, requestUri, request, accessToken, additionalHeaders, cancellationToken); - - public Task> Patch(string requestUri, HttpContent content, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Patch, requestUri, content, accessToken: null, additionalHeaders: null, cancellationToken); - - public Task> Patch(string requestUri, HttpContent content, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Patch, requestUri, content, accessToken: null, additionalHeaders, cancellationToken); - - public Task> Patch(string requestUri, HttpContent content, string accessToken, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Patch, requestUri, content, accessToken, additionalHeaders: null, cancellationToken); - - public Task> Patch(string requestUri, HttpContent content, string accessToken, List<(string header, string value)> additionalHeaders, CancellationToken cancellationToken = default) - => SendForResponse(HttpMethod.Patch, requestUri, content, accessToken, additionalHeaders, cancellationToken); - - private async Task SendWithoutResponse(HttpMethod method, - string requestUri, - TRequest? body, - string? accessToken, - List<(string header, string value)>? additionalHeaders, - CancellationToken cancellationToken) - { - try - { - using var request = CreateRequest(method, requestUri, body, accessToken, additionalHeaders); - using var response = await HttpClient.SendAsync(request, cancellationToken); - return await MapNonGenericResult(method, response, cancellationToken); - } - catch (InvalidOperationException exception) - { - return Result.Failure(exception.Message); - } - catch (HttpRequestException exception) - { - return Result.CriticalError(exception.Message); - } - catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested) - { - return Result.CriticalError("The HTTP request timed out."); - } - } - - private async Task SendWithoutResponse(HttpMethod method, - string requestUri, - HttpContent content, - string? accessToken, - List<(string header, string value)>? additionalHeaders, - CancellationToken cancellationToken) - { - try - { - using var request = CreateRequest(method, requestUri, content, accessToken, additionalHeaders); - using var response = await HttpClient.SendAsync(request, cancellationToken); - return await MapNonGenericResult(method, response, cancellationToken); - } - catch (InvalidOperationException exception) - { - return Result.Failure(exception.Message); - } - catch (HttpRequestException exception) - { - return Result.CriticalError(exception.Message); - } - catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested) - { - return Result.CriticalError("The HTTP request timed out."); - } - } - - private async Task SendMultipartWithoutResponse( - string requestUri, - byte[] fileData, - string fileName, - List<(string field, string value)> formFields, - string accessToken, - List<(string header, string value)>? additionalHeaders, - CancellationToken cancellationToken) - { - try - { - using var request = CreateMultipartRequest(requestUri, fileData, fileName, formFields, accessToken, additionalHeaders); - using var response = await HttpClient.SendAsync(request, cancellationToken); - return await MapNonGenericResult(HttpMethod.Post, response, cancellationToken); - } - catch (InvalidOperationException exception) - { - return Result.Failure(exception.Message); - } - catch (HttpRequestException exception) - { - return Result.CriticalError(exception.Message); - } - catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested) - { - return Result.CriticalError("The HTTP request timed out."); - } - } - - private async Task> SendForResponse(HttpMethod method, - string requestUri, - object? body, - string? accessToken, - List<(string header, string value)>? additionalHeaders, - CancellationToken cancellationToken) - { - try - { - using var request = CreateRequest(method, requestUri, body, accessToken, additionalHeaders); - using var response = await HttpClient.SendAsync(request, cancellationToken); - return await MapGenericResult(method, response, cancellationToken); - } - catch (InvalidOperationException exception) - { - return Result.Failure(exception.Message); - } - catch (HttpRequestException exception) - { - return Result.CriticalError(exception.Message); - } - catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested) - { - return Result.CriticalError("The HTTP request timed out."); - } - } - - private async Task> SendForResponse(HttpMethod method, - string requestUri, - HttpContent content, - string? accessToken, - List<(string header, string value)>? additionalHeaders, - CancellationToken cancellationToken) - { - try - { - using var request = CreateRequest(method, requestUri, content, accessToken, additionalHeaders); - using var response = await HttpClient.SendAsync(request, cancellationToken); - return await MapGenericResult(method, response, cancellationToken); - } - catch (InvalidOperationException exception) - { - return Result.Failure(exception.Message); - } - catch (HttpRequestException exception) - { - return Result.CriticalError(exception.Message); - } - catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested) - { - return Result.CriticalError("The HTTP request timed out."); - } - } - - private HttpRequestMessage CreateRequest(HttpMethod method, - string requestUri, - object? body, - string? accessToken, - List<(string header, string value)>? additionalHeaders) - { - if (string.IsNullOrWhiteSpace(requestUri)) - { - throw new ArgumentException("Request URI cannot be null, empty, or whitespace.", nameof(requestUri)); - } - - var request = new HttpRequestMessage(method, requestUri); - - if (accessToken is not null) - { - if (string.IsNullOrWhiteSpace(accessToken)) - { - throw new ArgumentException("Access token cannot be null, empty, or whitespace.", nameof(accessToken)); - } - - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); - } - - if (body is HttpContent httpContent) - { - request.Content = httpContent; - } - else if (body is not null) - { - string serialisedBody; - - try - { - serialisedBody = Serialise(body); - } - catch (Exception exception) - { - throw new InvalidOperationException($"The request body could not be serialized: {exception.Message}", exception); - } - - if (serialisedBody is null) - { - throw new InvalidOperationException("The request body could not be serialized."); - } - - request.Content = new StringContent(serialisedBody, Encoding.UTF8, "application/json"); - } - - if (additionalHeaders is not null) - { - AddHeaders(request, additionalHeaders); - } - - return request; - } - - private HttpRequestMessage CreateRequest(HttpMethod method, - string requestUri, - HttpContent content, - string? accessToken, - List<(string header, string value)>? additionalHeaders) - { - if (content is null) - { - throw new ArgumentNullException(nameof(content)); - } - - var request = CreateRequest(method, requestUri, body: null, accessToken, additionalHeaders: null); - request.Content = content; - - if (additionalHeaders is not null) - { - AddHeaders(request, additionalHeaders); - } - - return request; - } - - private HttpRequestMessage CreateMultipartRequest( - string requestUri, - byte[] fileData, - string fileName, - List<(string field, string value)> formFields, - string accessToken, - List<(string header, string value)>? additionalHeaders) - { - if (fileData is null) - { - throw new ArgumentNullException(nameof(fileData)); - } - - if (string.IsNullOrWhiteSpace(fileName)) - { - throw new ArgumentException("File name cannot be null, empty, or whitespace.", nameof(fileName)); - } - - if (formFields is null) - { - throw new ArgumentNullException(nameof(formFields)); - } - - var request = CreateRequest(HttpMethod.Post, requestUri, body: null, accessToken, additionalHeaders: null); - request.Content = CreateMultipartContent(fileData, fileName, formFields); - - if (additionalHeaders is not null) - { - AddHeaders(request, additionalHeaders); - } - - return request; - } - - private static void AddHeaders(HttpRequestMessage request, List<(string header, string value)> additionalHeaders) - { - foreach (var (header, value) in additionalHeaders) - { - if (string.IsNullOrWhiteSpace(header)) - { - throw new ArgumentException("Header name cannot be null, empty, or whitespace.", nameof(additionalHeaders)); - } - - if (string.IsNullOrWhiteSpace(value)) - { - throw new ArgumentException($"Header value for '{header}' cannot be null, empty, or whitespace.", nameof(additionalHeaders)); - } - - if (request.Headers.TryAddWithoutValidation(header, value)) - { - continue; - } - - if (request.Content is not null && request.Content.Headers.TryAddWithoutValidation(header, value)) - { - continue; - } - - throw new InvalidOperationException($"The header '{header}' could not be added to the request."); - } - } - - private static MultipartFormDataContent CreateMultipartContent( - byte[] fileData, - string fileName, - List<(string field, string value)> formFields) - { - var multipartContent = new MultipartFormDataContent(); - - var fileContent = new ByteArrayContent(fileData); - fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data"); - multipartContent.Add(fileContent, "file", fileName); - - foreach (var (field, value) in formFields) - { - if (string.IsNullOrWhiteSpace(field)) - { - throw new ArgumentException("Form field name cannot be null, empty, or whitespace.", nameof(formFields)); - } - - if (string.IsNullOrWhiteSpace(value)) - { - throw new ArgumentException($"Form field value for '{field}' cannot be null, empty, or whitespace.", nameof(formFields)); - } - - multipartContent.Add(new StringContent(value), field); - } - - return multipartContent; - } - - private async Task MapNonGenericResult(HttpMethod method, - HttpResponseMessage response, - CancellationToken cancellationToken) - { - if (response.IsSuccessStatusCode) - { - return MapSuccessfulResult(method, response.StatusCode); - } - - return await MapFailedResult(response, cancellationToken); - } - - private async Task> MapGenericResult(HttpMethod method, - HttpResponseMessage response, - CancellationToken cancellationToken) - { - if (!response.IsSuccessStatusCode) - { - return await MapFailedResult(response, cancellationToken); - } - - var rawContent = await ReadContent(response, cancellationToken); - if (string.IsNullOrWhiteSpace(rawContent)) - { - return Result.Failure("The response content was empty."); - } - - if (typeof(TResponse) == typeof(string)) - { - return Result.Success((TResponse)(object)rawContent); - } - - object deserialisedValue; - - try - { - deserialisedValue = Deserialise(rawContent, typeof(TResponse)); - } - catch (Exception exception) - { - return Result.Failure($"The response body could not be deserialized: {exception.Message}"); - } - - if (deserialisedValue is null) - { - return Result.Failure("The response body could not be deserialized."); - } - - if (deserialisedValue is not TResponse value) - { - return Result.Failure( - $"The deserialized response type '{deserialisedValue.GetType().FullName}' is not assignable to '{typeof(TResponse).FullName}'."); - } - - return method == HttpMethod.Get - ? Result.ObtainedResource(value) - : Result.Success(value); - } - - private static Result MapSuccessfulResult(HttpMethod method, HttpStatusCode statusCode) - { - if (method == HttpMethod.Delete) - { - return Result.DeletedResource(); - } - - if (method == HttpMethod.Post && statusCode == HttpStatusCode.Created) - { - return Result.CreatedResource(); - } - - if (method == HttpMethod.Put || method == HttpMethod.Patch) - { - return Result.UpdatedResource(); - } - - return Result.Success(); - } - - private static async Task MapFailedResult(HttpResponseMessage response, CancellationToken cancellationToken) - { - var rawContent = await ReadContent(response, cancellationToken); - var errorMessages = ExtractErrors(rawContent); - var primaryMessage = BuildPrimaryMessage(response, errorMessages); - - return response.StatusCode switch - { - HttpStatusCode.BadRequest => Result.Invalid(primaryMessage, errorMessages), - HttpStatusCode.Unauthorized => Result.Unauthorized(primaryMessage, errorMessages), - HttpStatusCode.Forbidden => Result.Forbidden(primaryMessage, errorMessages), - HttpStatusCode.NotFound => Result.NotFound(primaryMessage, errorMessages), - HttpStatusCode.Conflict => Result.Conflict(primaryMessage, errorMessages), - _ when (int)response.StatusCode >= 500 => Result.CriticalError(primaryMessage, errorMessages), - _ => Result.Failure(primaryMessage, errorMessages) - }; - } - - private static async Task ReadContent(HttpResponseMessage response, CancellationToken cancellationToken) - { - if (response.Content is null) - { - return null; - } - - return await response.Content.ReadAsStringAsync(cancellationToken); - } - - private static IReadOnlyList ExtractErrors(string? rawContent) - { - if (string.IsNullOrWhiteSpace(rawContent)) - { - return []; - } - - try - { - using var document = JsonDocument.Parse(rawContent); - var errors = new List(); - AppendErrors(document.RootElement, errors); - - return errors.Count == 0 ? [rawContent] : errors; - } - catch (JsonException) - { - return [rawContent]; - } - } - - private static void AppendErrors(JsonElement element, ICollection errors) - { - if (element.ValueKind == JsonValueKind.Object) - { - if (element.TryGetProperty("title", out var title) && title.ValueKind == JsonValueKind.String) - { - AddIfPresent(errors, title.GetString()); - } - - if (element.TryGetProperty("detail", out var detail) && detail.ValueKind == JsonValueKind.String) - { - AddIfPresent(errors, detail.GetString()); - } - - if (element.TryGetProperty("message", out var message) && message.ValueKind == JsonValueKind.String) - { - AddIfPresent(errors, message.GetString()); - } - - if (element.TryGetProperty("errors", out var nestedErrors)) - { - AppendErrors(nestedErrors, errors); - } - - foreach (var property in element.EnumerateObject()) - { - if (property.NameEquals("title") || property.NameEquals("detail") || property.NameEquals("message") || property.NameEquals("errors")) - { - continue; - } - - if (property.Value.ValueKind is JsonValueKind.Array or JsonValueKind.Object) - { - AppendErrors(property.Value, errors); - } - } - - return; - } - - if (element.ValueKind == JsonValueKind.Array) - { - foreach (var item in element.EnumerateArray()) - { - AppendErrors(item, errors); - } - - return; - } - - if (element.ValueKind == JsonValueKind.String) - { - AddIfPresent(errors, element.GetString()); - } - } - - private static void AddIfPresent(ICollection errors, string? value) - { - if (!string.IsNullOrWhiteSpace(value)) - { - errors.Add(value); - } - } - - private static string BuildPrimaryMessage(HttpResponseMessage response, IReadOnlyList errors) - { - if (errors.Count > 0) - { - return errors[0]; - } - - return response.ReasonPhrase ?? $"Request failed with status code {(int)response.StatusCode}."; - } - } -} diff --git a/SecurityService.Client/SecurityServiceClient.cs b/SecurityService.Client/SecurityServiceClient.cs index f1eea49c..87f10e6a 100644 --- a/SecurityService.Client/SecurityServiceClient.cs +++ b/SecurityService.Client/SecurityServiceClient.cs @@ -1,5 +1,4 @@ -using Newtonsoft.Json; -using Shared.Results; +using Shared.Results; using SimpleResults; namespace SecurityService.Client @@ -18,18 +17,8 @@ namespace SecurityService.Client /// /// /// - public class SecurityServiceClient : ClientBase, ISecurityServiceClient + public class SecurityServiceClient : ClientProxyBase, ISecurityServiceClient { - //private static String Serialise(Object arg) - //{ - // return JsonConvert.SerializeObject(arg); - //} - - //private static Object Deserialise(String arg, Type type) - //{ - // return JsonConvert.DeserializeObject(arg, type); - //} - #region Fields ///