ITLab.Template.DevPack.Abstractions
Defines foundational contracts consumed by infrastructure and application layers.
Componentes
| Tipo | Nome | Responsabilidade |
|---|---|---|
| Interface | IAppOptions | Marks bindable options and declares the configuration section path |
| Interface | ICacheService | Cache contract for get/create, set, try-get, remove and diagnostics |
| Interface | IDateTimeProvider | Time normalization contract for UTC/system/user-local values |
| Sealed Class | UtcDateTimeProvider | Default IDateTimeProvider — every value resolves to UTC; singleton |
| Sealed Class | LocalDateTimeProvider | IDateTimeProvider that converts to ICurrentUser.LocalTimeZone (IANA), fallback UTC; scoped |
| Static Class | DateTimeProviderServiceCollectionExtensions | DI helpers AddDevPackUtcDateTimeProvider() / AddDevPackLocalDateTimeProvider() |
| Interface | IServiceProviderAccessor | Provides controlled access to the active service provider |
| Interface | ISecretProtector | Symmetric encrypt/decrypt of secret strings for storage at rest |
| Sealed Class | DataProtectionSecretProtector | Default ISecretProtector over ASP.NET Core Data Protection |
| Static Class | SecretProtectorServiceCollectionExtensions | DI helper AddDevPackSecretProtector() |
Como usar
// App options contract used by strongly typed configuration.
public sealed class MyFeatureOptions : IAppOptions
{
public static string ConfigSectionPath => "MyFeature";
public bool Enabled { get; init; }
}
// Cache usage with safe fallback factory.
var customer = await cacheService.GetOrCreateAsync(
cacheKey: $"customer:{id}",
factory: () => repository.LoadCustomerAsync(id),
absoluteExpiration: TimeSpan.FromMinutes(10));
DateTimeProvider — escolha por host
| Host | Implementação | Lifetime | Por quê |
|---|---|---|---|
| Web API com user context | LocalDateTimeProvider | Scoped | UserLocal* resolve via ICurrentUser.LocalTimeZone |
| Worker / batch / console | UtcDateTimeProvider | Singleton | Sem user context — degrade para UTC, sem custo de scope |
| Fallback / testes | UtcDateTimeProvider | Singleton | Determinístico, sem dependências scoped |
Registro
// Pré-requisito para ambos:
services.AddSingleton(TimeProvider.System);
// Web API:
services.AddDevPackLocalDateTimeProvider(); // Scoped
// requer ICurrentUser registrado (do DevPack Identity).
// Worker:
services.AddDevPackUtcDateTimeProvider(); // Singleton
Comportamento de timezone
LocalDateTimeProvider resolve ICurrentUser.LocalTimeZone (IANA) via
TimeZoneInfo.TryFindSystemTimeZoneById. Em .NET 8+ no Windows, identificadores
IANA são aceitos diretamente — o runtime aplica mapeamento IANA↔Windows
internamente. Não é necessário tratamento por plataforma.
Fallback silencioso para UTC quando LocalTimeZone é null, vazio ou
desconhecido ao runtime — LocalDateTimeProvider nunca lança exceção.
// Cenário: usuário em São Paulo (IANA "America/Sao_Paulo"), UTC = 2026-05-01 15:00.
// provider.UserLocalTimeOffset = 2026-05-01 12:00 -03:00
// provider.UserTimeZone = TimeZoneInfo for America/Sao_Paulo
// provider.UserLocalTimeOffsetSpan = -03:00:00
// Cenário: usuário sem LocalTimeZone definido (LocalTimeZone == null).
// provider.UserLocalTimeOffset = 2026-05-01 15:00 +00:00 (UTC)
// provider.UserTimeZone = TimeZoneInfo.Utc
// provider.UserLocalTimeOffsetSpan = TimeSpan.Zero
Secret protection
ISecretProtector encrypts secret strings (client secrets, bind passwords) for storage at rest;
DataProtectionSecretProtector implements it over ASP.NET Core Data Protection. Register with
services.AddDevPackSecretProtector() and consume it from a per-tenant settings store (see
../Identity/Settings/README.md).
services.AddDevPackSecretProtector(); // adds Data Protection + ISecretProtector
var token = protector.Protect(clientSecret); // store this
var clientSecret = protector.Unprotect(token); // read back
Production: configure a persistent Data Protection key ring (Azure Blob/Key Vault, file share, …). The in-memory default loses keys on restart, making previously protected secrets undecryptable.
O que não fazer
- Do not use
IServiceProviderAccessoras a generic service locator in domain code. - Do not log the plaintext or the protected token produced by
ISecretProtector. - Do not rely on the in-memory Data Protection key ring in production — protected secrets won't survive a restart.
- Do not store mutable runtime state in
IAppOptionsimplementations. - Do not rely on cache as the source of truth for business consistency.
- Do not register
LocalDateTimeProvideras Singleton — depends on scopedICurrentUser. - Do not throw or log error when timezone is invalid —
LocalDateTimeProviderfalls back to UTC by design.
Extensão pelo produto
- Products can implement custom
IDateTimeProvider(e.g. multi-tenant timezone strategies) and replace the registration. - Products can replace
ICacheServicewith distributed cache implementations while keeping contract behavior.