Friday, 1 August 2025

Exception Handling in .NET MAUI with Device Information Logging

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:

csharp
// 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:

csharp
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:

csharp
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:

csharp
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:

csharp
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

csharp
// 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:

csharp
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:

csharp
[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:

  1. Permissions: Ensure you have required permissions for location (in AndroidManifest.xml and Info.plist)

  2. Privacy: Inform users you're collecting this data (may require privacy policy updates)

  3. Performance: Consider batching errors if the app is offline

  4. Security: Use HTTPS and consider authentication for your error logging endpoint

  5. 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

Cricket Streaming MAUI App: Complete Solution

This document outlines a comprehensive solution for building a cricket streaming MAUI app with subscription plans, geo-restrictions, and pre...

Ads2