using System.Net; using System.Net.Http.Json; using System.Text.Json; namespace RobotNet10.NavigationTuneUI.Helpers; /// /// Helper class for extracting meaningful error messages from HTTP responses /// public static class ErrorHelper { /// /// Extract error message from HTTP response /// public static async Task GetErrorMessageAsync(HttpResponseMessage response) { try { // Try to read as JSON error object var errorObject = await response.Content.ReadFromJsonAsync(); // Check for common error formats if (errorObject.ValueKind == JsonValueKind.Object) { // Format: { error: "message" } if (errorObject.TryGetProperty("error", out var errorProp) && errorProp.ValueKind == JsonValueKind.String) { var errorMessage = errorProp.GetString(); // If there's a details field, append it if (errorObject.TryGetProperty("details", out var detailsProp) && detailsProp.ValueKind == JsonValueKind.String) { var details = detailsProp.GetString(); if (!string.IsNullOrWhiteSpace(details)) { return $"{errorMessage}: {details}"; } } // If there's an errors array (validation errors), append them if (errorObject.TryGetProperty("errors", out var errorsProp) && errorsProp.ValueKind == JsonValueKind.Array) { var errors = errorsProp.EnumerateArray() .Where(e => e.ValueKind == JsonValueKind.String) .Select(e => e.GetString()) .Where(s => !string.IsNullOrWhiteSpace(s)) .ToList(); if (errors.Count > 0) { return $"{errorMessage}\n{string.Join("\n", errors)}"; } } return errorMessage ?? GetDefaultErrorMessage(response.StatusCode); } // Format: { message: "message" } if (errorObject.TryGetProperty("message", out var messageProp) && messageProp.ValueKind == JsonValueKind.String) { return messageProp.GetString() ?? GetDefaultErrorMessage(response.StatusCode); } } // Try to read as plain text var textContent = await response.Content.ReadAsStringAsync(); if (!string.IsNullOrWhiteSpace(textContent)) { return textContent; } } catch { // If parsing fails, fall back to status code message } return GetDefaultErrorMessage(response.StatusCode); } /// /// Get default error message based on HTTP status code /// private static string GetDefaultErrorMessage(HttpStatusCode statusCode) { return statusCode switch { HttpStatusCode.BadRequest => "Yêu cầu không hợp lệ. Vui lòng kiểm tra lại dữ liệu đầu vào.", HttpStatusCode.Unauthorized => "Bạn chưa được xác thực. Vui lòng đăng nhập lại.", HttpStatusCode.Forbidden => "Bạn không có quyền thực hiện thao tác này.", HttpStatusCode.NotFound => "Không tìm thấy tài nguyên yêu cầu.", HttpStatusCode.Conflict => "Xung đột dữ liệu. Có thể tài nguyên đã tồn tại.", HttpStatusCode.InternalServerError => "Lỗi máy chủ. Vui lòng thử lại sau.", HttpStatusCode.ServiceUnavailable => "Dịch vụ tạm thời không khả dụng. Vui lòng thử lại sau.", HttpStatusCode.RequestTimeout => "Yêu cầu quá thời gian chờ. Vui lòng thử lại.", _ => $"Lỗi không xác định ({(int)statusCode} {statusCode})" }; } /// /// Extract error message from exception /// public static string GetErrorMessage(Exception ex) { // For HttpRequestException, try to extract more meaningful message if (ex is HttpRequestException httpEx) { // Check if it's a connection error if (httpEx.Message.Contains("connection") || httpEx.Message.Contains("refused")) { return "Không thể kết nối đến máy chủ. Vui lòng kiểm tra kết nối mạng."; } // Check if it's a timeout if (httpEx.Message.Contains("timeout")) { return "Yêu cầu quá thời gian chờ. Vui lòng thử lại."; } return httpEx.Message; } // For TaskCanceledException (often timeout) if (ex is TaskCanceledException) { return "Yêu cầu quá thời gian chờ. Vui lòng thử lại."; } // For JsonException if (ex is JsonException) { return "Lỗi xử lý dữ liệu từ máy chủ. Vui lòng thử lại."; } // For InvalidOperationException if (ex is InvalidOperationException) { return ex.Message; } // Default: return exception message return ex.Message; } }