Вступ: навіщо мобільним додаткам .NET Aspire
Якщо ви коли-небудь розробляли .NET MAUI додаток, що має працювати з локальним API, то напевно знаєте цей біль. На Windows все чудово — localhost і поїхали. Але варто запустити емулятор Android — і раптом потрібна адреса 10.0.2.2. На iOS симуляторі — своя історія. А на фізичному пристрої — ще й сертифікати налаштовуй.
Чесно кажучи, це кожного разу з'їдає мінімум годину. І щоразу доводиться гуглити заново.
.NET Aspire вирішує цю проблему раз і назавжди.
З випуском .NET MAUI 10 Microsoft офіційно представила інтеграцію з .NET Aspire — хмарно-орієнтованим стеком для побудови спостережуваних розподілених додатків. Тепер ваш мобільний додаток автоматично знаходить локальні сервіси без жорстко закодованих URL-адрес, а Dev Tunnels забезпечують прозоре підключення з емуляторів і фізичних пристроїв.
Отже, давайте розберемо покроково, як це все налаштувати — від створення проєкту до моніторингу телеметрії на дашборді Aspire.
Що таке .NET Aspire і чому він важливий для мобільної розробки
.NET Aspire — це набір інструментів, шаблонів та NuGet-пакетів для побудови розподілених хмарних додатків. По суті, він дає вам чотири ключові речі:
- Оркестрація — управління декількома сервісами та їхніми залежностями через єдиний App Host проєкт
- Service Discovery — автоматичне виявлення сервісів без необхідності вказувати конкретні URL-адреси
- Телеметрія — вбудована підтримка OpenTelemetry для збору метрик, логів і розподілених трейсів
- Стійкість — патерни повторних спроб, circuit breaker та інші механізми для надійної роботи з мережею
До появи інтеграції з MAUI ці можливості були доступні лише для веб-додатків та мікросервісів. Тепер мобільні розробники нарешті отримують ті самі інструменти (і це, повірте, відчувається).
Ключові переваги для мобільної розробки
Інтеграція Aspire з .NET MAUI вирішує три найбільші болі мобільних розробників:
- Автоматична конфігурація мережі — більше не потрібно вручну обробляти
10.0.2.2для Android або налаштовувати валідацію сертифікатів - Service Discovery — ваш MAUI додаток знаходить та підключається до сервісів за іменем, а не за URL
- Dev Tunnels — вбудована підтримка тунелів для підключення емуляторів iOS та Android до сервісів на вашій машині
Звучить добре в теорії? На практиці — ще краще. Давайте налаштуємо.
Передумови та підготовка середовища
Перш ніж розпочати, переконайтеся що у вас є:
- .NET 10 SDK або новіша версія
- Visual Studio 2022 (v17.12+) або Visual Studio 2026 із робочим навантаженням .NET MAUI
- .NET Aspire workload — встановлюється через CLI
- Docker Desktop — для контейнерних залежностей (бази даних, Redis тощо)
Встановіть необхідні компоненти:
# Встановити .NET Aspire workload
dotnet workload install aspire
# Перевірити встановлення
dotnet workload list
# Переконатися, що шаблони доступні
dotnet new list | grep maui-aspire
Архітектура рішення: три ключові проєкти
Типове рішення .NET MAUI + Aspire складається з трьох проєктів. Нічого зайвого — кожен має свою чітку роль.
1. App Host — оркестратор
App Host — це серце вашої Aspire-інфраструктури. Він реєструє всі сервіси, налаштовує залежності та запускає дашборд моніторингу. Саме тут визначається, як сервіси знаходять один одного.
2. MAUI Service Defaults — конфігурація за замовчуванням
Містить спільну конфігурацію для Service Discovery, телеметрії та патернів стійкості. Створюється зі спеціального шаблону maui-aspire-servicedefaults, оптимізованого саме для мобільних додатків.
3. MAUI App — ваш мобільний додаток
Власне ваш .NET MAUI додаток, який підключається до Service Defaults і використовує Service Discovery для зв'язку з API.
Якщо схематично: App Host оркеструє всі сервіси та створює Dev Tunnels → MAUI Service Defaults надає конфігурацію → MAUI App використовує цю конфігурацію для підключення до сервісів за іменами. Просто і зрозуміло.
Покрокове налаштування інтеграції
Крок 1: Створення MAUI Service Defaults
Service Defaults — це спеціальний проєкт із розширеннями для підключення телеметрії та Service Discovery. Створюємо через CLI:
# Створити проєкт Service Defaults
dotnet new maui-aspire-servicedefaults -n MyApp.MauiServiceDefaults
# Додати посилання з MAUI проєкту на Service Defaults
dotnet add MyApp.csproj reference MyApp.MauiServiceDefaults/MyApp.MauiServiceDefaults.csproj
Після створення в проєкті з'явиться файл Extensions.cs з набором розширювальних методів. Ось як він виглядає:
// Extensions.cs у проєкті MAUI Service Defaults
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using OpenTelemetry;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
namespace MyApp.MauiServiceDefaults;
public static class Extensions
{
public static MauiAppBuilder AddServiceDefaults(this MauiAppBuilder builder)
{
builder.ConfigureOpenTelemetry();
builder.AddServiceDiscovery();
builder.Services.ConfigureHttpClientDefaults(http =>
{
// Увімкнути Service Discovery для всіх HttpClient
http.AddServiceDiscovery();
// Увімкнути стандартні обробники стійкості
http.AddStandardResilienceHandler();
});
return builder;
}
private static MauiAppBuilder ConfigureOpenTelemetry(
this MauiAppBuilder builder)
{
builder.Services.AddOpenTelemetry()
.WithMetrics(metrics =>
{
metrics.AddRuntimeInstrumentation()
.AddHttpClientInstrumentation();
// Розкоментуйте для метрик MAUI SDK:
// .AddMeter("Microsoft.Maui");
})
.WithTracing(tracing =>
{
tracing.AddHttpClientInstrumentation();
// Розкоментуйте для трейсів MAUI SDK:
// .AddSource("Microsoft.Maui");
});
builder.Services.AddOpenTelemetryExporters(builder.Configuration);
return builder;
}
}
Важливо: Service Defaults — виключно для спільної конфігурації. Не додавайте сюди моделі, сервіси або бізнес-логіку — для цього використовуйте окремий Class Library.
Крок 2: Налаштування App Host
App Host — це точка входу для оркестрації. Тут реєструєте API сервіси та підключаєте MAUI додаток. Ось тут, власне, починається найцікавіше:
// Program.cs в AppHost проєкті
var builder = DistributedApplication.CreateBuilder(args);
// Додати API сервіс
var weatherApi = builder.AddProject<Projects.WeatherApi>("webapi");
// Додати MAUI додаток (через метод AddMauiProject, НЕ через .csproj)
var mauiApp = builder.AddMauiProject("mauiapp");
// Для Windows та Mac Catalyst — пряме підключення через localhost
mauiApp.AddWindows()
.WithReference(weatherApi);
mauiApp.AddMacCatalyst()
.WithReference(weatherApi);
// Для iOS та Android — потрібен Dev Tunnel
var publicDevTunnel = builder.AddDevTunnel("devtunnel-public")
.WithAnonymousAccess()
.WithReference(weatherApi.GetEndpoint("https"));
mauiApp.AddiOSSimulator()
.WithOtlpDevTunnel()
.WithReference(weatherApi, publicDevTunnel);
mauiApp.AddAndroidEmulator()
.WithOtlpDevTunnel()
.WithReference(weatherApi, publicDevTunnel);
builder.Build().Run();
Тут є кілька нюансів, на які варто звернути увагу:
AddMauiProjectвикористовується замість стандартногоAddProject, оскільки MAUI додатки мають особливий процес збірки- Windows і Mac Catalyst працюють напряму через localhost — Dev Tunnel їм не потрібен
- Для iOS та Android створюється публічний Dev Tunnel з анонімним доступом
WithOtlpDevTunnel()створює окремий тунель для передачі телеметрії
Крок 3: Конфігурація MauiProgram.cs
Тепер у вашому MAUI додатку підключіть Service Defaults і налаштуйте HTTP клієнт:
// MauiProgram.cs
using MyApp.MauiServiceDefaults;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
// Підключити Service Defaults (Service Discovery + телеметрія)
builder.AddServiceDefaults();
// Налаштувати типізований HTTP клієнт із Service Discovery
builder.Services.AddHttpClient<WeatherApiClient>(client =>
{
// Ім'я сервісу збігається з іменем у App Host
// https+http:// — спочатку HTTPS, якщо недоступний — HTTP
client.BaseAddress = new Uri("https+http://webapi");
});
return builder.Build();
}
}
Зверніть увагу на URI https+http://webapi. Це не звичайна URL-адреса — це спеціальний синтаксис Service Discovery. webapi — ім'я ресурсу з App Host. Aspire автоматично перетворить його на реальну адресу, враховуючи платформу.
Тобто на Android він піде через тунель, на Windows — через localhost. І вам взагалі не потрібно про це думати. Ось це, мабуть, і є головна принадність всієї інтеграції.
Крок 4: Створення типізованого API клієнта
Типізовані клієнти — рекомендована практика в .NET. І в контексті Aspire вони працюють особливо гарно, бо Service Discovery підхоплює все автоматично:
// WeatherApiClient.cs
using System.Net.Http.Json;
public class WeatherApiClient
{
private readonly HttpClient _httpClient;
public WeatherApiClient(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<WeatherForecast[]?> GetForecastAsync(
CancellationToken cancellationToken = default)
{
return await _httpClient.GetFromJsonAsync<WeatherForecast[]>(
"/weatherforecast",
cancellationToken);
}
}
public record WeatherForecast(
DateOnly Date,
int TemperatureC,
string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
Крок 5: Використання клієнта у ViewModel
Інтегруємо типізований клієнт через DI — тут все стандартно для MVVM, нічого нового:
// MainPageViewModel.cs
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Collections.ObjectModel;
public partial class MainPageViewModel : ObservableObject
{
private readonly WeatherApiClient _weatherClient;
public MainPageViewModel(WeatherApiClient weatherClient)
{
_weatherClient = weatherClient;
}
[ObservableProperty]
private bool _isLoading;
public ObservableCollection<WeatherForecast> Forecasts { get; } = new();
[RelayCommand]
private async Task LoadWeatherAsync()
{
try
{
IsLoading = true;
var data = await _weatherClient.GetForecastAsync();
Forecasts.Clear();
if (data is not null)
{
foreach (var forecast in data)
Forecasts.Add(forecast);
}
}
catch (HttpRequestException ex)
{
// Обробка помилок мережі
await Shell.Current.DisplayAlertAsync(
"Помилка", $"Не вдалося завантажити дані: {ex.Message}", "OK");
}
finally
{
IsLoading = false;
}
}
}
Як працює Service Discovery на різних платформах
Мабуть, найкрутіша частина інтеграції — це повністю прозора робота Service Discovery на всіх платформах. Давайте подивимось, що відбувається "під капотом".
Windows та Mac Catalyst
Тут все максимально просто. Додаток і сервіси працюють на одній машині, тому Service Discovery просто перетворює ім'я сервісу на адресу localhost з відповідним портом. Ніяких тунелів, ніякої додаткової конфігурації.
Android емулятор
А от тут раніше починався головний біль. Емулятор Android працює у віртуальній машині з власним мережевим стеком. Історично для підключення до хост-машини використовувалася адреса 10.0.2.2 — і це потрібно було пам'ятати (або щоразу гуглити, як більшість з нас і робила).
З Aspire інтеграцією ви про це більше не думаєте — Dev Tunnel автоматично створює безпечний тунель від емулятора до ваших локальних сервісів.
iOS симулятор
iOS симулятор теж підключається через Dev Tunnel. Це, між іншим, вирішує ще й проблему з SSL-сертифікатами, яка раніше вимагала окремого танцю з бубном.
Фізичні пристрої
Для фізичних пристроїв Dev Tunnels стають ще ціннішими. Вони створюють публічний HTTPS ендпоінт, доступний з будь-якої мережі. Це означає, що для тестування на реальному пристрої більше не обов'язково бути в одній Wi-Fi мережі з машиною розробника.
Серйозна перевага, особливо якщо ви працюєте з QA-командою, яка сидить в іншому офісі (чи взагалі на ремоуті).
Генерація AspireAppSettings.g.cs
Цікавий технічний момент: на відміну від серверних додатків, де Aspire передає конфігурацію через змінні середовища, для MAUI все працює інакше. Налаштування генеруються як вихідний код у файлі AspireAppSettings.g.cs і включаються в додаток під час компіляції.
При першому запуску App Host цей файл автоматично створюється у директорії вашого MAUI проєкту. Він містить адреси сервісів, параметри Dev Tunnels, ендпоінти OTLP — все, що потрібно для роботи.
// AspireAppSettings.g.cs (генерується автоматично)
// Не редагуйте цей файл вручну!
namespace MyApp;
internal static class AspireAppSettings
{
// Конфігурація генерується App Host при запуску
// та включає адреси сервісів, тунелів і т.д.
}
Важливо: обов'язково додайте цей файл до .gitignore. Він містить адреси Dev Tunnels, специфічні для конкретної машини — коміт цього файлу в репозиторій лише створить плутанину для колег.
Моніторинг через Aspire Dashboard
Чесно кажучи, дашборд Aspire — це одна з тих речей, які побачивши раз, ви не зрозумієте, як жили без неї. Повна картина роботи вашого розподіленого додатка в реальному часі — і все це з коробки, без жодного рядка додаткової конфігурації.
Запуск та доступ до дашборда
Дашборд стартує автоматично при запуску App Host:
# Запустити оркестратор
dotnet run --project MyApp.AppHost
# Або через Aspire CLI
aspire run
Після запуску відкриється Aspire Dashboard у браузері. Там ви побачите всі зареєстровані сервіси і зможете моніторити їхній стан.
Що доступно на дашборді
- Структуровані логи — всі логи від усіх сервісів та MAUI додатка в одному місці з фільтрацією та пошуком
- Розподілені трейси — повний ланцюжок виклику від натискання кнопки в MAUI до відповіді API, з хронометражем кожного етапу
- Метрики — HTTP запити, час відповіді, помилки, використання ресурсів
- Стан здоров'я — health check ендпоінти для кожного сервісу
Увімкнення метрик MAUI SDK
За замовчуванням дашборд збирає лише стандартні метрики HTTP-клієнта та runtime. Якщо хочете побачити детальну інформацію про макети, рендеринг та інші внутрішні операції .NET MAUI — розкоментуйте відповідні рядки у Extensions.cs:
.WithMetrics(metrics =>
{
metrics.AddRuntimeInstrumentation()
.AddHttpClientInstrumentation()
// Увімкнути метрики MAUI SDK
.AddMeter("Microsoft.Maui");
})
.WithTracing(tracing =>
{
tracing.AddHttpClientInstrumentation()
// Увімкнути трейси MAUI SDK
.AddSource("Microsoft.Maui");
})
Тільки майте на увазі — це може генерувати значний обсяг телеметрії. Для розробки та профілювання — чудово, але в production будьте обережні з цим.
Обробка помилок та патерни стійкості
Мобільні додатки живуть у реальному світі нестабільного інтернету. Метро, підвал, природа — Wi-Fi зникає в найневідповідніший момент. Тому правильна обробка помилок — це не "nice to have", а необхідність. Aspire автоматично налаштовує стандартні обробники стійкості через Microsoft.Extensions.Http.Resilience.
Стандартний обробник стійкості
Коли ви викликаєте AddStandardResilienceHandler() у Service Defaults, автоматично додаються:
- Повторні спроби (Retry) — автоматичне повторення невдалих HTTP запитів з експоненційною затримкою
- Circuit Breaker — захист від лавини запитів до сервісу, що не відповідає
- Таймаути — обмеження часу очікування відповіді
- Rate Limiting — обмеження частоти запитів
Все це працює прозоро. Вам не потрібно писати додатковий код у ваших API-клієнтах — стійкість вже вшита.
Кастомізація стратегій
Якщо стандартна конфігурація не підходить (а для мобільних додатків часто варто налаштувати більші таймаути), ви можете кастомізувати параметри:
builder.Services.AddHttpClient<WeatherApiClient>(client =>
{
client.BaseAddress = new Uri("https+http://webapi");
})
.AddStandardResilienceHandler(options =>
{
// Збільшити кількість повторних спроб для нестабільних мереж
options.Retry.MaxRetryAttempts = 5;
// Збільшити таймаут для повільних мобільних мереж
options.AttemptTimeout.Timeout = TimeSpan.FromSeconds(10);
options.TotalRequestTimeout.Timeout = TimeSpan.FromSeconds(60);
});
Практичні поради та типові помилки
Чекліст запуску
Якщо ваш MAUI додаток не може підключитися до сервісів — не панікуйте. Перевірте ці пункти (з досвіду — зазвичай проблема в одному з перших трьох):
- Переконайтеся, що
AddServiceDefaults()викликається вMauiProgram.cs - Ім'я сервісу у
BaseAddressмає точно збігатися з іменем у App Host - Перевірте схему
https+http://— пропущений+httpодна з найпоширеніших помилок - Перевірте посилання на Service Defaults проєкт у
.csproj - Переконайтеся, що App Host запущено перед запуском MAUI додатка
- Для iOS/Android — перевірте, що Dev Tunnel створено та доступний
Порядок запуску
Важливий момент, який легко пропустити: MAUI додаток не запускається автоматично при старті App Host. Правильний порядок такий:
- Запустіть App Host (
dotnet run --project AppHost) - Дочекайтеся появи Aspire Dashboard
- Запустіть MAUI додаток як окремий проєкт
Так, це трохи незвично, якщо ви звикли що F5 запускає все. Але це зроблено свідомо — MAUI проєкт має свій специфічний процес деплойменту на пристрій чи емулятор.
Файл .gitignore
Обов'язково додайте згенеровані файли до .gitignore:
# Aspire generated settings
**/AspireAppSettings.g.cs
Продуктивна збірка
Service Discovery та Dev Tunnels — це виключно інструменти розробки. Для production вам потрібно конфігурувати реальні URL-адреси API через стандартні механізми .NET MAUI (appsettings.json, змінні середовища або серверну конфігурацію). Не забудьте про це перед релізом — я бачив, як кілька команд пропускали цей крок і дивувались, чому додаток не працює після публікації.
Інтеграція з існуючим проєктом
Якщо у вас вже є .NET MAUI 10 проєкт, додати Aspire нескладно — буквально кілька команд:
# 1. Створити Service Defaults
dotnet new maui-aspire-servicedefaults -n YourApp.MauiServiceDefaults
# 2. Додати посилання
dotnet add YourApp.csproj reference YourApp.MauiServiceDefaults/YourApp.MauiServiceDefaults.csproj
# 3. Створити App Host проєкт
dotnet new aspire-apphost -n YourApp.AppHost
# 4. Додати NuGet пакет для MAUI підтримки
dotnet add YourApp.AppHost.csproj package Aspire.Hosting.Maui --prerelease
Далі модифікуйте MauiProgram.cs, додавши виклик builder.AddServiceDefaults(), та замініть жорстко закодовані URL-адреси на синтаксис Service Discovery. Весь процес — хвилин 15-20, якщо не відволікатись.
Поточний статус та обмеження
Станом на березень 2026 року, інтеграція .NET MAUI з Aspire знаходиться у стадії Preview. Що це означає на практиці:
- API може змінюватися між версіями — будьте готові до breaking changes
- Повна інтеграція з Visual Studio 2026 ще в процесі
- Деякі сценарії (наприклад, кілька MAUI проєктів в одному App Host) можуть працювати нестабільно
- Пакет
Aspire.Hosting.Mauiмає позначку--prerelease
Але, чесно кажучи, для повсякденної розробки і локального тестування інтеграція вже цілком робоча. Навіть у Preview стані вона суттєво спрощує життя мобільним розробникам — і, на мою думку, вже варта того, щоб спробувати у наступному проєкті.
FAQ — часті запитання
Чи можна використовувати .NET Aspire у production для мобільних додатків?
Aspire інтеграція з MAUI переважно призначена для середовища розробки — Service Discovery, Dev Tunnels та дашборд допомагають під час локальної роботи. Для production слід конфігурувати реальні URL-адреси API. Однак компоненти телеметрії (OpenTelemetry) цілком підходять і для production — якщо ви експортуєте метрики до Azure Application Insights або іншого OTLP-сумісного бекенду.
Чи обов'язково мати Docker для роботи з Aspire?
Ні, Docker потрібен лише якщо ваші сервіси використовують контейнерні залежності — PostgreSQL, Redis, RabbitMQ тощо. Якщо ваш App Host оркеструє тільки .NET проєкти, Docker не обов'язковий.
Чи працює Aspire інтеграція з .NET MAUI Blazor Hybrid?
Так, і це чудова новина. Blazor Hybrid додатки підтримуються повністю. Процес налаштування ідентичний звичайному MAUI додатку — BlazorWebView компоненти можуть використовувати ті самі типізовані HTTP клієнти через DI, нічого додатково конфігурувати не потрібно.
Як працює Dev Tunnel і чи є обмеження безпеки?
Dev Tunnel створює безпечний HTTPS тунель через інфраструктуру Microsoft. Тунелі з анонімним доступом (WithAnonymousAccess()) доступні без автентифікації — для розробки це зручно, але не використовуйте їх з реальними чутливими даними. Для більш безпечних сценаріїв можна налаштувати автентифікацію через Microsoft Entra ID.
Яка мінімальна версія .NET MAUI підтримує Aspire?
Інтеграція доступна починаючи з .NET MAUI 10 (.NET 10). Для більш ранніх версій підключення до локальних сервісів доведеться налаштовувати вручну — документація Microsoft «Connect to local web services» вам на допомогу.