Dependency injection
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.
Resolving dependencies
Dependencies can be resolved in three ways:
- Constructor injection (preferred)
- Property injection (using the
[Dependency]
attribute) - Explicitly, by using the
Container.Resolve<T>()
method
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 |
|
Built-in dependencies
The container instance itself is created by the App
base class and is exposed via the Container
property.
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 ExcelApplication
instance.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 theproject.config
file.ConnectionStringsDictionary
- allows strongly typed access to theConnectionStrings
section of theproject.config
file.Tracker
- aJot.Tracker
instance 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 App
class:
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 |
|
Expensive objects
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 RegisterType
and RegisterFactory
methods.
Registration lifetimes
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.