Skip to content

Commit 6b4cc69

Browse files
authored
fix: update service bindings to avoid caching (#1644)
1 parent 64aa399 commit 6b4cc69

File tree

4 files changed

+60
-3
lines changed

4 files changed

+60
-3
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212

1313
### Fixed
1414
- Fixed container to properly resolve async `.toService` bindings.
15+
- Fixed `.toService` binding to properly disable caching any values.
1516

1617
## [6.1.4]
1718

src/syntax/binding_to_syntax.ts

+16-2
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,28 @@ class BindingToSyntax<T> implements interfaces.BindingToSyntax<T> {
116116
}
117117

118118
public toService(service: interfaces.ServiceIdentifier<T>): void {
119-
this.toDynamicValue((context: interfaces.Context): T | Promise<T> => {
119+
this._binding.type = BindingTypeEnum.DynamicValue;
120+
121+
// Service bindings should never ever be cached. This is just a workaround to achieve that. A better design should replace this approach.
122+
Object.defineProperty(this._binding, 'cache', {
123+
configurable: true,
124+
enumerable: true,
125+
get() {
126+
return null;
127+
},
128+
set(_value: unknown) {},
129+
});
130+
this._binding.dynamicValue = (
131+
context: interfaces.Context,
132+
): T | Promise<T> => {
120133
try {
121134
return context.container.get<T>(service);
122135
} catch (_error: unknown) {
123136
// This is a performance degradation in this edge case, we do need to improve the internal resolution architecture in order to solve this properly.
124137
return context.container.getAsync<T>(service);
125138
}
126-
});
139+
};
140+
this._binding.implementationType = null;
127141
}
128142
}
129143

test/bugs/issue_1416.test.ts

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { describe, it } from 'mocha';
2+
import sinon from 'sinon';
3+
4+
import { Container, injectable, preDestroy } from '../../src/inversify';
5+
6+
describe('Issue 1416', () => {
7+
it('should allow providing default values on optional bindings', async () => {
8+
@injectable()
9+
class Test1 {
10+
public stub: sinon.SinonStub<unknown[], void> = sinon.stub();
11+
12+
@preDestroy()
13+
public destroy() {
14+
this.stub();
15+
}
16+
}
17+
18+
@injectable()
19+
class Test2 {
20+
public destroy(): void {}
21+
}
22+
23+
@injectable()
24+
class Test3 {
25+
public destroy(): void {}
26+
}
27+
28+
const container: Container = new Container({ defaultScope: 'Singleton' });
29+
30+
container.bind(Test1).toSelf();
31+
container.bind(Test2).toService(Test1);
32+
container.bind(Test3).toService(Test1);
33+
34+
const test1: Test1 = container.get(Test1);
35+
container.get(Test2);
36+
container.get(Test3);
37+
38+
container.unbindAll();
39+
40+
sinon.assert.calledOnce(test1.stub);
41+
});
42+
});

wiki/tagged_bindings.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Tagged bindings
22

33
We can use tagged bindings to fix `AMBIGUOUS_MATCH` errors when two or more
4-
concretions have been bound to an abstraction. Notice how the constructor
4+
concretions have been bound to an abstraction. Notice how the constructor
55
arguments of the `Ninja` class have been annotated using the `@tagged` decorator:
66

77
```ts

0 commit comments

Comments
 (0)