Loading...
Loading...
Guidance for dependency injection in .NET MAUI apps — service registration, lifetime selection (Singleton/Transient/Scoped), constructor injection, automatic resolution via Shell navigation, explicit resolution patterns, platform-specific registrations, and testability best practices. USE FOR: "dependency injection", "DI registration", "AddSingleton", "AddTransient", "AddScoped", "service registration", "constructor injection", "IServiceProvider", "MauiProgram DI", "register services". DO NOT USE FOR: data binding (use maui-data-binding), Shell route setup (use maui-shell-navigation), or unit test mocking patterns (use maui-unit-testing).
npx skill4agent add davidortinau/maui-skills maui-dependency-injectionbuilder.ServicesCreateMauiApp()public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder.UseMauiApp<App>();
// Services
builder.Services.AddSingleton<IDataService, DataService>();
builder.Services.AddTransient<IApiClient, ApiClient>();
// ViewModels
builder.Services.AddTransient<MainViewModel>();
builder.Services.AddTransient<DetailViewModel>();
// Pages
builder.Services.AddTransient<MainPage>();
builder.Services.AddTransient<DetailPage>();
return builder.Build();
}| Lifetime | Use When | Examples |
|---|---|---|
| Shared state, expensive to create, or app-wide config | Database connection, settings service, HttpClient factory |
| Stateless, lightweight, or per-request usage | ViewModels, pages, API call wrappers |
| Per-scope lifetime (rarely used in MAUI — no built-in scope per page) | Scoped unit-of-work in manually created scopes |
Rule of thumb: Usefor ViewModels and Pages. UseAddTransientfor services that hold shared state or are expensive to construct. AvoidAddSingletonunless you create and manageAddScopedinstances yourself.IServiceScope
public class MainViewModel
{
private readonly IDataService _dataService;
private readonly IApiClient _apiClient;
public MainViewModel(IDataService dataService, IApiClient apiClient)
{
_dataService = dataService;
_apiClient = apiClient;
}
}BindingContextpublic partial class MainPage : ContentPage
{
public MainPage(MainViewModel viewModel)
{
InitializeComponent();
BindingContext = viewModel;
}
}// In MauiProgram.cs
builder.Services.AddTransient<DetailPage>();
builder.Services.AddTransient<DetailViewModel>();
// Route registration (AppShell.xaml.cs or startup)
Routing.RegisterRoute(nameof(DetailPage), typeof(DetailPage));
// Navigation — DI resolves DetailPage and its DetailViewModel
await Shell.Current.GoToAsync(nameof(DetailPage));// From any Element with a Handler
var service = this.Handler.MauiContext.Services.GetService<IDataService>();IServiceProviderpublic class MyService
{
private readonly IServiceProvider _serviceProvider;
public MyService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public void DoWork()
{
var api = _serviceProvider.GetRequiredService<IApiClient>();
}
}// In MauiProgram.cs
#if ANDROID
builder.Services.AddSingleton<INotificationService, AndroidNotificationService>();
#elif IOS || MACCATALYST
builder.Services.AddSingleton<INotificationService, AppleNotificationService>();
#elif WINDOWS
builder.Services.AddSingleton<INotificationService, WindowsNotificationService>();
#endifpublic interface IDataService
{
Task<List<Item>> GetItemsAsync();
}
public class DataService : IDataService
{
public async Task<List<Item>> GetItemsAsync() { /* ... */ }
}
// Register the interface → implementation mapping
builder.Services.AddSingleton<IDataService, DataService>();var services = new ServiceCollection();
services.AddSingleton<IDataService, FakeDataService>();App.xamlAppIServiceProviderAppCreateWindow()public partial class App : Application
{
private readonly IServiceProvider _services;
public App(IServiceProvider services)
{
_services = services;
InitializeComponent(); // XAML resources parse here
}
protected override Window CreateWindow(IActivationState? activationState)
{
// Safe to resolve services here — container is fully built
var mainPage = _services.GetRequiredService<MainPage>();
return new Window(new AppShell());
}
}MauiProgram.csAddSingleton#ifCreateWindow()