Add SocketsHttpHandler

This commit is contained in:
2025-12-25 09:03:01 +01:00
parent cd4eae34c3
commit 8da8734065
3 changed files with 54 additions and 13 deletions

View File

@@ -0,0 +1,29 @@
using Jugenddienst_Stunden.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using System.Net.Http;
namespace Jugenddienst_Stunden.Infrastructure;
internal static class HttpClientRegistration {
/// <summary>
/// Registriert den ApiClient mit einem SocketsHttpHandler als prim<69>ren MessageHandler.
/// Vermeidet den Android-spezifischen Cast-Fehler in Xamarin.Android.Net.AndroidMessageHandler.
///</summary>
public static IServiceCollection AddApiHttpClient(this IServiceCollection services, ApiOptions options) {
if (services is null)
throw new ArgumentNullException(nameof(services));
if (options is null)
throw new ArgumentNullException(nameof(options));
// ApiOptions als Singleton bereitstellen (kann nach Bedarf angepasst werden)
services.AddSingleton(options);
// HttpClient f<>r ApiClient registrieren und einen SocketsHttpHandler verwenden.
// SocketsHttpHandler vermeidet das problematische Casting, das bei AndroidMessageHandler
// zur InvalidCastException (URLConnectionInvoker -> HttpURLConnection) f<>hrt.
services.AddHttpClient<IApiClient, ApiClient>()
.ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler());
return services;
}
}

View File

@@ -263,6 +263,7 @@
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="9.0.110" /> <PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="9.0.110" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="9.0.9" /> <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="9.0.9" />
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.0" />
<PackageReference Include="Microsoft.Maui.Graphics" Version="9.0.110" /> <PackageReference Include="Microsoft.Maui.Graphics" Version="9.0.110" />
<PackageReference Include="Microsoft.NET.Runtime.MonoAOTCompiler.Task" Version="9.0.9" /> <PackageReference Include="Microsoft.NET.Runtime.MonoAOTCompiler.Task" Version="9.0.9" />
<PackageReference Include="Microsoft.NET.Runtime.WebAssembly.Wasi.Sdk" Version="9.0.9" /> <PackageReference Include="Microsoft.NET.Runtime.WebAssembly.Wasi.Sdk" Version="9.0.9" />

View File

