What you will learn

  • Make an asynchronous HTTPS GET request
  • Deserialize JSON into a typed model
  • Show loading, errors and a list of results
How to use this example: Start from a new .NET MAUI App project called MauiApi with .NET 10. Use the complete file listings below, and leave other template-generated files unchanged unless the lesson explicitly says otherwise. Run the Android target on Windows.

1. Create the project

Create MauiApi. Add a C# class named Post.cs and replace the two MainPage files. This demo retrieves a short list of example posts from the public JSONPlaceholder test API. It does not create user accounts or store personal information.

2. Use asynchronous networking

The sample creates one HttpClient for the lifetime of the page and calls GetFromJsonAsync<List<Post>>. The async/await approach keeps the interface responsive while the request is in progress. A try/catch block displays network errors as friendly status text.

3. Enable Internet access where needed

Android apps require network permission. Verify that the app’s Platforms/Android/AndroidManifest.xml includes an android.permission.INTERNET uses-permission element. The project template and debug configuration may already add it; do not duplicate the entry unnecessarily. Use HTTPS endpoints rather than bypassing transport security.

4. Run and test

  1. Confirm that your Android emulator has Internet access.
  2. Run the app and press Load posts.
  3. Confirm that five posts appear.
  4. Turn off the emulator’s connectivity and retry to see the error message.

Public test endpoints can change or become temporarily unavailable. The app should handle these failures gracefully.

Complete sample code

Use the exact file names and folder locations shown below. Copy each listing into your MAUI project. The separate source files can also be downloaded individually.

Post.cs
namespace MauiApi;

public class Post
{
    public int Id { get; set; }
    public string Title { get; set; } = "";
    public string Body { get; set; } = "";
}
MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiApi.MainPage"
             Title="REST API">
    <Grid Padding="20" RowDefinitions="Auto,Auto,Auto,*" RowSpacing="12">
        <Label Text="REST API Demo" FontSize="26"
               FontAttributes="Bold" />
        <Button Grid.Row="1" x:Name="LoadButton"
                Text="Load posts" Clicked="OnLoadClicked" />
        <Label Grid.Row="2" x:Name="StatusLabel"
               Text="Tap Load posts to begin." />
        <CollectionView Grid.Row="3" x:Name="PostsView"
                        EmptyView="No posts loaded.">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <VerticalStackLayout Padding="8" Spacing="4">
                        <Label Text="{Binding Title}" FontAttributes="Bold" />
                        <Label Text="{Binding Body}" FontSize="13" />
                    </VerticalStackLayout>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </Grid>
</ContentPage>
MainPage.xaml.cs
using System.Net.Http.Json;

namespace MauiApi;

public partial class MainPage : ContentPage
{
    private static readonly HttpClient Client = new()
    {
        Timeout = TimeSpan.FromSeconds(15)
    };

    public MainPage() => InitializeComponent();

    private async void OnLoadClicked(object sender, EventArgs e)
    {
        LoadButton.IsEnabled = false;
        StatusLabel.Text = "Loading...";
        try
        {
            const string url =
                "https://jsonplaceholder.typicode.com/posts?_limit=5";
            var posts = await Client.GetFromJsonAsync<List<Post>>(url);
            PostsView.ItemsSource = posts ?? [];
            StatusLabel.Text = $"Loaded {posts?.Count ?? 0} posts.";
        }
        catch (Exception ex) when (ex is HttpRequestException or TaskCanceledException)
        {
            PostsView.ItemsSource = null;
            StatusLabel.Text = "Request failed. Check Internet access and try again.";
        }
        finally
        {
            LoadButton.IsEnabled = true;
        }
    }
}
Platforms/Android/AndroidManifest.xml (permission excerpt)
<!-- Add inside the existing <manifest> element only if absent. -->
<uses-permission android:name="android.permission.INTERNET" />

Common problems and solutions

  • “NameResolutionFailure” or network error: Check emulator Wi-Fi and HTTPS reachability.
  • Posts do not appear: Inspect the debugger Output window and confirm JSONPlaceholder is reachable.
  • Manifest XML fails to parse: Add the permission inside the existing manifest element; do not paste the excerpt as a complete standalone file.

Practice exercise

Replace the URL with https://jsonplaceholder.typicode.com/users and build a typed User model to display names.

Expected result: The app loads HTTPS JSON data into a CollectionView and displays a helpful error if the request fails.

Official references