diff --git a/LehrerApp.Desktop/App.axaml.cs b/LehrerApp.Desktop/App.axaml.cs index 9e73574..96679e2 100644 --- a/LehrerApp.Desktop/App.axaml.cs +++ b/LehrerApp.Desktop/App.axaml.cs @@ -112,7 +112,17 @@ public class App : Application } finally { - _serviceProvider.Dispose(); + // Der direkte WebUntis-Client meldet seine Sitzung asynchron ab. Ein synchrones + // ServiceProvider.Dispose() lehnt reine IAsyncDisposable-Dienste ab und ließ die App + // beim Schließen mit InvalidOperationException abstürzen. + try + { + _serviceProvider.DisposeAsync().AsTask().GetAwaiter().GetResult(); + } + catch (Exception ex) + { + AppBootstrapper.Logger.Error("Dienste konnten beim Beenden nicht vollständig freigegeben werden.", ex); + } _serviceProvider = null; } } diff --git a/LehrerApp.WebUntis.Tests/WebUntisClientTests.cs b/LehrerApp.WebUntis.Tests/WebUntisClientTests.cs index e6df3aa..937aff8 100644 --- a/LehrerApp.WebUntis.Tests/WebUntisClientTests.cs +++ b/LehrerApp.WebUntis.Tests/WebUntisClientTests.cs @@ -16,7 +16,7 @@ public sealed class WebUntisClientTests "2\t20\t8b\tMeier\tBerta\r\n"); var handler = new QueueHandler( Json("{\"jsonrpc\":\"2.0\",\"result\":{\"sessionId\":\"session-1\"}}"), - Json("{\"data\":{\"finished\":true,\"reportParams\":\"foo=bar\"}}"), + Json("{\"data\":{\"finished\":true,\"error\":false,\"reportParams\":\"foo=bar\"}}"), new HttpResponseMessage(HttpStatusCode.OK) { Content = new ByteArrayContent(latin1), diff --git a/LehrerApp.WebUntis/WebUntisClient.cs b/LehrerApp.WebUntis/WebUntisClient.cs index 80d1905..b54996d 100644 --- a/LehrerApp.WebUntis/WebUntisClient.cs +++ b/LehrerApp.WebUntis/WebUntisClient.cs @@ -417,7 +417,7 @@ public sealed class WebUntisClient : IAsyncDisposable } if (!TryProperty(payload, "data", out var data) || data.ValueKind != JsonValueKind.Object || - (TryProperty(data, "error", out var reportError) && reportError.ValueKind is not JsonValueKind.Null and not JsonValueKind.Undefined)) + (TryProperty(data, "error", out var reportError) && HasErrorValue(reportError))) throw new WebUntisException($"Report-Anfrage fehlgeschlagen: {ErrorMessage(payload, response)}"); if (!OptionalBoolean(data, "finished")) return null; return ReportData.From(data); @@ -646,6 +646,19 @@ public sealed class WebUntisClient : IAsyncDisposable (string.Equals(value.GetString(), "true", StringComparison.OrdinalIgnoreCase) || value.GetString() == "1"); } + private static bool HasErrorValue(JsonElement value) => value.ValueKind switch + { + JsonValueKind.Null or JsonValueKind.Undefined or JsonValueKind.False => false, + JsonValueKind.True => true, + JsonValueKind.String => !string.IsNullOrWhiteSpace(value.GetString()) && + !string.Equals(value.GetString(), "false", StringComparison.OrdinalIgnoreCase) && + value.GetString() != "0", + JsonValueKind.Number => !value.TryGetInt32(out var number) || number != 0, + JsonValueKind.Array => value.GetArrayLength() > 0, + JsonValueKind.Object => value.EnumerateObject().Any(), + _ => true, + }; + private static string ErrorMessage(JsonElement payload, HttpResponseMessage response) { if (payload.ValueKind == JsonValueKind.String) return payload.GetString() ?? "Unerwartete Antwort."; @@ -654,8 +667,25 @@ public sealed class WebUntisClient : IAsyncDisposable if (TryProperty(payload, "error", out var error) && OptionalString(error, "message") is { } errorMessage) return errorMessage; if (OptionalString(payload, "message") is { } message) return message; - if (TryProperty(payload, "data", out var data) && OptionalString(data, "message") is { } dataMessage) - return dataMessage; + if (TryProperty(payload, "data", out var data)) + { + if (OptionalString(data, "message") is { } dataMessage) return dataMessage; + if (data.ValueKind == JsonValueKind.Object) + { + var dataFields = data.EnumerateObject().Select(property => property.Name).Take(8).ToArray(); + if (dataFields.Length > 0) + return $"HTTP {(int)response.StatusCode}; unerwartete data-Felder: " + + $"{string.Join(", ", dataFields)}."; + } + else + { + return $"HTTP {(int)response.StatusCode}; data hat den Typ {data.ValueKind}."; + } + } + var fields = payload.EnumerateObject().Select(property => property.Name).Take(8).ToArray(); + return fields.Length == 0 + ? $"HTTP {(int)response.StatusCode}; leeres JSON-Objekt." + : $"HTTP {(int)response.StatusCode}; unerwartete JSON-Felder: {string.Join(", ", fields)}."; } return response.IsSuccessStatusCode ? "Unerwartete JSON-Antwort." : $"HTTP {(int)response.StatusCode}"; }