@@ -9,6 +9,7 @@ using Microsoft.Extensions.Logging;
using ZXing.Net.Maui.Controls; using ZXing.Net.Maui.Controls;
using System.Net.Http; using System.Net.Http;
using Jugenddienst_Stunden.ViewModels; using Jugenddienst_Stunden.ViewModels;
using System.Net;
namespace Jugenddienst_Stunden; namespace Jugenddienst_Stunden;
@@ -32,7 +33,7 @@ public static class MauiProgram {
//#if DEBUG //#if DEBUG
// if (string.IsNullOrWhiteSpace(GlobalVar.ApiKey)) { // if (string.IsNullOrWhiteSpace(GlobalVar.ApiKey)) {
// GlobalVar.ApiKey = Preferences.Default.Get("apiKey", // GlobalVar.ApiKey = Preferences.Default.Get("apiKey",
// "MTQxfHNkdFptQkNZTXlPT3ZyMHNBZDl0UnVxNExMRXxodHRwOi8vaG91cnMuZGF1bmkubWluZS5udTo4MS9hcHBhcGk="); // "MTQxfHNkdFptQkNZTXlPT3ZyMHxodHRwOi8vaG91cnMuZGF1bmkubWluZS5udTo4MS9hcHBhcGk=");
// GlobalVar.Name = Preferences.Default.Get("name", "Testserver: Isabell"); // GlobalVar.Name = Preferences.Default.Get("name", "Testserver: Isabell");
// GlobalVar.Surname = Preferences.Default.Get("surname", "Biasi"); // GlobalVar.Surname = Preferences.Default.Get("surname", "Biasi");
// GlobalVar.EmployeeId = Preferences.Default.Get("EmployeeId", 141); // GlobalVar.EmployeeId = Preferences.Default.Get("EmployeeId", 141);
@@ -42,6 +43,10 @@ public static class MauiProgram {
// builder.Logging.AddDebug(); // builder.Logging.AddDebug();
//#endif //#endif
// ApiClient registrieren: SocketsHttpHandler als Primary Handler (vermeidet AndroidMessageHandler-Castfehler)
var apiOptions = new Infrastructure.ApiOptions { BaseUrl = GlobalVar.ApiUrl, Timeout = TimeSpan.FromSeconds(15) };
builder.Services.AddApiHttpClient(apiOptions);
// DI: AlertService für globale Alerts (z. B. leere ApiUrl) // DI: AlertService für globale Alerts (z. B. leere ApiUrl)
builder.Services.AddSingleton<IAlertService, AlertService>(); builder.Services.AddSingleton<IAlertService, AlertService>();
@@ -50,17 +55,23 @@ public static class MauiProgram {
// DI: ApiOptions IMMER aus aktuellen Settings erzeugen (nicht beim Start einfrieren) // DI: ApiOptions IMMER aus aktuellen Settings erzeugen (nicht beim Start einfrieren)
builder.Services.AddTransient(sp => new ApiOptions { builder.Services.AddTransient(sp => new ApiOptions {
BaseUrl = sp.GetRequiredService<IAppSettings>().ApiUrl, Timeout = TimeSpan.FromSeconds(15) BaseUrl = sp.GetRequiredService<IAppSettings>().ApiUrl,
Timeout = TimeSpan.FromSeconds(15)
}); });
// Token Provider soll ebenfalls aus Settings/Preferences lesen // Token Provider soll ebenfalls aus Settings/Preferences lesen
builder.Services.AddSingleton<ITokenProvider, SettingsTokenProvider>(); builder.Services.AddSingleton<ITokenProvider, SettingsTokenProvider>();
// HttpClient + ApiClient // HttpClient + ApiClient
// Configure HttpClient with RequestLoggingHandler and disable automatic redirects for diagnosis // Configure HttpClient with SocketsHttpHandler (managed) and RequestLoggingHandler
builder.Services.AddTransient<RequestLoggingHandler>(); builder.Services.AddTransient<RequestLoggingHandler>();
builder.Services.AddSingleton<HttpClient>(sp => { builder.Services.AddSingleton<HttpClient>(sp => {
var nativeHandler = new HttpClientHandler { AllowAutoRedirect = false }; var nativeHandler = new SocketsHttpHandler {
AllowAutoRedirect = false,
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
PooledConnectionLifetime = TimeSpan.FromMinutes(5),
ConnectTimeout = TimeSpan.FromSeconds(10)
};
var logging = sp.GetRequiredService<RequestLoggingHandler>(); var logging = sp.GetRequiredService<RequestLoggingHandler>();
logging.InnerHandler = nativeHandler; logging.InnerHandler = nativeHandler;
// HttpClient.Timeout will be adjusted by ApiClient if needed // HttpClient.Timeout will be adjusted by ApiClient if needed
@@ -95,16 +106,16 @@ public static class MauiProgram {
// DI: Validatoren // DI: Validatoren
builder.Services.AddSingleton<IHoursValidator, HoursValidator>(); builder.Services.AddSingleton<IHoursValidator, HoursValidator>();
// DI: Services & Repositories // DI: Services & Repositories
builder.Services.AddSingleton<IHoursRepository, HoursRepository>(); builder.Services.AddSingleton<IHoursRepository, HoursRepository>();
builder.Services.AddSingleton<IHoursService, HoursService>(); builder.Services.AddSingleton<IHoursService, HoursService>();
builder.Services.AddSingleton<IAuthService, AuthService>(); builder.Services.AddSingleton<IAuthService, AuthService>();
// DI: Views/ViewModels // DI: Views/ViewModels
builder.Services.AddTransient<ViewModels.StundenViewModel>(); builder.Services.AddTransient<ViewModels.StundenViewModel>();
builder.Services.AddTransient<Views.StundenPage>(); builder.Services.AddTransient<Views.StundenPage>();
builder.Services.AddTransient<ViewModels.LoginViewModel>(); builder.Services.AddTransient<ViewModels.LoginViewModel>();
builder.Services.AddTransient<Views.LoginPage>(); builder.Services.AddTransient<Views.LoginPage>();
return builder.Build(); return builder.Build();
} }