AgentStack
SKILL verified MIT Self-run

Maui Dependency Injection

skill-davidortinau-maui-skills-maui-dependency-injection · by davidortinau

>

No reviews yet
0 installs
11 views
0.0% view→install

Install

$ agentstack add skill-davidortinau-maui-skills-maui-dependency-injection

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Maui Dependency Injection? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Dependency Injection in .NET MAUI

Lifetime Decision Framework

| Question | Answer → Lifetime | |---|---| | Does it hold shared state or is expensive to create? | AddSingleton | | Is it stateless, lightweight, or per-request? | AddTransient | | Do you manage IServiceScope yourself? | AddScoped |

> ⚠️ Avoid AddScoped in MAUI — there is no built-in scope per page. > Using it without manually creating IServiceScope gives you singleton > behaviour silently, which is confusing and error-prone.

Singleton traps

// ❌ ViewModel registered as Singleton — stale data across navigations
builder.Services.AddSingleton();

// ✅ ViewModels are Transient — fresh instance each navigation
builder.Services.AddTransient();

> Register Pages and ViewModels as Transient. Register services that hold > shared state as Singleton (e.g., IDataService, HttpClient factory).


Gotcha: XAML Resource Parsing vs. DI Timing

XAML resources (App.xaml styles, converters) are parsed during InitializeComponent() — before the DI container is fully available. If a resource or converter needs a service, resolve it in CreateWindow(), not in the constructor.

// ❌ Resolving services during XAML parse — container may not be ready
public App(IDataService data)
{
    InitializeComponent(); // XAML parses here
    _data = data;          // may fail for types not yet resolved
}

// ✅ Defer service resolution to CreateWindow
public partial class App : Application
{
    private readonly IServiceProvider _services;

    public App(IServiceProvider services)
    {
        _services = services;
        InitializeComponent();
    }

    protected override Window CreateWindow(IActivationState? activationState)
    {
        // Safe — container is fully built
        var mainPage = _services.GetRequiredService();
        return new Window(new AppShell());
    }
}

Gotcha: Unregistered Page Silently Skips DI

If a Page is used in Shell XAML (`) but **not registered** in builder.Services, MAUI instantiates it with the parameterless constructor. Dependencies are silently null` — no exception.

// ❌ Page not registered — constructor injection silently skipped
// builder.Services.AddTransient(); // missing!

// ✅ Always register pages that need injection
builder.Services.AddTransient();
builder.Services.AddTransient();

Anti-Pattern: Service Locator Overuse

// ❌ Service locator scattered through code — hard to test, hides dependencies
public void DoWork()
{
    var service = this.Handler.MauiContext.Services.GetService();
    service.Load();
}

// ✅ Constructor injection — explicit, testable
public class MyViewModel(IDataService dataService)
{
    public void DoWork() => dataService.Load();
}

> Use explicit resolution (Handler.MauiContext.Services) only when constructor > injection is genuinely unavailable (e.g., inside a custom handler or > platform callback).


Platform-Specific Registration Pitfall

When using #if directives for platform services, ensure the interface is always registered — otherwise consumers on untargeted platforms get a runtime null.

// ❌ No registration on Windows — GetService returns null
#if ANDROID
builder.Services.AddSingleton();
#elif IOS || MACCATALYST
builder.Services.AddSingleton();
#endif

// ✅ Cover all platforms or provide a no-op fallback
#if ANDROID
builder.Services.AddSingleton();
#elif IOS || MACCATALYST
builder.Services.AddSingleton();
#elif WINDOWS
builder.Services.AddSingleton();
#endif

Checklist

  • [ ] Every Page and ViewModel that needs injection is registered in MauiProgram.cs
  • [ ] Pages/ViewModels are AddTransient; shared services are AddSingleton
  • [ ] Constructor injection used everywhere possible; service locator only as last resort
  • [ ] Interfaces defined for any service you need to mock in tests
  • [ ] Platform-specific #if registrations cover all target platforms (or provide fallback)
  • [ ] Late-bound services resolved in CreateWindow(), not during XAML parse
  • [ ] AddScoped only used when you manually manage IServiceScope

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.