Previous MAUI-HttpClient-CRUD MAUI-Cancellation-Token Next

REST API consumer in MAUI with error handling

REST API consumer in MAUI with error handling so your app stays resilient when the network fails, the server responds incorrectly, or the user is offline.

πŸ›‘οΈ Error Handling with HttpClient

1. Wrap Calls in try/catch

Every API call should be protected:

public async Task<List<Post>> GetPostsAsync()
{
    try
    {
        return await _httpClient.GetFromJsonAsync<List<Post>>("posts");
    }
    catch (HttpRequestException ex)
    {
        // Network or server unreachable
        Console.WriteLine($"Network error: {ex.Message}");
        return new List<Post>();
    }
    catch (NotSupportedException ex)
    {
        // Content type not supported
        Console.WriteLine($"Unsupported content: {ex.Message}");
        return new List<Post>();
    }
    catch (JsonException ex)
    {
        // Invalid JSON
        Console.WriteLine($"Invalid JSON: {ex.Message}");
        return new List<Post>();
    }
}

2. Use EnsureSuccessStatusCode

This throws if the response isn’t 2xx:

var response = await _httpClient.PostAsJsonAsync("posts", newPost);
response.EnsureSuccessStatusCode();

Wrap in try/catch to handle gracefully.

3. Provide User-Friendly Feedback

Instead of just logging, surface messages in the UI:

public async Task<string> SafeCreatePostAsync(Post newPost)
{
    try
    {
        var response = await _httpClient.PostAsJsonAsync("posts", newPost);
        response.EnsureSuccessStatusCode();
        return "Post created successfully!";
    }
    catch (Exception ex)
    {
        return $"Failed to create post: {ex.Message}";
    }
}

4. ViewModel Example

Add a property for error messages:

private string _errorMessage;
public string ErrorMessage
{
    get => _errorMessage;
    set { _errorMessage = value; OnPropertyChanged(); }
}

public async Task LoadPosts()
{
    try
    {
        var posts = await _api.GetPostsAsync();
        Posts.Clear();
        foreach (var post in posts)
            Posts.Add(post);
        ErrorMessage = string.Empty;
    }
    catch (Exception ex)
    {
        ErrorMessage = $"Could not load posts: {ex.Message}";
    }
}

5. UI Binding

Show errors in your page:

<Label Text="{Binding ErrorMessage}" TextColor="Red" />

βœ… Benefits

  • Prevents app crashes.
  • Gives clear feedback to users.
  • Handles offline scenarios gracefully.
  • Keeps logs for debugging.

Retry Logic with Exponential Backoff in MAUI

adding retry logic with exponential backoff makes your MAUI app much more resilient when consuming REST APIs. Instead of failing immediately on a network hiccup, the app will retry a few times with increasing delays before showing an error.

πŸ”„ Retry Logic with Exponential Backoff

1. Helper Method

You can wrap your API calls in a retry loop:

private async Task<T> ExecuteWithRetry<T>(Func<Task<T>> operation, int maxRetries = 3)
{
    int delay = 1000; // start with 1 second
    for (int attempt = 1; attempt <= maxRetries; attempt++)
    {
        try
        {
            return await operation();
        }
        catch (HttpRequestException ex)
        {
            Console.WriteLine($"Attempt {attempt} failed: {ex.Message}");
            if (attempt == maxRetries)
                throw; // rethrow after last attempt
        }

        await Task.Delay(delay);
        delay *= 2; // exponential backoff
    }

    throw new Exception("Operation failed after retries.");
}

2. Use It in Your Service

Wrap your API calls:

public async Task<List<Post>> GetPostsAsync()
{
    return await ExecuteWithRetry(async () =>
    {
        return await _httpClient.GetFromJsonAsync<List<Post>>("posts");
    });
}

3. Apply to Other Methods

You can reuse ExecuteWithRetry for POST, PUT, and DELETE:

public async Task<Post> CreatePostAsync(Post newPost)
{
    return await ExecuteWithRetry(async () =>
    {
        var response = await _httpClient.PostAsJsonAsync("posts", newPost);
        response.EnsureSuccessStatusCode();
        return await response.Content.ReadFromJsonAsync<Post>();
    });
}

4. User-Friendly Feedback

In your ViewModel, catch the final exception and surface a message:

public async Task LoadPosts()
{
    try
    {
        var posts = await _api.GetPostsAsync();
        Posts.Clear();
        foreach (var post in posts)
            Posts.Add(post);
        ErrorMessage = string.Empty;
    }
    catch (Exception ex)
    {
        ErrorMessage = $"Could not load posts after retries: {ex.Message}";
    }
}

βœ… Benefits

  • Handles temporary network glitches.
  • Avoids overwhelming the server with rapid retries.
  • Provides clear feedback if all attempts fail.
  • Keeps your app responsive and user-friendly.
Back to Index
Previous MAUI-HttpClient-CRUD MAUI-Cancellation-Token Next
*