# Dependency injection The MVVM Toolkit deliberately ships **no DI container of its own** — it integrates with `Microsoft.Extensions.DependencyInjection`, the same container used by ASP.NET Core, Worker services, and the .NET Generic Host. > **Default to constructor injection.** Resolve services and child > ViewModels through the constructor of the type that needs them. Avoid the > service-locator pattern (`Ioc.Default.GetService()`) in user code. --- ## Recommended composition root (Generic Host) ```csharp using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; public partial class App : Application { public IHost Host { get; } public App() { Host = Microsoft.Extensions.Hosting.Host .CreateDefaultBuilder() .ConfigureServices((_, services) => { services.AddSingleton(); services.AddSingleton(); services.AddSingleton(WeakReferenceMessenger.Default); services.AddSingleton(); services.AddTransient(); services.AddTransient(); }) .Build(); } public static T GetService() where T : class => ((App)Current).Host.Services.GetRequiredService(); } ``` Generic Host benefits: - `appsettings.json` configuration binding via `Microsoft.Extensions.Configuration` - Built-in logging via `Microsoft.Extensions.Logging` - Hosted services (`IHostedService`) for background work - Scope validation in development builds > On WPF and Windows Forms, integrate the host lifetime with the > application lifetime — see > [Use the .NET Generic Host in a WPF app](https://learn.microsoft.com/en-us/dotnet/desktop/wpf/app-development/how-to-use-host-builder). --- ## Composition root (no Generic Host) When you don't need configuration/logging/hosting, build the provider directly: ```csharp public partial class App : Application { public IServiceProvider Services { get; } public App() { var services = new ServiceCollection(); services.AddSingleton(); services.AddTransient(); Services = services.BuildServiceProvider(); } public static T GetService() where T : class => ((App)Current).Services.GetRequiredService(); } ``` --- ## Constructor injection Inject services and child ViewModels through the constructor: ```csharp public sealed partial class ContactViewModel( IFilesService files, IMessenger messenger, ILogger logger) : ObservableRecipient(messenger) { [ObservableProperty] private string? name; [RelayCommand] private async Task SaveAsync() { logger.LogInformation("Saving {Name}", Name); await files.SaveAsync(Name!); } } ``` Why constructor injection beats a service locator: - Dependencies are explicit and visible at the call site. - Unit tests inject fakes/mocks without resorting to runtime tricks. - The DI container validates the dependency graph at startup (with `BuildServiceProvider(validateScopes: true)` in dev). - No hidden runtime failures — missing registrations throw immediately. --- ## Lifetimes | Lifetime | Method | Typical use in XAML apps | |----------|--------|--------------------------| | Singleton | `AddSingleton` | Shell/main-window VM, settings, file/HTTP services, the shared `IMessenger`, app-wide caches | | Transient | `AddTransient` | Per-page or per-document ViewModels (a fresh instance every resolve) | | Scoped | `AddScoped` | Rarely needed in client apps; useful when you create explicit `IServiceScope`s (per-window scopes, per-request scopes for embedded HTTP) | ```csharp services.AddSingleton(); // 1 instance for app lifetime services.AddTransient(); // new instance per resolve services.AddScoped(); // 1 per scope (rare) ``` --- ## Resolving in a View Resolve the root ViewModel for the page in code-behind, then let it pull its own dependencies: ```csharp public sealed partial class ContactPage : Page { public ContactViewModel ViewModel { get; } public ContactPage() { ViewModel = App.GetService(); InitializeComponent(); } } ``` Bind in XAML with `{x:Bind ViewModel.Xxx}` (compiled bindings) or `{Binding Xxx}` against the `DataContext`. For navigation frameworks (WinUI 3 `Frame.Navigate`, MAUI Shell, Prism, MVVMCross), let the framework resolve the page and the page resolves its ViewModel from DI. Avoid creating ViewModels manually. --- ## `IMessenger` registration The toolkit provides two implementations. Register the one you want once, and inject `IMessenger` everywhere: ```csharp services.AddSingleton(WeakReferenceMessenger.Default); // or services.AddSingleton(StrongReferenceMessenger.Default); ``` Then: ```csharp public sealed partial class MyViewModel(IMessenger messenger) : ObservableRecipient(messenger) { } ``` Multiple messengers (e.g., one per window) are also valid — register them with keyed services or as scoped instances. --- ## Keyed services (.NET 8+) Useful when you have multiple implementations of the same interface and want to choose one by key: ```csharp services.AddKeyedSingleton("csv"); services.AddKeyedSingleton("json"); public sealed partial class ExportViewModel( [FromKeyedServices("csv")] IExporter csvExporter, [FromKeyedServices("json")] IExporter jsonExporter) : ObservableObject { /* ... */ } ``` --- ## Testing seams Constructor-injected dependencies are trivial to swap in tests. With `Moq` (or `NSubstitute` / `FakeItEasy`): ```csharp [Fact] public async Task Save_calls_files_service() { var files = new Mock(); var messenger = new WeakReferenceMessenger(); var logger = NullLogger.Instance; var vm = new ContactViewModel(files.Object, messenger, logger) { Name = "Ada" }; await vm.SaveCommand.ExecuteAsync(null); files.Verify(f => f.SaveAsync("Ada"), Times.Once); } ``` If you find yourself needing to mock `Ioc.Default` or static state, the ViewModel is using a service locator — refactor to constructor injection instead. --- ## Legacy: `Ioc.Default` The toolkit ships `CommunityToolkit.Mvvm.DependencyInjection.Ioc` for cases where constructor injection is impossible (e.g., a XAML-instantiated ViewModel for design-time data, a `ValueConverter`, a control template). Setup: ```csharp Ioc.Default.ConfigureServices( new ServiceCollection() .AddSingleton() .AddTransient() .BuildServiceProvider()); ``` Resolve: ```csharp var files = Ioc.Default.GetRequiredService(); ``` Treat this as an escape hatch only. Inside ViewModels, services, and any class you can pass through DI, prefer constructor injection. --- ## Common mistakes 1. **Resolving children from inside a ViewModel constructor via `Ioc`.** Hides the dependency. Inject the child VM (or a factory) through the constructor instead. 2. **Registering everything as singleton.** A "per-document" ViewModel registered as singleton becomes shared state across all documents — a subtle data-corruption bug. Use `AddTransient` for per-instance VMs. 3. **Building multiple `ServiceProvider` instances.** Each `BuildServiceProvider()` is a fresh container — singletons aren't shared. Build once at startup, then reuse. 4. **Capturing the `IServiceProvider` itself in long-lived objects.** Indicates a service-locator pattern. Inject the specific dependencies you need. 5. **Forgetting to wire scope validation in development.** Use `Host.CreateDefaultBuilder()` (which sets `ValidateScopes` and `ValidateOnBuild` in development) so registration mistakes fail at startup, not at first use.