During its lifetime, a QueryStorm app instantiates many objects: components, ribbons, context menu commands, excel functions classes as well as any domain-specific services.
Each of these classes can have dependencies of their own. For example, a component could depend on a service in order to access some remote data.
To make it easy for objects to get the dependencies they need, QueryStorm apps use dependency injection, specifically, the Unity IOC Container.
Dependencies can be resolved in three ways:
- Constructor injection (preferred)
- Property injection (using the
- Explicitly, by using the
For example, if a component needs access to the current workbook, it can request an
IWorkbookAccessor by including an argument for it in the constructor (constructor injection):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
The container instance itself is created by the
App base class and is exposed via the
The container is initially populated with registrations for a number of services that provide general-purpose functionality to apps:
IExcelAccessor- allows access to the root Excel
IWorkbookAccessor- allows access to the current workbook (i.e. the containing workbook for workbook apps, active workbook for extension apps).
IShortcutService- allows registering additional keyboard shortcuts (can override existing Excel shortcuts).
IQueryStormLogger- allows writing to the QueryStorm log window (Runtime) and messages pane (IDE).
ISyncRunner- allows running actions on the main Excel thread.
IDialogService- offers the ability to show general purpose dialogs (message-boxes, save-file dialogs, input dialogs).
IDataContext- gives raw (untyped) access to the datacontext (usually workbook tables and variables).
IEventHandlerHook- service that allows intercepting event handlers. By default a pass-through implementation that can be replaced with a custom implementation (e.g. to show a custom dialog while async event handlers are executing).
ProjectConfiguration- allows strongly typed access to the contents of the
ConnectionStringsDictionary- allows strongly typed access to the
ConnectionStringssection of the
Jot.Trackerinstance used to save configuration settings for the app.
CredentialsVault- used to securely store credentials for the app (usernames, passwords, api keys). Mainly used by scripts with templated connection strings, but can be used by user code as well.
Registering user-defined dependencies
Apps can freely register their own specific dependencies as well. This is typically done in the constructor or the
Start() method (either option is fine).
For example, suppose multiple parts of an app use a specific service. The service should first be registered with the container inside the
1 2 3 4 5 6 7 8 9
A component could then request an instance of this service simply by adding a constructor argument for it.
1 2 3 4 5 6 7
For dependencies that are expensive to create, it's best to create them lazily, so they are only created when they are first needed. Instead of creating the instance and registering it with the container using the
RegisterInstance method, it's preferable to use the
It is important to be mindful of the lifetime of the created objects. When registering a type with the Unity container, you can specify if the container should create a single instance of a particular service (
ContainerControllerLifetimeManager) which it will return every time it is requested, or if it should return a new instance of the service every time it is requested (
TransientLifetimeManager, default if no lifetime manager is specified).
About Unity IOC
This page provided a minimal introduction to using the Unity IOC container. While the Unity IOC container is fairly simple to use, a detailed description of it is outside the scope of this documentation. To learn more about the Unity IOC container, visit the Unity container documentation page.