# Hosting
🌍 Idioma: English | Español
Host genérico para aplicaciones Delphi inspirado en Microsoft.Extensions.Hosting de .NET. Compone servicios, configuración, hosted services (workers en segundo plano) y el ciclo de vida de la aplicación en un runtime único y gestionado.
¿Por qué usarlo?
- 🏗️ Arranque unificado — Un único lugar para DI, configuración, logging y servicios en segundo plano
- 🌍 Consciente del entorno — Modos
Development/Staging/Production/Testingintegrados - ⚙️ Configuración por capas — Host config, luego app config, con sobreescritura por variables de entorno
- 🔄 Hosted services — Registra implementaciones de
IHostedServiceque arrancan y paran con el host - 🛑 Apagado elegante —
IHostApplicationLifetimeseñalizaStarted,Stopping,Stopped - 🔌 Integración con DI —
IServiceProvideres la columna vertebral; todos los servicios se registran viaIServiceCollection
Inicio rápido
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
Cualquier clase registrada como hosted service debe implementar IHostedService:
type
TMyWorker = class(TInterfacedObject, IHostedService)
public
procedure Start;
procedure Stop;
end;
procedure TMyWorker.Start;
begin
// se lanza cuando se llama a Host.Start
end;
procedure TMyWorker.Stop;
begin
// se llama en el apagado elegante
end;Registra el worker:
Services.AddHostedService<TMyWorker>;
// equivalente a:
Services.AddSingleton<IHostedService, TMyWorker>;Si un Stop lanza, el resto del apagado se ejecuta igual: los demás servicios paran y el contenedor se apaga. Host.Stop lanza lo que falló al final: la misma excepción, o una EAggregateException con todos los fallos dentro si fallaron varios pasos.
Entorno
El entorno se lee del ajuste de host environment —--environment Staging en la línea de comandos, o la variable DAF_ENVIRONMENT— y por defecto es Production:
| Valor | IsDevelopment | IsStaging | IsProduction | IsTesting |
|---|---|---|---|---|
Development |
✅ | |||
Staging |
✅ | |||
Production |
✅ | |||
Testing |
✅ |
Las preguntas comparan el nombre sin distinguir mayúsculas. Cualquier otro nombre es un entorno más: QA carga appsettings.QA.json, y las cuatro preguntas responden False.
var Env := Host.Services.GetRequiredService<IHostEnvironment>;
if Env.IsDevelopment then
WriteLn('Modo desarrollo activo');
WriteLn(Env.ContentRootPath);Ajustes de host leídos al arrancar, como argumento o como variable —gana el argumento—:
| Clave | Variable | Por defecto | Propósito |
|---|---|---|---|
environment |
DAF_ENVIRONMENT |
Production |
Nombre del entorno |
applicationName |
DAF_APPLICATIONNAME |
Nombre del ejecutable | Nombre de la aplicación |
contentRoot |
DAF_CONTENTROOT |
Directorio actual | Directorio raíz de contenido |
Cuando el directorio actual es el del sistema, como en un servicio de Windows, el content root es en su lugar la carpeta del ejecutable. Env.BinPath es siempre esa carpeta.
Validación del contenedor
En el entorno Development el host construye el contenedor con ValidateOnBuild y ValidateScopes: un registro cuyas dependencias no se pueden satisfacer, o un Singleton que captura un Scoped, detiene Build con todos los hallazgos juntos. En cualquier otro entorno el contenedor se construye sin validar.
ServiceProviderOptions en el builder dice las opciones que usará Build, y asignarla las fija sea cual sea el entorno:
Builder.ServiceProviderOptions := TServiceProviderOptions.None; // nunca valida
Builder.ServiceProviderOptions := TServiceProviderOptions.Create(True, True); // valida siempreLa validación alcanza a los registros por clase; un registro por factory queda fuera. Con ValidateScopes, un servicio Scoped pedido al proveedor raíz, o por el proveedor que recibió un Singleton, también se rechaza al resolverlo. Los servicios alojados y las tareas de arranque son Singleton, así que lo que necesiten de un Scoped lo resuelven desde un ámbito propio, con un IServiceScopeFactory recibido por constructor.
Ciclo de vida de la aplicación
var Lifetime := Host.Services.GetRequiredService<IHostApplicationLifetime>;
Lifetime.ApplicationStarted.Register(procedure begin
WriteLn('App arrancada');
end);
Lifetime.ApplicationStopping.Register(procedure begin
WriteLn('Parando...');
end);
// Solicitar parada elegante desde cualquier lugar
Lifetime.StopApplication;Usar la familia de aplicaciones
Para un programa con línea principal, cada variante de la familia de aplicaciones —Daf.Cli, Daf.Web, Daf.VCL o Daf.FMX— envuelve este pipeline y añade Run. El builder es usable en cuanto se crea: Services, Configuration y Environment responden en cuanto se leen, así que los registros ocurren donde están escritos. Build devuelve la aplicación, y su Run da el código de salida.
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;Consulta La familia de aplicaciones para saber cuál es tu punto de entrada y qué añade la capa sobre el host.
Documentación
- 📖 Guía de uso — pipeline de configuración, servicios scoped, hosted services, hooks de ciclo de vida
- 📖 La familia de aplicaciones — cuál es tu punto de entrada, qué añade la capa sobre el host y qué es en términos de .NET
- 📖 Composición del arranque —
IStartupTaskfrente aIHostedService, y las dos fases del arranque - 📁 HostQuickStart — componer, construir, arrancar y parar, sin ninguna variante de aplicación alrededor
- 📁 StartupReport — dónde queda el registro del arranque, y qué enseña un arranque que no llega a completarse
- 📁 HostLifetime — las tres notificaciones del ciclo de vida, y una copia del
IHostque se suelta enApplicationStopped - 📁 ConsoleSample — configuración y el patrón de opciones en un programa de consola
- 📁 HostedService — workers en segundo plano con
AddHostedService - 📁 PackageInit — un
IStartupTaskaportado desde un paquete, sin que el.dprlo nombre
Abstracciones
Hosting.Abstractions
🌍 Idioma: English | Español
Contratos principales del sistema de hosting de DAF. Este módulo define solo interfaces y tipos — sin implementación. Referencíalo cuando escribas hosted services, componentes conscientes del entorno, o extensiones del host genérico sin depender del host concreto.
Qué hay en este módulo
Todos los tipos se encuentran en Daf.Extensions.Hosting.
Interfaces principales
| Interfaz | Rol |
|---|---|
IHostApplicationBuilder |
El contrato común de la familia de aplicaciones: Services, Configuration, Environment, Logging, Properties, ServiceProviderOptions |
IStartupTask |
Se ejecuta una vez al arrancar, con el proveedor ya construido: Run, y nada que parar |
IHost |
El host en ejecución: Services, Start, Stop, WaitForShutdown |
IHostedService |
Contrato de servicio en segundo plano: Start / Stop |
IHostEnvironment |
Entorno de ejecución: nombre, nombre de app, rutas, IsDevelopment, … |
IHostBuilderContext |
Contexto de arranque, registrado en el contenedor: Environment, Configuration, Properties |
IHostApplicationLifetime |
Señales de ciclo de vida: ApplicationStarted, ApplicationStopping, ApplicationStopped, StopApplication |
Constantes de entorno
TEnvironments.Development // 'Development'
TEnvironments.Staging // 'Staging'
TEnvironments.Production // 'Production'
TEnvironments.Testing // 'Testing'Ajustes de host
Las claves de la configuración de host de la que se deriva IHostEnvironment, con los nombres del HostDefaults de .NET. Como variables de entorno llevan el prefijo DAF_: DAF_ENVIRONMENT.
THostDefaults.EnvironmentKey // 'environment'
THostDefaults.ApplicationKey // 'applicationName'
THostDefaults.ContentRootKey // 'contentRoot'Helper
IServiceCollectionHelper añade AddHostedService<T> y AddStartupTask<T> directamente sobre IServiceCollection:
Services.AddHostedService<TMyWorker>; // = AddSingleton<IHostedService, TMyWorker>
Services.AddStartupTask<TMySeeder>; // = AddSingleton<IStartupTask, TMySeeder>En Delphi solo hay un record helper visible por tipo, así que una unit que traiga otro para IServiceCollection esconde este. La salida es la fachada de clase Hosting, que toma la implementación como metaclase: Hosting.AddHostedService(Services, TMyWorker).
Dependencias
Daf.Extensions.DependencyInjection(DependencyInjection.Abstractions)Daf.Extensions.Configuration(Configuration.Abstractions)Daf.Extensions.Logging(Logging.Abstractions) — por elILoggingBuilderque el contrato de la familia expone como propiedadDaf.Commons
La implementación está en Hosting.