Refactor: Remove GlobalVar and replace with IAppSettings; restructure affected infrastructure, services, and view models for dependency injection.

This commit is contained in:
2025-12-26 11:43:20 +01:00
parent 1ee0fc61f6
commit 4d5b093ea0
15 changed files with 103 additions and 463 deletions

View File

@@ -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 SettingsBaseUrl 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;
}
}