To handle exceptions in a MAUI app and log device information to your server, you'll need to implement a comprehensive error handling strategy. Here's how to do it:
1. Global Exception Handling
First, set up a global exception handler in your MAUI app:
// In MauiProgram.cs public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); // ... other configurations // Add global exception handling AppDomain.CurrentDomain.UnhandledException += (sender, args) => { HandleException(args.ExceptionObject as Exception); }; return builder.Build(); }
2. Platform-Specific Device Information
Create a service to collect device information:
public interface IDeviceInfoService { string GetDeviceName(); string GetDeviceId(); string GetCountry(); Task<(double latitude, double longitude)> GetLocationAsync(); } // Platform implementations (Android, iOS, etc.) public partial class DeviceInfoService : IDeviceInfoService { public partial string GetDeviceName(); public partial string GetDeviceId(); public partial string GetCountry(); public partial Task<(double latitude, double longitude)> GetLocationAsync(); }
3. Exception Handling Service
Create a service to handle exceptions and send them to your server:
public class ExceptionHandlerService { private readonly IDeviceInfoService _deviceInfoService; private readonly HttpClient _httpClient; public ExceptionHandlerService(IDeviceInfoService deviceInfoService) { _deviceInfoService = deviceInfoService; _httpClient = new HttpClient(); } public async Task HandleExceptionAsync(Exception ex) { try { var deviceName = _deviceInfoService.GetDeviceName(); var deviceId = _deviceInfoService.GetDeviceId(); var country = _deviceInfoService.GetCountry(); var location = await _deviceInfoService.GetLocationAsync(); var currentDateTime = DateTime.UtcNow.ToString("o"); var errorData = new ErrorLog { DeviceName = deviceName, DeviceId = deviceId, DateTime = currentDateTime, Country = country, Latitude = location.latitude, Longitude = location.longitude, ExceptionType = ex.GetType().Name, Message = ex.Message, StackTrace = ex.StackTrace, InnerException = ex.InnerException?.ToString() }; await SendToServerAsync(errorData); } catch (Exception loggingEx) { // Fallback logging if sending to server fails Console.WriteLine($"Failed to log exception: {loggingEx}"); } } private async Task SendToServerAsync(ErrorLog errorData) { var json = JsonSerializer.Serialize(errorData); var content = new StringContent(json, Encoding.UTF8, "application/json"); // Replace with your server endpoint var response = await _httpClient.PostAsync("https://your-server.com/api/errorlogs", content); if (!response.IsSuccessStatusCode) { throw new HttpRequestException($"Failed to send error log: {response.StatusCode}"); } } } public class ErrorLog { public string DeviceName { get; set; } public string DeviceId { get; set; } public string DateTime { get; set; } public string Country { get; set; } public double Latitude { get; set; } public double Longitude { get; set; } public string ExceptionType { get; set; } public string Message { get; set; } public string StackTrace { get; set; } public string InnerException { get; set; } }
4. Platform-Specific Implementations
Android Implementation:
public partial class DeviceInfoService { public partial string GetDeviceName() { return $"{DeviceInfo.Manufacturer} {DeviceInfo.Model}"; } public partial string GetDeviceId() { return Android.Provider.Settings.Secure.GetString( Android.App.Application.Context.ContentResolver, Android.Provider.Settings.Secure.AndroidId); } public partial string GetCountry() { var locale = Java.Util.Locale.Default; return locale.Country; } public partial async Task<(double latitude, double longitude)> GetLocationAsync() { try { var request = new GeolocationRequest(GeolocationAccuracy.Medium); var location = await Geolocation.GetLocationAsync(request); return (location?.Latitude ?? 0, location?.Longitude ?? 0); } catch { return (0, 0); } } }
iOS Implementation:
public partial class DeviceInfoService { public partial string GetDeviceName() { return DeviceInfo.Name; } public partial string GetDeviceId() { return UIKit.UIDevice.CurrentDevice.IdentifierForVendor?.ToString(); } public partial string GetCountry() { return Foundation.NSLocale.CurrentLocale.CountryCode; } public partial async Task<(double latitude, double longitude)> GetLocationAsync() { try { var request = new GeolocationRequest(GeolocationAccuracy.Medium); var location = await Geolocation.GetLocationAsync(request); return (location?.Latitude ?? 0, location?.Longitude ?? 0); } catch { return (0, 0); } } }
5. Register Services in MAUI
// In MauiProgram.cs builder.Services.AddSingleton<IDeviceInfoService, DeviceInfoService>(); builder.Services.AddSingleton<ExceptionHandlerService>();
6. Using the Exception Handler
In your code, you can now handle exceptions:
try { // Your code that might throw exceptions } catch (Exception ex) { var exceptionHandler = MauiApplication.Current.Services.GetService<ExceptionHandlerService>(); await exceptionHandler.HandleExceptionAsync(ex); // Optionally show user-friendly message await Shell.Current.DisplayAlert("Error", "An unexpected error occurred", "OK"); }
7. Server-Side Implementation
On your server, you'll need an endpoint to receive these error logs. Here's a basic ASP.NET Core example:
[ApiController] [Route("api/errorlogs")] public class ErrorLogController : ControllerBase { [HttpPost] public IActionResult LogError([FromBody] ErrorLog errorLog) { // Store in database or logging system Console.WriteLine($"Received error: {JsonSerializer.Serialize(errorLog)}"); return Ok(); } }
Important Considerations:
Permissions: Ensure you have required permissions for location (in AndroidManifest.xml and Info.plist)
Privacy: Inform users you're collecting this data (may require privacy policy updates)
Performance: Consider batching errors if the app is offline
Security: Use HTTPS and consider authentication for your error logging endpoint
Offline Support: Implement local storage for errors when offline with sync later
This implementation provides a robust error handling system that captures all the requested device information and sends it to your server for analysis.
No comments:
Post a Comment