Dependency Injection

DependencyInjection

🌍 Language: English | Español

IoC/DI container for Delphi with a fluent API inspired by .NET’s Microsoft.Extensions.DependencyInjection. Register services once, resolve them anywhere — with Singleton, Scoped, and Transient lifetimes.

Delphi 12+ License


Why use this?

  • 🔌 Familiar API — Same AddSingleton / AddTransient / AddScoped pattern as .NET
  • 🎯 Generic & type-safe — Compile-time verification via generics, no string tokens
  • Three lifetime modes — Singleton, Scoped (per scope), Transient (new every time)
  • 🏭 Flexible registration — By class, by factory lambda, or by existing instance
  • 💤 Lazy resolutionLazy.From<T>() defers creation until first use
  • 🦆 Duck TypingTDuckDecorator<T> wraps any object implementing the same interface shape
  • 📦 Zero external deps — Depends only on DependencyInjection.Abstractions

Quick Start

uses
  Daf.Extensions.DependencyInjection,
  Daf.DependencyInjection;

var
  Services: IServiceCollection;
  Provider: IServiceProvider;
begin
  Services := TServiceCollection.Create;

  // Register
  Services.AddSingleton<IMyService, TMyService>;

  // Build the container (freezes the collection)
  Provider := Services.BuildServiceProvider;

  // Resolve
  var Svc := Provider.GetRequiredService<IMyService>;
  Svc.DoWork;

  // Always shut down when done
  Provider.ShutDown;
end;

Registration overloads

// By implementation class
Services.AddSingleton<IMyService, TMyServiceImpl>;

// By factory lambda (full control)
Services.AddTransient<IMyService>(
  function(P: IServiceProvider): IMyService
  begin
    Result := TMyServiceImpl.Create(P.GetRequiredService<IConfig>);
  end);

// By existing instance (Singleton only)
Services.AddSingleton<IMyService>(MyExistingInstance);

Scopes

var Scope := Provider.CreateScope;
try
  var Svc := Scope.ServiceProvider.GetRequiredService<IScopedService>;
  // Scoped instances are unique within this scope
finally
  Scope := nil; // triggers Shutdown + managed cleanup
end;

AppModule pattern

Organise registrations by module:

type
  TMyModule = class(TInterfacedObject, IAppModule)
    procedure AddServices(const Services: IServiceCollection);
  end;

procedure TMyModule.AddServices(const Services: IServiceCollection);
begin
  Services.AddSingleton<IMyService, TMyService>;
  Services.AddTransient<IOther, TOtherImpl>;
end;

See DependencyInjection.Abstractions for the IAppModule interface and all core contracts.


Documentation

  • 📖 Usage Guide — lifetimes, scopes, Lazy, DuckDecorator, integration with Hosting

Abstractions

DependencyInjection.Abstractions

🌍 Language: English | Español

Core contracts (interfaces and types) for the DAF Dependency Injection system. This module contains no implementation — it defines the shape that consumers depend on and that DependencyInjection implements.

Delphi 12+ License


What’s in this module

Unit Contents
Daf.Extensions.DependencyInjection IServiceCollection, IServiceProvider, IServiceScope, lifetimes, Factory, TDuckDecorator<T>, Lazy
Daf.AppModule IAppModule — module registration pattern
Daf.DependencyInjection.ActivatorUtilities Helpers to construct objects via RTTI with DI-resolved arguments

Key types

IServiceCollection

Fluent builder for registering services before the container is built.

Services
  .AddSingleton<ICache, TMemoryCache>
  .AddTransient<IRepo, TRepoImpl>
  .AddScoped<IUoW, TDbUoW>;

var Provider := Services.BuildServiceProvider;

IServiceProvider

The resolved container. Use it to obtain service instances.

var Svc := Provider.GetRequiredService<IMyService>;
var Opt: IMyService;
if Provider.TryGet<IMyService>(Opt) then ...
var All := Provider.GetServices<IPlugin>;

TServiceLifeTime

type TServiceLifeTime = (Singleton, Scoped, Transient);

IServiceScope

A lifetime boundary. Scoped services are shared within a scope and released when the scope ends.

var Scope := Provider.CreateScope;
var Svc := Scope.ServiceProvider.GetRequiredService<IScopedService>;
Scope := nil; // releases scoped instances

IAppModule

Convention for grouping service registrations:

type
  IAppModule = interface(IInvokable)
    procedure AddServices(const Services: IServiceCollection);
  end;

Factory

Helper to build TServiceFactory from a class or instance:

Services.Add(TypeInfo(IMyService), Singleton, Factory.From(TypeInfo(IMyService), TMyImpl));

TDuckDecorator<T>

Base class for wrapping a service with pre/post-call logic without inheritance. Override BeforeCall / AfterCall.

Lazy

Result := Lazy.From<IHeavy>(Provider, function(P): IHeavy begin Result := THeavy.Create end);

Dependency

This module has no dependencies on other DAF modules. It depends only on the Delphi RTL (System.Rtti, System.Generics.Collections).

The implementation is in DependencyInjection.