ο»Ώ# Hosting
π Language: English | EspaΓ±ol
Generic host for Delphi applications inspired by .NETβs Microsoft.Extensions.Hosting. Composes services, configuration, hosted services (background workers) and the application lifetime into a single, managed runtime.
Why use this?
- ποΈ Unified startup β One place for DI, configuration, logging and background services
- π Environment-aware β Built-in
Development/Staging/Production/Testingmodes - βοΈ Layered configuration β Host config, then app config, with environment variable overrides
- π Hosted services β Register
IHostedServiceimplementations that start and stop with the host - π Graceful shutdown β
IHostApplicationLifetimesignalsStarted,Stopping,Stopped - π DI integration β
IServiceProvideris the backbone; all services registered viaIServiceCollection
Quick Start
uses
Daf.Hosting,
Daf.Extensions.Hosting,
Daf.Extensions.DependencyInjection;
var Builder := THost.CreateBuilder;
Builder.Services.AddSingleton<IMyService, TMyService>;
Builder.Services.AddHostedService<TMyWorker>; // IHostedService
var Host := Builder.Build;
try
Host.Start;
Host.WaitForShutdown;
finally
StopAndNil(Host);
end;IHostedService
Any class registered as a hosted service must implement IHostedService:
type
TMyWorker = class(TInterfacedObject, IHostedService)
public
procedure Start;
procedure Stop;
end;
procedure TMyWorker.Start;
begin
// launched when Host.Start is called
end;
procedure TMyWorker.Stop;
begin
// called on graceful shutdown
end;Register it:
Services.AddHostedService<TMyWorker>;
// equivalent to:
Services.AddSingleton<IHostedService, TMyWorker>;If a Stop raises, the rest of the shutdown still runs: the other services stop and the container is shut down. Host.Stop raises what failed at the end β the exception itself, or an EAggregateException holding every failure when several steps failed.
Environment
The environment is read from the environment host setting β --environment Staging on the command line, or the DAF_ENVIRONMENT variable β and defaults to Production:
| Value | IsDevelopment | IsStaging | IsProduction | IsTesting |
|---|---|---|---|---|
Development |
β | |||
Staging |
β | |||
Production |
β | |||
Testing |
β |
The questions compare the name without regard to case. Any other name is one more environment: QA loads appsettings.QA.json, and the four questions answer False.
var Env := Host.Services.GetRequiredService<IHostEnvironment>;
if Env.IsDevelopment then
WriteLn('Running in development mode');
WriteLn(Env.ContentRootPath);Host settings read at startup, as an argument or as a variable β the argument wins:
| Key | Variable | Default | Purpose |
|---|---|---|---|
environment |
DAF_ENVIRONMENT |
Production |
Environment name |
applicationName |
DAF_APPLICATIONNAME |
Executable name | Application name |
contentRoot |
DAF_CONTENTROOT |
Current directory | Content root directory |
When the current directory is the system one, as for a Windows service, the content root is the folder of the executable instead. Env.BinPath is always that folder.
Container validation
In the Development environment the host builds the container with ValidateOnBuild and ValidateScopes: a registration whose dependencies cannot be satisfied, or a Singleton that captures a Scoped, stops Build with every finding listed. In any other environment the container is built without validating.
ServiceProviderOptions on the builder reads the options Build will use, and assigning it fixes them whatever the environment:
Builder.ServiceProviderOptions := TServiceProviderOptions.None; // never validate
Builder.ServiceProviderOptions := TServiceProviderOptions.Create(True, True); // always validateThe validation reaches the registrations made by class; a factory registration is left out. With ValidateScopes, a Scoped service asked of the root provider, or through the provider a Singleton received, is also rejected when it is resolved. Hosted services and startup tasks are Singletons, so what they need from a Scoped they resolve from a scope of their own, through an IServiceScopeFactory taken by constructor.
Application Lifetime
var Lifetime := Host.Services.GetRequiredService<IHostApplicationLifetime>;
Lifetime.ApplicationStarted.Register(procedure begin
WriteLn('App started');
end);
Lifetime.ApplicationStopping.Register(procedure begin
WriteLn('Stopping...');
end);
// Request a graceful stop from anywhere
Lifetime.StopApplication;Using the application family
For a program with a main line, each variant of the application family β Daf.Cli, Daf.Web, Daf.VCL or Daf.FMX β wraps this pipeline and adds Run. The builder is usable the moment it is created: Services, Configuration and Environment answer as soon as they are read, so registrations happen where they are written. Build returns the application, and its Run gives the exit code.
uses Daf.Cli, Daf.CommandLine, Daf.Configuration.CommandLine;
var B := TCliApplication.CreateBuilder(CommandLineConfig.ProcessArgs);
B.Services.AddSingleton<IMyService, TMyService>;
B.Services.AddHostedService<TMyWorker>;
ExitCode := B.Build.Run;See The application family for which entry point is yours and what the layer adds over the host.
Documentation
- π Usage Guide β configuration pipeline, scoped services, hosted services, lifetime hooks
- π The application family β which entry point is yours, what the layer adds over the host, and what it is in .NET terms
- π Startup composition β
IStartupTaskvsIHostedService, and the two phases of startup - π HostQuickStart β compose, build, start and stop, with no application variant around it
- π StartupReport β where the startup record goes, and what a startup that does not complete shows
- π HostLifetime β the three lifetime notifications, and a copy of the
IHostreleased inApplicationStopped - π ConsoleSample β configuration and the options pattern in one console program
- π HostedService β background workers with
AddHostedService - π PackageInit β an
IStartupTaskcontributed from a package, without the.dprnaming it
Abstractions
Hosting.Abstractions
π Language: English | EspaΓ±ol
Core contracts for the DAF hosting system. This module defines interfaces and types only β no implementation. Reference it when writing hosted services, environment-aware components, or generic host extensions without depending on the concrete host.
Whatβs in this module
All types live in Daf.Extensions.Hosting.
Core interfaces
| Interface | Role |
|---|---|
IHostApplicationBuilder |
The shared contract of the application family: Services, Configuration, Environment, Logging, Properties, ServiceProviderOptions |
IStartupTask |
Runs once at startup with the provider already built: Run, and nothing to stop |
IHost |
The running host: Services, Start, Stop, WaitForShutdown |
IHostedService |
Background service contract: Start / Stop |
IHostEnvironment |
Runtime environment: name, app name, paths, IsDevelopment, β¦ |
IHostBuilderContext |
Startup context, registered in the container: Environment, Configuration, Properties |
IHostApplicationLifetime |
Lifetime signals: ApplicationStarted, ApplicationStopping, ApplicationStopped, StopApplication |
Environment constants
TEnvironments.Development // 'Development'
TEnvironments.Staging // 'Staging'
TEnvironments.Production // 'Production'
TEnvironments.Testing // 'Testing'Host settings
The keys of the host configuration that IHostEnvironment is derived from, named as in .NETβs HostDefaults. As environment variables they carry the DAF_ prefix: DAF_ENVIRONMENT.
THostDefaults.EnvironmentKey // 'environment'
THostDefaults.ApplicationKey // 'applicationName'
THostDefaults.ContentRootKey // 'contentRoot'Helper
IServiceCollectionHelper adds AddHostedService<T> and AddStartupTask<T> directly on IServiceCollection:
Services.AddHostedService<TMyWorker>; // = AddSingleton<IHostedService, TMyWorker>
Services.AddStartupTask<TMySeeder>; // = AddSingleton<IStartupTask, TMySeeder>Only one record helper per type is in scope in Delphi, so a unit bringing a second one for IServiceCollection hides this one. The Hosting class facade is the way through, and it takes the implementation as a metaclass: Hosting.AddHostedService(Services, TMyWorker).
Dependencies
Daf.Extensions.DependencyInjection(DependencyInjection.Abstractions)Daf.Extensions.Configuration(Configuration.Abstractions)Daf.Extensions.Logging(Logging.Abstractions) β for theILoggingBuilderthe family contract exposes as a propertyDaf.Commons
The implementation is in Hosting.