-
Notifications
You must be signed in to change notification settings - Fork 1
Application Lifecycle
You have a custom application class, that derives either from BackendFxApplication
or more specifically from BackendFxDbApplication
. The latter implies, that there is a kind of database managed by the application itself. The instance of this class is considered as application wide singleton.
First of all, you have to create the singleton instance of your custom application class. There are some dependencies, that are considered as application wide singletons by design:
-
a
ICompositionRoot
: The starting point for the application to create an injected object graph. You can read more about it in Mark Seemann's excellent article. In the packageBackend.Fx.SimpleInjectorDependencyInjection
you will find a usefulSimpleInjectorCompositionRoot
. However, you are free to bring your own dependency injection framework. -
a
ITenantIdService
: Sometimes, the application needs to know the active tenant ids (e.g. to run a job for all tenants). It will use this instance to retrieve the relevant ids. -
a
IDatabaseBootstrapper
(applies toBackendFxDbApplication
only): as the name says, the responability of this instance is to create and/or migrate the owned database on application start.
You simply boot the application by calling the Boot()
method. This will trigger the following actions:
- The
async
virtual methodOnBoot
is being called. Provide an implementation that ensures whatever is externally required by your application- In case of a
BackendFxDbApplication
this method is already implemented:- The
async
virtual methodOnDatabaseBoot()
is being called. This marks an optional extension point to do something before the database is used. -
WaitForDatabase()
is called. Implement a busy wait for a dependent database system according to your needs. This comes handy, when you are usingdocker-compose
and your database container is not guaranteed to be ready before your application start. -
DatabaseBootstrapper.EnsureDatabaseExistence()
is called. The implementation is expected to ensure the existence of a database containing the schema required by your application to work - The
async
virtual methodOnDatabaseBooted()
is being called. Provide an implementation that ensures whatever is externally required by your application
- The
- In case of a
- the composition root is verified. Note that in case of Simple Injector this marks the switch from construction of the container to usage of the container.
- The
async
virtual methodOnBooted
is being called. Your extension point to do something after booting the application.- this is a good point to call the
RegisterSeedActionForNewlyCreatedTenants()
and/orSeedDataForAllActiveTenants()
method to enable automatic data seeding on startup and/or tenant creation.
- this is a good point to call the
- an internal
ManalResetEvent
is set. Other threads that has been queued to wait for this event by callingWaitForBoot(int timeoutMilliSeconds = int.MaxValue)
are now allowed to proceed.
When the custom application class instance is disposed, all disposable instances are disposed as well:
- the
ICompositionRoot
. This will result in disposal of all singleton instances created by the composition root itself. - the
IDatabaseBootstrapper
(in case ofBackendFxDbApplication
)
You are encouraged to implement Dispose(bool disposing)
in your custom application class, if there are more instances that require a clean shutdown.
As general rule, your application logic should never depend on the composition root. By doing so, you'd create classes that are shamelessly lying about their dependencies. You might have heard of the Service Locator Anti Pattern.
Also don't use the composition root in your
IDatabaseBootstrapper
. Follow the principle "separate use from construction", well imagined as "You don't build and use a hotel at the same time".
The only acceptable components allowed to use the composition root are as follows:
- OLTP entry points, e.g. a middleware in case of ASP.Net Core or a command handler.
- Background jobs, please see
IJobEngine
- handling of integration events, technically the same thing like a background job.