davianspace_dependencyinjection 1.0.3
davianspace_dependencyinjection: ^1.0.3 copied to clipboard
Microsoft.Extensions.DependencyInjection-inspired DI container for Dart and Flutter with scopes, async resolution, keyed services, and diagnostics.
Changelog #
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
1.0.3 — 2026-02-25 #
Added #
- Options Pattern integration —
davianspace_optionsis now a runtime dependency.configure<T>()andpostConfigure<T>()extension methods onServiceCollectionregisterOptions<T>(singleton),OptionsSnapshot<T>(scoped), andOptionsMonitor<T>(singleton) automatically. A keyedOptionsChangeNotifieris registered per options type to drive live reloads without a directTreference. - Configuration integration —
davianspace_configurationis now a runtime dependency.addConfiguration(config)andaddConfigurationBuilder(build)extension methods onServiceCollectionregisterConfiguration(andConfigurationRootwhen applicable) as injectable singletons.
Changed #
- SDK lower bound relaxed from
>=3.3.0to>=3.0.0. Field promotion inCallSiteExecutorwas refactored to use local variable capture to remain compatible with Dart 3.0.
Fixed #
CallSiteExecutor._scopedCachefield promotion — replaced implicit_scopedCache != nullfield promotion (Dart ≥3.2 only) with explicit local variable capture (final cache = _scopedCache) in both the sync_resolveScopedand async_resolveScopedAsyncpaths.- Dispose guard on root
ServiceProvider— all resolution methods (tryGet,getRequired,getAll,getAsync,tryGetAsync,tryGetKeyed,getRequiredKeyed,getAsyncKeyed,createScope,resolveRequired,resolveAll) now throwStateErrorwhen called on a disposed provider, consistent with the guard already in place onScopedServiceProvider. CallSiteValidator.validate()—collectAllparameter honoured — the parameter was previously ignored; violations now accumulate intoContainerBuildExceptionwhencollectAll: true(default), or throwScopeViolationExceptionimmediately whencollectAll: false.DisposalExceptionreports all failures — previously only the first disposal error was recorded; every failing service is now captured in theerrorslist. TheserviceTypeandcauseconvenience getters retain first-error access for backward compatibility.DependencyGraph.detectCycles()— iterative DFS — replaced the recursive depth-first search with an explicit stack to eliminate the risk of aStackOverflowErroron deep (but acyclic) dependency graphs.OptionsChangeDisposable.dispose()is now idempotent — callingdispose()twice no longer double-removes the listener or throws.ScopeManager.disposeAll()/disposeAllAsync()continue on error — all scopes are now disposed even when one throws; the first error is rethrown after all scopes have been processed, matching the behaviour ofDisposalTracker.RootServiceProvider.dispose()— unawaiteddiagnostics.close()— the fire-and-forgetFuturereturned byStreamController.close()is now explicitly markedunawaited, eliminating the implicit discard.
Performance #
CallSiteExecutorcached per-provider — bothServiceProviderandScopedServiceProviderpreviously allocated a newCallSiteExecutor(5-argument constructor) on every resolution call. The executor is now alate finalfield initialised once per provider, reducing per-call allocation to a singleResolutionChainobject.
Tests #
- Test suite expanded from 52 to 112 tests (+60).
- Added
ActivatorHelper.instance.clear()to globalsetUpto prevent inter-test contamination via the global singleton registry. - New test groups: Root provider disposal guard (11),
DisposalExceptionmulti-error (3), Scope violation validatorcollectAll(2),CallSiteExecutorcaching (2),ScopeManager(11),Lazy<T>(6),ActivatorUtilities(4), Options pattern (10),ServiceModule(2),DependencyGraphiterative DFS (5).
1.0.0 — 2024-01-01 #
Added #
ServiceCollection— mutable registration builder with fluent API.ServiceProvider— immutable, validated root DI container.ScopedServiceProvider/ServiceScope— per-scope provider with isolatedScopedCacheandDisposalTracker.- Service lifetimes: singleton, scoped, transient.
- Factory registration (
addSingletonFactory,addScopedFactory,addTransientFactory) withServiceProviderBaseparameter (no unsafe casts). - Async factory registration (
addSingletonAsync,addScopedAsync,addTransientAsync,addKeyedSingletonAsync,addKeyedScopedAsync,addKeyedTransientAsync). - Pre-built instance registration (
addInstance). - Keyed services — register multiple implementations under a typed key
(
addKeyedSingleton,addKeyedScoped,addKeyedTransient, factory/async variants); resolved withgetRequiredKeyed/tryGetKeyed/getAsyncKeyed. - Multi-registration —
getAll<T>()returns every registration forTin insertion order (backed byMap<Type, List<CallSite>>for O(1) lookup). tryGet<T>()— null-safe synchronous resolution.tryGetAsync<T>()— null-safe asynchronous resolution (on both root and scoped providers).replace(ServiceDescriptor)— override an existing registration.addRange(Iterable<ServiceDescriptor>)— bulk registration.tryAdd/tryAddSingleton/tryAddScoped/tryAddTransient/tryAddKeyed— no-op if type is already registered.isRegistered<T>()/isKeyedRegistered<T>(key)on concrete providers.ResolutionChain— O(1) Set-backed cycle detection (previously O(n)).- Cycle detection propagated through the full transitive dependency graph.
DisposalTracker.track()throwsStateErrorin production (not just in debug mode viaassert).- Scope-disposed guard on all
ScopedServiceProviderresolution methods. ServiceProviderOptions.productionis the new default forbuildServiceProvider()(wasdevelopment).CallSiteValidator— captive-dependency scope validation (singleton depending on scoped service) in development mode.DependencyGraph— topological cycle detection at build time.ServiceProviderDiagnostics— structured trace/info/warn/error events.- Constructor injection via AOT-safe
ReflectionHelperfactory system. dumpRegistrations()diagnostic helper onServiceProvider.