What's wrong
AddNavigationProvider<TNavigationProvider>() (UndoRedo/ServiceCollectionExtensions.cs ~L83-89) uses TryAddScoped<INavigationProvider, TNavigationProvider>(). But UndoRedoService, which takes INavigationProvider? in its constructor, is registered Transient by AddUndoRedo() (~L34) and Singleton by AddSingletonUndoRedo() (~L76). A scoped dependency of a singleton (or of a transient resolved from the root) is a captive dependency, which Microsoft.Extensions.DependencyInjection rejects under ValidateScopes/ValidateOnBuild — both on by default in the generic host's Development environment.
Failure scenarios (reproduced with temporary MSTest tests)
AddSingletonUndoRedo() + AddNavigationProvider<Nav>() (the natural desktop-app setup):
BuildServiceProvider(new ServiceProviderOptions { ValidateOnBuild = true, ValidateScopes = true }) throws
AggregateException ... Cannot consume scoped service 'ktsu.UndoRedo.INavigationProvider' from singleton 'ktsu.UndoRedo.Contracts.IUndoRedoService'.
Without validation, the singleton silently captures a provider resolved from the root scope, so "scoped" never actually applies.
AddUndoRedo() + AddNavigationProvider<Nav>() (what docs/dependency-injection.md ~L123-126 recommends "for most applications"):
resolving IUndoRedoService from the root provider with ValidateScopes = true throws
InvalidOperationException: Cannot resolve 'ktsu.UndoRedo.Contracts.IUndoRedoService' from root provider because it requires scoped service 'ktsu.UndoRedo.INavigationProvider'.
So a consumer following the docs gets a startup crash under Host.CreateDefaultBuilder in Development.
Suggested fix
Make the navigation provider's lifetime compatible with the undo/redo registration — e.g. change AddNavigationProvider<T> to TryAddTransient, or deprecate the scoped variant and direct users to AddSingletonNavigationProvider alongside AddSingletonUndoRedo. Update the lifetime table / "Scoped Navigation Provider" section in docs/dependency-injection.md to match.
Acceptance criteria
- Tests build a provider with
ValidateOnBuild = true, ValidateScopes = true for each supported pairing (AddUndoRedo/AddSingletonUndoRedo × each Add*NavigationProvider) and resolve IUndoRedoService from the root without exceptions — or unsupported pairings are removed/documented.
What's wrong
AddNavigationProvider<TNavigationProvider>()(UndoRedo/ServiceCollectionExtensions.cs~L83-89) usesTryAddScoped<INavigationProvider, TNavigationProvider>(). ButUndoRedoService, which takesINavigationProvider?in its constructor, is registered Transient byAddUndoRedo()(~L34) and Singleton byAddSingletonUndoRedo()(~L76). A scoped dependency of a singleton (or of a transient resolved from the root) is a captive dependency, which Microsoft.Extensions.DependencyInjection rejects underValidateScopes/ValidateOnBuild— both on by default in the generic host's Development environment.Failure scenarios (reproduced with temporary MSTest tests)
AddSingletonUndoRedo()+AddNavigationProvider<Nav>()(the natural desktop-app setup):BuildServiceProvider(new ServiceProviderOptions { ValidateOnBuild = true, ValidateScopes = true })throwsAggregateException ... Cannot consume scoped service 'ktsu.UndoRedo.INavigationProvider' from singleton 'ktsu.UndoRedo.Contracts.IUndoRedoService'.Without validation, the singleton silently captures a provider resolved from the root scope, so "scoped" never actually applies.
AddUndoRedo()+AddNavigationProvider<Nav>()(whatdocs/dependency-injection.md~L123-126 recommends "for most applications"):resolving
IUndoRedoServicefrom the root provider withValidateScopes = truethrowsInvalidOperationException: Cannot resolve 'ktsu.UndoRedo.Contracts.IUndoRedoService' from root provider because it requires scoped service 'ktsu.UndoRedo.INavigationProvider'.So a consumer following the docs gets a startup crash under
Host.CreateDefaultBuilderin Development.Suggested fix
Make the navigation provider's lifetime compatible with the undo/redo registration — e.g. change
AddNavigationProvider<T>toTryAddTransient, or deprecate the scoped variant and direct users toAddSingletonNavigationProvideralongsideAddSingletonUndoRedo. Update the lifetime table / "Scoped Navigation Provider" section indocs/dependency-injection.mdto match.Acceptance criteria
ValidateOnBuild = true, ValidateScopes = truefor each supported pairing (AddUndoRedo/AddSingletonUndoRedo× eachAdd*NavigationProvider) and resolveIUndoRedoServicefrom the root without exceptions — or unsupported pairings are removed/documented.