Middleware
Middleware docs are included for historical reasons. They are likely to be remove in favor of more appropiate features.
Middlewares can be added to a container in order to intercept service resolution requests:
Basic middleware
import { interfaces, Container } from "inversify";
function logger(planAndResolve: interfaces.Next): interfaces.Next {
return (args: interfaces.NextArgs) => {
let start = new Date().getTime();
let result = planAndResolve(args);
let end = new Date().getTime();
console.log(`wooooo ${end - start}`);
return result;
};
}
let container = new Container();
container.applyMiddleware(logger);
Multiple middleware functions
When multiple middleware functions are applied:
container.applyMiddleware(middleware1, middleware2);
The middleware will be invoked from right to left.
This means that middleware2
is invoked before middleware1
.
Context interceptor
In some cases you may want to intercept the resolution plan.
The default contextInterceptor
is passed to the middleware as an property of args
.
function middleware1(planAndResolve: interfaces.Next): interfaces.Next<unknown> {
return (args: interfaces.NextArgs) => {
// args.nextContextInterceptor
// ...
};
}
You can extend the default contextInterceptor
using a function:
function middleware1(planAndResolve: interfaces.Next<unknown>): interfaces.Next<unknown> {
return (args: interfaces.NextArgs) => {
let nextContextInterceptor = args.contextInterceptor;
args.contextInterceptor = (context: interfaces.Context) => {
console.log(context);
return nextContextInterceptor(context);
};
return planAndResolve(args);
};
}
Custom metadata reader
It is not recommended to create your own custom metadata reader. We have included this feature to allow library / framework creators to have a higher level of customization but the average user should not use a custom metadata reader. In general, a custom metadata reader should only be used when developing a framework in order to provide users with an annotation APIs less explicit than the default annotation API.
If you are developing a framework or library and you create a custom metadata reader,
Please remember to provide your framework with support for an alternative for all the
decorators in the default API: @injectable
, @inject
, @multiInject
, @tagged
,
@named
, @optional
, @postConstruct
, @preDestroy
@targetName
& @unmanaged
.
Middleware allows you to intercept a plan and resolve it but you are not allowed to change the way the annotation phase behaves.
There is a second extension point that allows you to decide what kind of annotation system you would like to use. The default annotation system is powered by decorators and reflect-metadata:
@injectable()
class Ninja implements Ninja {
private _katana: Katana;
private _shuriken: Shuriken;
constructor(
@inject("Katana") katana: Katana,
@inject("Shuriken") shuriken: Shuriken
) {
this._katana = katana;
this._shuriken = shuriken;
}
public fight() { return this._katana.hit(); };
public sneak() { return this._shuriken.throw(); };
}
You can use a custom metadata reader to implement a custom annotation system.
For example, you could implement an annotation system based on static properties:
class Ninja implements Ninja {
public static constructorInjections = [
"Katana", "Shuriken"
];
private _katana: Katana;
private _shuriken: Shuriken;
constructor(
katana: Katana,
shuriken: Shuriken
) {
this._katana = katana;
this._shuriken = shuriken;
}
public fight() { return this._katana.hit(); };
public sneak() { return this._shuriken.throw(); };
}
A custom metadata reader must implement the interfaces.MetadataReader
interface.
A full example can be found in our unit tests.
Once you have a custom metadata reader you will be ready to apply it:
let container = new Container();
container.applyCustomMetadataReader(new StaticPropsMetadataReader());