Clone this wiki locally
The notion of a Named Scope is the most general and powerful facility offered in this Extension -- the other facilities are actually implemented using the Named Scope mechanism.
A Named Scope lets you specify on a
Binding that objects created via the Binding are to act as the Scope Object for other objects that are generated as part of the work of Composing the object graph for a given
Get<T>() Resolve Request.
The facility consists of two Extension Methods
DefinesNamedScope(string scopeName). This identifies the
Binding as creating a Scope which can be referred to in other
Bindings. Only a single instance of a service scoped in this manner will be created per Object Graph being Composed (each Composition in the Composition Root (e.g. via
Kernel.Get<T>()will generate a separately isolated instance)
InNamedScope(string scopeName). This constrains all resolutions of the Service Type being bound to produce a single shared instance which will be yielded as part of any Resolve within a given Object Graph Composition. (TODO verify) Note that an
Exceptionwill be thrown if a Resolve has not yet had cause to visit a Binding that employs
DefinesNamedScope()to establish the Named Scope with the cited
scopeNameearlier in the Object Graph Composition.
Scenario 1: Sheet implementation with collaborating components sharing a single Sheet Data Repository per Sheet object within a single Object Graph Composition
Lets examine how this works using an example scenario. Imagine that you are creating an Excel-like application that has multiple worksheets. As part of the implementation, you have multiple components (e.g. the data repository) that have a worksheet as their Scope and need to be accessible to several other components.
To be more concrete you might have a
Sheet implementation which relies on two collaborating components -- one to draw the sheet (
SheetPresenter) and one to update the calculated values on each cell (
SheetCalculator). These two parts of the overall Sheet code each have a dependency on
SheetDataRepository and the same instance needs to be supplied to each one. One can’t simply
Bind...().To<SheetDataRepository>().InSingletonScope() because you need to be able have multiple sheets in the system. In this case the
Bindings can be specified as follows in order to have the
Sheet instance act as the Scope relative to which a single
SheetDataRepository instances is created and shared for subsequent usages within the Object Graph being Composed:
const string ScopeName = "Sheet"; Bind<Sheet>().ToSelf().DefinesNamedScope(ScopeName); Bind<SheetDataRepository>().ToSelf().InNamedScope(ScopeName); Bind<SheetPresenter>().ToSelf(); Bind<SheetCalculator>().ToSelf();
Scenario 2: Deferred Creation of Services via Factories that require Shared Objects from the Initial Object Graph
In conjunction with
Ninject.Extensions.ContextPreservation this Scope type can also be used for instances that are not created as direct dependency within a single Object Graph Composition, but at a later point in time by a (possibly generated) Factory that was Resolved as a dependency in the initial Object Graph Composition.
Extending Scenario #1, lets say
SheetCalculator gets a Factory (
CellCalculatorFactory) injected with a
CreateCellCalculator() method that is used by the
SheetCalculator to create a
CellCalculator whenever a formula is added to a cell. However, the
CellCalculator of course needs to gain access to a
SheetDataRepository -- the single one that was generated in the initial Object Graph Composition.
This scenario can be modelled using the following
this.kernel.Load(new NamedScopeModule()); this.kernel.Load(new ContextPreservationModule()); const string ScopeName = "Sheet"; Bind<Sheet>().ToSelf().DefinesNamedScope(ScopeName); Bind<SheetDataRepository>().ToSelf().InNamedScope(ScopeName); Bind<SheetPresenter>().ToSelf(); Bind<SheetCalculator>().ToSelf(); Bind<CellCalculatorFactory>().ToSelf(); Bind<CellCalculator>().ToSelf();