using System.Net; using System.Text.Json; namespace RobotNet10.CustomConfigurationEditor.Services.API; /// /// Helper class để parse error messages từ HTTP responses /// public static class HttpErrorHelper { /// /// Extract user-friendly error message từ HttpResponseMessage /// public static async Task GetErrorMessageAsync(HttpResponseMessage response) { try { // Try to read error message from response body var content = await response.Content.ReadAsStringAsync(); if (!string.IsNullOrWhiteSpace(content)) { // Try to parse as JSON error object try { using var doc = JsonDocument.Parse(content); var root = doc.RootElement; // Check for common error property names if (root.TryGetProperty("error", out var errorProp)) { var errorMsg = errorProp.GetString(); if (!string.IsNullOrWhiteSpace(errorMsg)) return errorMsg; } if (root.TryGetProperty("message", out var messageProp)) { var message = messageProp.GetString(); if (!string.IsNullOrWhiteSpace(message)) return message; } if (root.TryGetProperty("errors", out var errorsProp) && errorsProp.ValueKind == JsonValueKind.Array) { var errors = errorsProp.EnumerateArray() .Select(e => e.GetString()) .Where(s => !string.IsNullOrWhiteSpace(s)) .ToList(); if (errors.Count > 0) return string.Join("; ", errors); } // If it's a simple string, return it if (root.ValueKind == JsonValueKind.String) { return root.GetString() ?? GetDefaultMessage(response.StatusCode); } } catch (JsonException) { // If JSON parsing fails, check if content is a simple error message if (content.Length < 500) // Reasonable length for error message { return content; } } } } catch (Exception ex) when (ex is HttpRequestException or ObjectDisposedException) { // Fall through to default message } return GetDefaultMessage(response.StatusCode); } /// /// Extract user-friendly error message từ Exception /// public static string GetErrorMessage(Exception ex) { // Check for HttpRequestException if (ex is HttpRequestException httpEx) { // Try to extract meaningful message var message = httpEx.Message; // Remove technical details if (message.Contains("net_http_message_not_success_statuscode")) { return "Unable to connect to server. Please check your network connection."; } if (message.Contains("timeout")) { return "Request timeout. Please try again."; } if (message.Contains("connection")) { return "Unable to connect to server. Please check your network connection."; } return message; } // Check for TaskCanceledException (often timeout) if (ex is TaskCanceledException) { return "Request timeout. Please try again."; } // Return original message if it's user-friendly var exMessage = ex.Message; if (!string.IsNullOrWhiteSpace(exMessage) && !exMessage.Contains("net_http") && !exMessage.Contains("StatusCode") && !exMessage.Contains("Bad Request") && exMessage.Length < 200) { return exMessage; } // Default fallback return "An error occurred. Please try again or contact the administrator."; } /// /// Get default error message based on HTTP status code /// private static string GetDefaultMessage(HttpStatusCode statusCode) { return statusCode switch { HttpStatusCode.BadRequest => "Invalid data. Please check your input.", HttpStatusCode.Unauthorized => "You do not have permission to perform this action.", HttpStatusCode.Forbidden => "You do not have access to this resource.", HttpStatusCode.NotFound => "The requested data was not found.", HttpStatusCode.Conflict => "Data already exists or conflicts with existing data.", HttpStatusCode.InternalServerError => "Server error. Please try again later.", HttpStatusCode.ServiceUnavailable => "Service is temporarily unavailable. Please try again later.", HttpStatusCode.GatewayTimeout => "Request timeout. Please try again.", _ => $"Error: {statusCode}. Please try again." }; } }