Resolvers
Resolvers in Aurelia's DI system provide advanced control over instantiating and injecting dependencies. They allow you to modify the resolution behavior for specific dependencies, enabling patterns like lazy loading, optional dependencies, and factory-based instantiation.
Built-in Resolvers
Aurelia offers several built-in resolvers that can be used to customize dependency injection:
Lazy
Purpose: Injects a function that lazily retrieves the dependency when invoked.
Usage:
Explanation: Instead of injecting an instance of
HttpClient
directly, a functiongetHttpClient
is injected. This function can be called to retrieve theHttpClient
instance when needed.
All
Purpose: Injects an array of all registered instances matching the provided key.
Usage:
Explanation: Injects all instances registered under the
Plugin
key as an array, allowing you to manage multiple plugins collectively.
Optional
Purpose: Injects an instance if it exists; otherwise, injects
null
.Usage:
Explanation: The
LoggedInUser
dependency is injected only if it has been previously registered. If not,null
is injected, allowing for optional usage.
Parent
Purpose: Starts dependency resolution from the parent container instead of the current one.
Usage:
Explanation: Instead of resolving from the current container, the resolver starts from the parent container, allowing access to dependencies defined higher up in the container hierarchy.
Factory
Purpose: Injects a factory function that can create instances of the dependency, allowing for dynamic data passing.
Usage:
Explanation: A factory function
createCustomClass
is injected, which can be called with specific data to create instances ofCustomClass
on demand.
NewInstance
Purpose: Injects a new dependency instance each time, ignoring any existing instances in the container.
Usage:
Explanation: Each time
AnotherComponent
is instantiated, a new instance ofCustomClass
is created, regardless of any existing instances in the container.
Using Resolvers with TypeScript
When using TypeScript, the @autoinject
decorator does not support resolvers directly. Instead, you should use argument decorators to apply resolvers without duplicating the constructor's parameter order.
Example:
Custom Resolvers
In addition to built-in resolvers, Aurelia allows you to create custom resolvers to tailor the dependency resolution process to your needs.
Example:
Usage in Injection:
Best Practices
Ensure Consistency Between
@inject
and Constructor Parameters: The dependencies listed in the@inject
decorator must match the constructor parameters in both type and order.Leverage
@autoinject
When Possible: Using@autoinject
with TypeScript can reduce boilerplate and improve clarity by automatically inferring dependencies from constructor parameter types.Use Resolvers Appropriately: Utilize built-in resolvers like
Lazy
,All
, andOptional
to handle specific dependency injection scenarios effectively.Avoid Overusing Singleton Lifetimes: While singletons are convenient, overusing them can lead to tightly coupled code. Prefer transient lifetimes for dependencies that should have a limited scope.
Explicit Configuration for Critical Services: To prevent unintended behaviors, consider explicitly registering essential services with specific lifetimes.
Utilize Child Containers for Scoped Dependencies: When dealing with components like custom elements or routed views, appropriately leverage child containers to scope dependencies.
Maintain Loose Coupling Between Components: Strive for loose coupling by minimizing direct dependencies between unrelated components, enhancing modularity and testability.
Last updated
Was this helpful?