Как реализовать доступ к API и обработку ответов?

Реализация доступа к API и обработка ответов в Xamarin (и в Xamarin.Forms) осуществляется с помощью стандартных .NET-инструментов, таких как HttpClient, а также дополнительных библиотек, таких как Refit, RestSharp или Flurl. Наиболее распространённый и рекомендуемый способ — использование HttpClient в связке с асинхронными методами и сериализацией JSON через Newtonsoft.Json или System.Text.Json.

Базовая архитектура доступа к API

Обычно структура кода для работы с API включает:

  1. Модель данных (DTO)

  2. Клиент-сервис (API-сервис) — класс, отвечающий за HTTP-запросы

  3. ViewModel — вызывает сервис и обрабатывает полученные данные

  4. View (страница) — отображает данные пользователю

Создание модели данных (Data Transfer Object)

Допустим, у нас есть API, возвращающий список пользователей:

\[
{
"id": 1,
"name": "John Doe",
"email": "john@example.com"
}
\]

Создаём соответствующий класс:

public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}

Создание API-сервиса с использованием HttpClient

public class ApiService
{
private readonly HttpClient \_httpClient;
public ApiService()
{
\_httpClient = new HttpClient
{
BaseAddress = new Uri("https://api.example.com/")
};
\_httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
}
public async Task&lt;List<User&gt;> GetUsersAsync()
{
var response = await \_httpClient.GetAsync("users");
if (!response.IsSuccessStatusCode)
{
// Логика обработки ошибок
throw new HttpRequestException($"Ошибка {response.StatusCode}");
}
var json = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject&lt;List<User&gt;>(json);
}
public async Task&lt;User&gt; CreateUserAsync(User newUser)
{
var json = JsonConvert.SerializeObject(newUser);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await \_httpClient.PostAsync("users", content);
var resultJson = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
throw new Exception($"Ошибка создания пользователя: {resultJson}");
}
return JsonConvert.DeserializeObject&lt;User&gt;(resultJson);
}
}

Использование API-сервиса во ViewModel

public class UsersViewModel : INotifyPropertyChanged
{
public ObservableCollection&lt;User&gt; Users { get; set; } = new ObservableCollection&lt;User&gt;();
public ICommand LoadUsersCommand { get; }
private readonly ApiService \_apiService;
public UsersViewModel()
{
\_apiService = new ApiService();
LoadUsersCommand = new Command(async () => await LoadUsersAsync());
}
private async Task LoadUsersAsync()
{
try
{
var users = await \_apiService.GetUsersAsync();
Users.Clear();
foreach (var user in users)
{
Users.Add(user);
}
}
catch (Exception ex)
{
// Вывод сообщения об ошибке или логирование
Debug.WriteLine($"Ошибка при получении данных: {ex.Message}");
}
}
public event PropertyChangedEventHandler PropertyChanged;
}

Отображение данных во View (XAML)

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.Views.UsersPage">
&lt;ContentPage.BindingContext&gt;
&lt;local:UsersViewModel /&gt;
&lt;/ContentPage.BindingContext&gt;
&lt;StackLayout&gt;
&lt;Button Text="Загрузить пользователей" Command="{Binding LoadUsersCommand}" /&gt;
&lt;ListView ItemsSource="{Binding Users}"&gt;
&lt;ListView.ItemTemplate&gt;
&lt;DataTemplate&gt;
&lt;TextCell Text="{Binding Name}" Detail="{Binding Email}" /&gt;
&lt;/DataTemplate&gt;
&lt;/ListView.ItemTemplate&gt;
&lt;/ListView&gt;
&lt;/StackLayout&gt;
&lt;/ContentPage&gt;

Работа с заголовками, токенами и аутентификацией

Если API требует токена:

\_httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", accessToken);

Можно также динамически добавлять заголовки:

\_httpClient.DefaultRequestHeaders.Remove("Custom-Header");
\_httpClient.DefaultRequestHeaders.Add("Custom-Header", "value");

Обработка ошибок и статус-кодов

При работе с API важно обрабатывать:

  • Коды 4xx, 5xx

  • Тайм-ауты

  • Неверный формат JSON

  • Потерю подключения

Пример:

if (response.StatusCode == HttpStatusCode.Unauthorized)
{
// Выполнить выход из системы или запросить повторную аутентификацию
}

Использование Refit — альтернатива HttpClient

Refit — это библиотека, позволяющая описывать HTTP-запросы как интерфейсы.

Установка:

Install-Package Refit

Интерфейс API:

public interface IApi
{
\[Get("/users")\]
Task&lt;List<User&gt;> GetUsers();
\[Post("/users")\]
Task&lt;User&gt; CreateUser(\[Body\] User user);
}

Использование:

var api = RestService.For&lt;IApi&gt;("https://api.example.com");
var users = await api.GetUsers();

Поддержка отмены запросов (CancellationToken)

Для отмены запросов:

var cts = new CancellationTokenSource();
await \_httpClient.GetAsync("users", cts.Token);

Можно использовать, например, при уходе со страницы, чтобы не загружать ненужные данные.

Кэширование ответов

По умолчанию HttpClient не кэширует ответы. Можно реализовать кэш самостоятельно:

  • В память (MemoryCache, словарь)

  • В файл/SQLite

  • Через сторонние библиотеки (Akavache, MonkeyCache)

Логирование и отладка

Для отладки API-запросов:

  • Используйте Debug.WriteLine(response) или Console.WriteLine.

  • Добавьте перехватчик HTTP-запросов через HttpMessageHandler:

public class LoggingHandler : DelegatingHandler
{
public LoggingHandler(HttpMessageHandler innerHandler) : base(innerHandler) { }
protected override async Task&lt;HttpResponseMessage&gt; SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
Debug.WriteLine($"Request: {request}");
var response = await base.SendAsync(request, cancellationToken);
Debug.WriteLine($"Response: {response}");
return response;
}
}

Советы по безопасности и производительности

  • Используйте HTTPS для всех запросов.

  • Не храните токены и логины в открытом виде — используйте SecureStorage.

  • Для больших API-ответов избегайте полной десериализации — обрабатывайте частями.

  • Используйте ConfigureAwait(false) для асинхронных методов, если не нужен доступ к UI-потоку.

  • Не создавайте новый HttpClient при каждом запросе — используйте один экземпляр (или через HttpClientFactory).

Поддержка .NET MAUI и миграция

Большая часть кода доступа к API в Xamarin переносится в MAUI без изменений. Рекомендуется использовать HttpClientFactory и Dependency Injection в MAUI-подходе. В Xamarin эти технологии тоже можно применять вручную.

Таким образом, подключение к API в Xamarin реализуется через HttpClient, поддержку сериализации JSON и архитектурную изоляцию в виде сервисов. Грамотное построение API-слоя делает приложение масштабируемым, поддерживаемым и легко тестируемым.