using DataConnection.REST.Configuration; using DataConnection.REST.Interfaces; using System; using System.Collections.Generic; using System.Net.Http; using System.Net.Http.Headers; using System.Net.Http.Json; using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; namespace DataConnection.REST.Implementations { /// /// Base implementation for a REST service client using HttpClient. /// public class BaseRestServiceClient : IRestServiceClient, IDisposable { protected readonly HttpClient _httpClient; protected readonly RestServiceOptions _options; public BaseRestServiceClient(HttpClient httpClient, RestServiceOptions options) { _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient)); _options = options ?? throw new ArgumentNullException(nameof(options)); ConfigureHttpClient(); } protected virtual void ConfigureHttpClient() { if (!string.IsNullOrWhiteSpace(_options.BaseUrl)) { _httpClient.BaseAddress = new Uri(_options.BaseUrl); } _httpClient.Timeout = TimeSpan.FromSeconds(_options.TimeoutSeconds); _httpClient.DefaultRequestHeaders.Accept.Clear(); _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); // Add authentication headers based on options if (!string.IsNullOrWhiteSpace(_options.ApiKey)) { // Example: Add API key header (adjust header name as needed) _httpClient.DefaultRequestHeaders.TryAddWithoutValidation("X-API-KEY", _options.ApiKey); } else if (!string.IsNullOrWhiteSpace(_options.AuthToken)) { _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _options.AuthToken); } else if (!string.IsNullOrWhiteSpace(_options.Username) && !string.IsNullOrWhiteSpace(_options.Password)) { var basicAuthValue = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{_options.Username}:{_options.Password}")); _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", basicAuthValue); } // Add other authentication methods (e.g., OAuth) if necessary } public virtual async Task GetAsync(string requestUri, CancellationToken cancellationToken = default) { try { var response = await _httpClient.GetAsync(requestUri, cancellationToken); response.EnsureSuccessStatusCode(); // Throws exception for non-success status codes return await response.Content.ReadFromJsonAsync(cancellationToken: cancellationToken); } catch (HttpRequestException ex) { // Log or handle specific HTTP request errors Console.WriteLine($"HTTP Request Error: {ex.Message}"); // Consider custom exception handling throw; } catch (Exception ex) { // Log or handle other errors (e.g., deserialization) Console.WriteLine($"Error during GET request: {ex.Message}"); throw; } } public virtual async Task PostAsync(string requestUri, TRequest payload, CancellationToken cancellationToken = default) { try { var response = await _httpClient.PostAsJsonAsync(requestUri, payload, cancellationToken); response.EnsureSuccessStatusCode(); return await response.Content.ReadFromJsonAsync(cancellationToken: cancellationToken); } catch (HttpRequestException ex) { Console.WriteLine($"HTTP Request Error: {ex.Message}"); throw; } catch (Exception ex) { Console.WriteLine($"Error during POST request: {ex.Message}"); throw; } } public virtual async Task?> CreateEntityAsync(string entityName, Dictionary entityData, CancellationToken cancellationToken = default) { // Default implementation - derived classes should override this for service-specific logic try { var response = await _httpClient.PostAsJsonAsync($"/{entityName}", entityData, cancellationToken); response.EnsureSuccessStatusCode(); var responseContent = await response.Content.ReadAsStringAsync(cancellationToken); if (string.IsNullOrEmpty(responseContent)) return entityData; // Return original data if no response content var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; return JsonSerializer.Deserialize>(responseContent, options); } catch (HttpRequestException ex) { Console.WriteLine($"HTTP Request Error during entity creation: {ex.Message}"); throw; } catch (Exception ex) { Console.WriteLine($"Error during entity creation: {ex.Message}"); throw; } } // Implement other methods (PUT, DELETE, etc.) similarly public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing) { // HttpClient is typically managed by HttpClientFactory, // but if created directly, dispose it here. // _httpClient?.Dispose(); } } } }