Skip to main content

Dependency Injection

Nidus includes a purpose-built DI engine (TCoreInject, TNidusInject) that manages the entire application object graph.

How it works​

When the Nidus.Inject unit is first loaded (e.g. via its initialization section in the .dpr), it creates a global pointer GNidusInject: PNidusInject and bootstraps TCoreInject. TCoreInject registers all framework internals:

InternalRegistration
TTracker, TRouteManagerSingletonLazy
TModernObjectSingleton
TBindService, TRouteService, TModuleServiceFactory
TBindProvider, TModuleProvider, TRouteProvider, TRouteParseFactory
TNidusSingletonLazy + wired via IncludeModuleService / IncludeBindService / IncludeRouteParser

Registering your own providers​

Use TModule.Configure to declare providers for a module scope:

procedure TOrderModule.Configure(const ABuilder: IModuleBuilder);
begin
ABuilder
// Singleton: one TOrderService instance for the app lifetime
.AddProvider(TBind<TOrderService>.Singleton)
// Factory: new TOrderValidator on each injection
.AddProvider(TBind<TOrderValidator>.Factory)
// Interface-backed singleton
.AddProvider(TBind<TMemoryOrderRepo>.SingletonInterface<IOrderRepository>)
.Export(TOrderService);
end;

Resolving dependencies​

// Resolve by class
var LOrderSvc := GetNidus.Get<TOrderService>;

// Resolve by interface
var IRepo := GetNidus.GetInterface<IOrderRepository>;

// Resolve with a tag (when multiple bindings exist for the same type)
var LSvc := GetNidus.Get<TOrderService>('v2');

Source: TNidus.Get<T> and TNidus.GetInterface<I> delegate to TBindService.GetBind<T> / TBindService.GetBindInterface<I>, returning a TResultPair<T, Exception>. Errors are re-raised automatically.

Lifecycle management​

Object lifetimes are controlled by the bind strategy:

  • Singleton — created during Start, destroyed during Finalize.
  • SingletonLazy — created on first resolution, destroyed during Finalize.
  • Factory — created on every Get<T> call; caller owns the instance.

Finalization​

GetNidus.Finalize;

Finalize frees FAppModule and calls GNidusInject^.ExtractInject<TNidusInject>(C_NIDUS) to clean up the internal container. The finalization section of Nidus.Inject also calls Finalize automatically when the unit is unloaded, so double-finalization is safe.