在Aurelia(+TypeScript)中如何直接引用容器并显式请求新实例?
Absolutely! In Aurelia (paired with TypeScript), you can absolutely reference the dependency injection (DI) container directly in view models or other contexts, and explicitly request new instances whenever you need them. Let me break down how to do this properly, along with best practices:
1. Inject the Container into Your Context
The recommended way to access the DI container is via constructor injection—Aurelia lets you inject the Container class directly, just like any other dependency. This keeps your code aligned with Aurelia's core DI patterns.
Example TypeScript code:
import { Container } from 'aurelia-dependency-injection'; import { MyCustomService } from './my-custom-service'; export class DashboardViewModel { private container: Container; constructor(container: Container) { this.container = container; } // ... rest of your view model logic }
2. Requesting New Instances
Once you have a reference to the container, you have a few options to get fresh instances:
Option A: Use invoke() for one-off fresh instances
The invoke() method creates a brand new instance of your target class every time you call it—this bypasses the dependency's registered scope (even if it's set as a singleton). It's perfect when you need a one-time fresh instance without altering global registration rules.
Example:
// Inside a view model method spawnNewService(): void { const freshServiceInstance = this.container.invoke(MyCustomService); // This instance is unique to this call—no shared state with other instances }
Option B: Register as transient and use get()
If you want every get() call to return a new instance, register your dependency as transient first. This makes fresh instances the default behavior whenever you resolve the dependency via the container.
First, register the service (usually in your app's setup or feature registration):
import { Container } from 'aurelia-dependency-injection'; import { MyCustomService } from './my-custom-service'; // In main.ts or a feature's registration file container.registerTransient(MyCustomService);
Then in your view model:
getFreshService(): void { const freshService = this.container.get(MyCustomService); // A new instance is returned every time you call this }
Option C: Create a child container for scoped instances
If you need a set of isolated, related instances (like for a modal or a nested component flow), create a child container. Instances resolved from the child container are scoped to it, and you can dispose of the child container later to clean up those instances.
Example:
createScopedContext(): void { const childContainer = this.container.createChild(); const scopedService = childContainer.get(MyCustomService); // This instance is only available within the child container's scope }
Key Best Practices
- Avoid overusing direct container access: While it's allowed, prefer constructor injection for most dependencies. Direct container calls can make your code harder to test and more tightly coupled to Aurelia's DI system.
- Testability: When writing unit tests, you can mock the
Containeror use Aurelia's test harness to provide a test container with mocked dependencies. - Scope clarity: Be intentional about whether you need a singleton, transient, or scoped instance. Use
invoke()sparingly for edge cases where you need to bypass the registered scope temporarily.
内容的提问来源于stack exchange,提问作者Jorge Garcia

