.Net Maui Calling Rest Apis With Httpclient And Refit Complete Guide
Understanding the Core Concepts of .NET MAUI Calling REST APIs with HttpClient and Refit
Exploring REST API Integration in .NET MAUI: HttpClient and Refit
Introduction
.NET Multi-platform App UI (MAUI) is a powerful framework for building full-fledged applications across multiple platforms—iOS, Android, and Windows—using C# and XAML. Central to many modern applications is the consumption of RESTful APIs, enabling seamless data exchange between the client and the server. This guide delves into two primary methods for API consumption in .NET MAUI: HttpClient and Refit.
Understanding RESTful APIs
REST (Representational State Transfer) is a stateless architecture for designing networked applications. It employs standard HTTP methods such as GET, POST, PUT, DELETE, and PATCH to manipulate resources identified by unique URIs. REST APIs are widely used due to their simplicity, efficiency, and platform independence.
Key Components:
- Resources: Identified by unique URIs (e.g.,
https://api.example.com/users
). - Representations: Data formats (e.g., JSON, XML).
- Methods: Actions performed on resources:
- GET: Retrieve data.
- POST: Create new data.
- PUT/PATCH: Update existing data.
- DELETE: Remove data.
Status Codes:
- 200 OK: Successful request.
- 201 Created: Resource created successfully.
- 400 Bad Request: Invalid request.
- 401 Unauthorized: Authentication required.
- 404 Not Found: Resource not found.
- 500 Internal Server Error: Server-side issue.
HttpClient: The Basics
HttpClient is a built-in .NET class for accessing RESTful services and sending HTTP requests. It's a versatile tool providing fine-grained control over request configuration and response handling.
Advantages:
- Cross-Platform Compatibility: Works seamlessly on iOS, Android, Windows, and macOS.
- Minimal Overhead: No external dependencies; part of the .NET framework.
- Performance: Efficient for low-level HTTP operations.
Basic Usage:
Initiate HttpClient:
HttpClient client = new HttpClient();
Configure HttpClient (Optional):
client.BaseAddress = new Uri("https://api.example.com"); client.DefaultRequestHeaders.Add("Accept", "application/json"); client.DefaultRequestHeaders.Add("User-Agent", "MAUIApp");
Send GET Request:
HttpResponseMessage response = await client.GetAsync("users"); if (response.IsSuccessStatusCode) { string data = await response.Content.ReadAsStringAsync(); // Process JSON data }
Send POST Request:
var user = new { Name = "John Doe", Email = "john.doe@example.com" }; string json = JsonConvert.SerializeObject(user); var content = new StringContent(json, Encoding.UTF8, "application/json"); HttpResponseMessage response = await client.PostAsync("users", content); if (response.IsSuccessStatusCode) { string jsonResponse = await response.Content.ReadAsStringAsync(); // Process response }
Dispose HttpClient:
client.Dispose();
Best Practices:
- Singleton Pattern: Reuse a single instance of
HttpClient
to improve performance. - Timeout Configuration: Set appropriate timeouts to avoid hanging requests.
- Error Handling: Gracefully handle exceptions and status codes.
- Security: Use HTTPS for secure communication.
Example of Singleton HttpClient:
public static class HttpClientFactory
{
private static readonly HttpClient _httpClient = new HttpClient();
static HttpClientFactory()
{
_httpClient.BaseAddress = new Uri("https://api.example.com");
_httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
}
public static HttpClient CreateClient()
{
return _httpClient;
}
}
// Usage
HttpClient client = HttpClientFactory.CreateClient();
HttpResponseMessage response = await client.GetAsync("users");
Introduction to Refit
While HttpClient
provides excellent control, it can be cumbersome for complex API interactions. Refit is a type-safe REST client for .NET, abstracting away the low-level details and reducing boilerplate code. It simplifies API consumption by allowing you to define interfaces and automatically generating the client implementation at runtime.
Advantages:
- Type Safety: Compiler checks API definitions.
- Clean Code: Interfaces with clear method signatures.
- Attributes: Simplify configuration of HTTP requests.
- Interceptor Support: Customize request and response processing.
Setting Up Refit:
Install Refit NuGet Package:
dotnet add package Refit
Define API Interface:
public interface IApiService { [Get("/users")] Task<List<User>> GetUsersAsync(); [Post("/users")] Task CreateUserAsync([Body] User user); [Put("/users/{id}")] Task UpdateUserAsync(int id, [Body] User user); [Delete("/users/{id}")] Task DeleteUserAsync(int id); }
Generate API Client:
HttpClient httpClient = new HttpClient(); IApiService apiService = RestService.For<IApiService>(httpClient, new RefitSettings { ContentSerializer = new SystemTextJsonContentSerializer(Options.Create(new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = true })) });
Use API Client:
// Fetch users List<User> users = await apiService.GetUsersAsync(); // Create user var newUser = new User { Name = "Jane Doe", Email = "jane.doe@example.com" }; await apiService.CreateUserAsync(newUser); // Update user var updatedUser = new User { Name = "Jane D.", Email = "jane.d@example.com" }; await apiService.UpdateUserAsync(1, updatedUser); // Delete user await apiService.DeleteUserAsync(1);
Response Handling:
Refit supports various response handling strategies, including automatic deserialization of JSON responses into C# objects.
Example: Handling Complex Responses:
public interface IApiService
{
[Get("/users/{id}")]
Task<UserResponse> GetUserAsync(int id);
}
public class UserResponse
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Status { get; set; }
}
// Usage
IApiService apiService = RestService.For<IApiService>(httpClient);
UserResponse user = await apiService.GetUserAsync(1);
Error Handling:
Refit throws ApiException
for HTTP errors, allowing you to handle specific status codes and messages.
Example: Error Handling:
try
{
await apiService.CreateUserAsync(newUser);
}
catch (ApiException ex)
{
if (ex.StatusCode == HttpStatusCode.Conflict)
{
// Handle conflict error
}
else
{
// Handle other errors
}
}
Customization:
Refit supports various customization options, including request headers, deserialization settings, and custom content types.
Example: Custom Request Headers:
public interface IApiService
{
[Get("/users")]
[Headers("Authorization: Bearer {token}")]
Task<List<User>> GetUsersAsync([Header("Authorization")] string token);
}
// Usage
string authToken = "your_auth_token_here";
List<User> users = await apiService.GetUsersAsync(authToken);
Conclusion
Integrating REST APIs into .NET MAUI applications is essential for building dynamic and responsive apps. Both HttpClient
and Refit offer robust solutions for API consumption, with HttpClient
providing fine-grained control and Refit simplifying complex interactions through type-safe interfaces. Understanding these tools and best practices will enable you to build efficient, scalable, and maintainable applications.
Online Code run
Step-by-Step Guide: How to Implement .NET MAUI Calling REST APIs with HttpClient and Refit
Example 1: Calling REST API with HttpClient
Step 1: Create a New .NET MAUI Project
- Open Visual Studio.
- Go to File > New > Project.
- Select .NET MAUI App (Preview).
- Provide a project name and location, then click Create.
Step 2: Add Model Classes
Let's assume you want to fetch data from an API that returns a list of users in JSON format. Create a model class to represent a user.
// Models/User.cs
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
Step 3: Create a Service to Handle HTTP Requests
Create a service class that uses HttpClient
to make requests to the REST API.
// Services/UserService.cs
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
public class UserService
{
private readonly HttpClient _httpClient;
public UserService()
{
_httpClient = new HttpClient();
}
public async Task<List<User>> GetUsersAsync()
{
var response = await _httpClient.GetAsync("https://jsonplaceholder.typicode.com/users");
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
var users = JsonConvert.DeserializeObject<List<User>>(content);
return users;
}
throw new Exception($"Error: {response.StatusCode}");
}
}
Step 4: Use the Service in Your ViewModel
Create a ViewModel to interact with the service and hold the data.
// ViewModels/UserViewModel.cs
using System.Collections.ObjectModel;
using System.Threading.Tasks;
public class UserViewModel
{
private readonly UserService _userService;
public ObservableCollection<User> Users { get; set; } = new ObservableCollection<User>();
public UserViewModel()
{
_userService = new UserService();
}
public async Task LoadUsersAsync()
{
var users = await _userService.GetUsersAsync();
foreach (var user in users)
{
Users.Add(user);
}
}
}
Step 5: Bind the ViewModel to the UI
In your MainPage.xaml
, set up a ListView to display the users.
<!-- 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="MauiAppWithHttpClient.MainPage">
<CollectionView x:Name="UsersListView">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Text="{Binding Id}" FontAttributes="Bold" />
<Label Grid.Column="1" Text="{Binding Name}" Margin="5,0,0,0" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ContentPage>
In your MainPage.xaml.cs
, set the binding context and call LoadUsersAsync()
.
// MainPage.xaml.cs
using System.Threading.Tasks;
using Microsoft.Maui.Controls;
public partial class MainPage : ContentPage
{
private UserViewModel _viewModel;
public MainPage()
{
InitializeComponent();
_viewModel = new UserViewModel();
BindingContext = _viewModel;
}
protected override async void OnAppearing()
{
base.OnAppearing();
await _viewModel.LoadUsersAsync();
UsersListView.ItemsSource = _viewModel.Users;
}
}
Step 6: Install Newtonsoft.Json Package
If not already installed, install the Newtonsoft.Json package via NuGet:
- Right-click on the project in Solution Explorer.
- Select Manage NuGet Packages.
- Search for Newtonsoft.Json and install it.
Step 7: Run the Application
Run your application on any available platform, such as Android, iOS, or Windows.
Example 2: Calling REST API with Refit
Step 1: Create a New .NET MAUI Project
Follow the same steps as above to create a new project.
Step 2: Add Model Classes
Use the same model class as before.
// Models/User.cs
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
Step 3: Define an API Interface
Using Refit, define an API interface for the HTTP requests.
// Services/IUserApi.cs
using System.Collections.Generic;
using System.Threading.Tasks;
using Refit;
public interface IUserApi
{
[Get("/users")]
Task<List<User>> GetUsersAsync();
}
Step 4: Create a Service to Handle API Requests
Use Refit to generate the API service from the interface.
// Services/UserService.cs
using Refit;
using System.Threading.Tasks;
public class UserService
{
private readonly IUserApi _userApi;
public UserService()
{
_userApi = RestService.For<IUserApi>("https://jsonplaceholder.typicode.com");
}
public async Task<List<User>> GetUsersAsync()
{
return await _userApi.GetUsersAsync();
}
}
Step 5: Use the Service in Your ViewModel
Again, create a ViewModel to interact with the service and hold the data.
// ViewModels/UserViewModel.cs
using System.Collections.ObjectModel;
using System.Threading.Tasks;
public class UserViewModel
{
private readonly UserService _userService;
public ObservableCollection<User> Users { get; set; } = new ObservableCollection<User>();
public UserViewModel()
{
_userService = new UserService();
}
public async Task LoadUsersAsync()
{
var users = await _userService.GetUsersAsync();
foreach (var user in users)
{
Users.Add(user);
}
}
}
Step 6: Bind the ViewModel to the UI
The binding context and UI setup are the same as in Example 1.
<!-- 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="MauiAppWithRefit.MainPage">
<CollectionView x:Name="UsersListView">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Text="{Binding Id}" FontAttributes="Bold" />
<Label Grid.Column="1" Text="{Binding Name}" Margin="5,0,0,0" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ContentPage>
// MainPage.xaml.cs
using System.Threading.Tasks;
using Microsoft.Maui.Controls;
public partial class MainPage : ContentPage
{
private UserViewModel _viewModel;
public MainPage()
{
InitializeComponent();
_viewModel = new UserViewModel();
BindingContext = _viewModel;
}
protected override async void OnAppearing()
{
base.OnAppearing();
await _viewModel.LoadUsersAsync();
UsersListView.ItemsSource = _viewModel.Users;
}
}
Step 7: Install Refit Package
Install the Refit package via NuGet:
- Right-click on the project in Solution Explorer.
- Select Manage NuGet Packages.
- Search for Refit and install it.
Step 8: Run the Application
Run your application on any available platform, such as Android, iOS, or Windows.
Login to post a comment.