Refactor: Remove GlobalVar and replace with IAppSettings; restructure affected infrastructure, services, and view models for dependency injection.
This commit is contained in:
@@ -47,9 +47,11 @@ internal sealed class ApiClient : IApiClient {
|
||||
|
||||
public async Task<T> SendAsync<T>(HttpMethod method, string path, object? body = null,
|
||||
IDictionary<string, string?>? query = null, CancellationToken ct = default) {
|
||||
|
||||
// Absolute URI aus aktuellem Settings‑BaseUrl bauen, ohne HttpClient.BaseAddress zu nutzen.
|
||||
var uri = BuildAbsoluteUri(_settings.ApiUrl, path, query);
|
||||
using var req = new HttpRequestMessage(method, uri);
|
||||
|
||||
// Authorization PRO REQUEST setzen (immer, wenn Token vorhanden ist)
|
||||
// Hinweis: Das QR-Token kann RFC-unzulässige Zeichen (z. B. '|') enthalten.
|
||||
// AuthenticationHeaderValue würde solche Werte ablehnen. Daher ohne Validierung setzen.
|
||||
@@ -134,43 +136,44 @@ internal sealed class ApiClient : IApiClient {
|
||||
throw new InvalidOperationException(
|
||||
"ApiUrl ist leer. Bitte zuerst eine gültige Server-URL setzen (Preferences key 'apiUrl').");
|
||||
|
||||
// Basis muss absolut sein (z. B. https://host/appapi/)
|
||||
var baseUri = new Uri(baseUrl, UriKind.Absolute);
|
||||
|
||||
var normalizedBase = baseUrl.Trim();
|
||||
// Pfad relativ zur Basis aufbauen
|
||||
string relativePath = path ?? string.Empty;
|
||||
|
||||
if (relativePath.StartsWith('/'))
|
||||
relativePath = relativePath.TrimStart('/');
|
||||
|
||||
if (query is not null && query.Count > 0) {
|
||||
if (normalizedBase.EndsWith('/'))
|
||||
normalizedBase = normalizedBase.TrimEnd('/');
|
||||
|
||||
var sb = new StringBuilder(relativePath);
|
||||
sb.Append(relativePath.Contains('?') ? '&' : '?');
|
||||
sb.Append(string.Join('&', query
|
||||
.Where(kv => kv.Value is not null)
|
||||
.Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value!)}")));
|
||||
relativePath = sb.ToString();
|
||||
} else {
|
||||
if (!normalizedBase.EndsWith('/'))
|
||||
normalizedBase += "/";
|
||||
}
|
||||
|
||||
var baseUri = new Uri(normalizedBase, UriKind.Absolute);
|
||||
|
||||
// Wenn path bereits absolut ist, direkt verwenden
|
||||
//if (Uri.TryCreate(relativePath, UriKind.Absolute, out var absoluteFromPath))
|
||||
// return absoluteFromPath;
|
||||
|
||||
// Sonderfall: Wenn path ein absoluter file:// URI ist, diesen relativ zur Basis behandeln
|
||||
// Weiß nicht wie file:// zustande kommt, vermutlich wäre das zu verhindern
|
||||
if (Uri.TryCreate(relativePath, UriKind.Absolute, out var uri)) {
|
||||
if (uri.Scheme == Uri.UriSchemeFile) {
|
||||
|
||||
var normalizedBase = baseUrl.Trim();
|
||||
if (!normalizedBase.EndsWith('/'))
|
||||
normalizedBase += "/";
|
||||
|
||||
if (relativePath.StartsWith('/'))
|
||||
relativePath = relativePath.TrimStart('/');
|
||||
|
||||
var baseUriNormalized = new Uri(normalizedBase, UriKind.Absolute);
|
||||
return new Uri(baseUriNormalized, relativePath);
|
||||
}
|
||||
return uri;
|
||||
if (Uri.TryCreate(relativePath, UriKind.Absolute, out var absoluteFromPath)) {
|
||||
var uriString = absoluteFromPath.ToString();
|
||||
if (uriString.EndsWith('/') && absoluteFromPath.AbsolutePath.Length > 1)
|
||||
return new Uri(uriString.TrimEnd('/'));
|
||||
return absoluteFromPath;
|
||||
}
|
||||
|
||||
var result = new Uri(baseUri, relativePath);
|
||||
var finalUriString = result.ToString();
|
||||
if (finalUriString.EndsWith('/') && result.AbsolutePath.Length > 1)
|
||||
return new Uri(finalUriString.TrimEnd('/'));
|
||||
|
||||
return new Uri(baseUri, relativePath);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,18 @@
|
||||
using Jugenddienst_Stunden.Interfaces;
|
||||
using Jugenddienst_Stunden.Types;
|
||||
|
||||
namespace Jugenddienst_Stunden.Infrastructure;
|
||||
|
||||
internal sealed class PreferencesAppSettings : IAppSettings {
|
||||
/// <summary>
|
||||
/// Represents the application settings and provides access to user preferences
|
||||
/// such as API URL, API key, employee ID, and personal details.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The <c>AppSettings</c> class implements the <c>IAppSettings</c> interface and manages
|
||||
/// persistent configuration settings needed for the application.
|
||||
/// These settings include preferences like API configuration and user identification details.
|
||||
/// </remarks>
|
||||
internal sealed class AppSettings : IAppSettings {
|
||||
public string ApiUrl {
|
||||
get => Preferences.Default.Get("apiUrl", "");
|
||||
set => Preferences.Default.Set("apiUrl", value);
|
||||
@@ -27,4 +37,5 @@ internal sealed class PreferencesAppSettings : IAppSettings {
|
||||
get => Preferences.Default.Get("surname", "Eingeloggt");
|
||||
set => Preferences.Default.Set("surname", value);
|
||||
}
|
||||
public Settings? Settings { get; set; }
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
using Jugenddienst_Stunden.Interfaces;
|
||||
|
||||
namespace Jugenddienst_Stunden.Infrastructure;
|
||||
|
||||
internal sealed class GlobalVarTokenProvider : ITokenProvider {
|
||||
public string? GetToken() => Models.GlobalVar.ApiKey;
|
||||
}
|
||||
Reference in New Issue
Block a user