feat: Implement ExistingDatabaseContext for managing existing databases with customizable naming strategies and auto-discovery of entities
feat: Add SqlServerSchemaProvider for extracting database schema information from SQL Server feat: Introduce DatabaseType and NamingStrategy enums for better database management and naming conventions feat: Create IDatabaseDiscovery and IDatabaseManager interfaces for database operations and metadata retrieval feat: Develop REST service client architecture with BaseRestServiceClient and SAP Business One specific implementation feat: Implement REST service discovery page with UI for connecting to SAP Business One Service Layer and displaying discovered entities
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
using DataConnection.REST.Configuration;
|
||||
using DataConnection.REST.Interfaces;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DataConnection.REST.Implementations
|
||||
{
|
||||
/// <summary>
|
||||
/// Base implementation for a REST service client using HttpClient.
|
||||
/// </summary>
|
||||
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<T?> GetAsync<T>(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<T>(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<TResponse?> PostAsync<TRequest, TResponse>(string requestUri, TRequest payload, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await _httpClient.PostAsJsonAsync(requestUri, payload, cancellationToken);
|
||||
response.EnsureSuccessStatusCode();
|
||||
return await response.Content.ReadFromJsonAsync<TResponse>(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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user