用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/tomevault-io/skills-registry --skill maui-dependency-injection命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
| Use when this capability is needed.
> Use when this capability is needed.
Review architecture and API design for the vfs-s3 project. Use when the user mentions @architect, asks to review an issue's design, discuss module boundaries, API shape, or architectural decisions for vfs-s3. Also trigger when the user wants to create an ADR (Architecture Decision Record) or evaluate a technical approach for the project. Intended for dispatch from Codex automation or Claude routines; GitHub trigger phrase: @vfs-s3-bot please prepare design doc Use when this capability is needed.
基于 SOC 职业分类
正在显示 SKILL.md
| name | maui-dependency-injection |
| description | > Use when this capability is needed. |
| 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
AddScopedin MAUI — there is no built-in scope per page. Using it without manually creatingIServiceScopegives you singleton behaviour silently, which is confusing and error-prone.
// ❌ ViewModel registered as Singleton — stale data across navigations
builder.Services.AddSingleton<DetailViewModel>();
// ✅ ViewModels are Transient — fresh instance each navigation
builder.Services.AddTransient<DetailViewModel>();
Register Pages and ViewModels as Transient. Register services that hold shared state as Singleton (e.g.,
IDataService,HttpClientfactory).
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<MainPage>();
return new Window(new AppShell());
}
}
If a Page is used in Shell XAML (<ShellContent ContentTemplate="...">) 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<DetailPage>(); // missing!
// ✅ Always register pages that need injection
builder.Services.AddTransient<DetailPage>();
builder.Services.AddTransient<DetailViewModel>();
// ❌ Service locator scattered through code — hard to test, hides dependencies
public void DoWork()
{
var service = this.Handler.MauiContext.Services.GetService<IDataService>();
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).
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<INotificationService, AndroidNotificationService>();
#elif IOS || MACCATALYST
builder.Services.AddSingleton<INotificationService, AppleNotificationService>();
#endif
// ✅ Cover all platforms or provide a no-op fallback
#if ANDROID
builder.Services.AddSingleton<INotificationService, AndroidNotificationService>();
#elif IOS || MACCATALYST
builder.Services.AddSingleton<INotificationService, AppleNotificationService>();
#elif WINDOWS
builder.Services.AddSingleton<INotificationService, WindowsNotificationService>();
#endif
MauiProgram.csAddTransient; shared services are AddSingleton#if registrations cover all target platforms (or provide fallback)CreateWindow(), not during XAML parseAddScoped only used when you manually manage IServiceScopeConverted and distributed by TomeVault — claim your Tome and manage your conversions.