DS.Foundation
8.4.1
dotnet add package DS.Foundation --version 8.4.1
NuGet\Install-Package DS.Foundation -Version 8.4.1
<PackageReference Include="DS.Foundation" Version="8.4.1" />
<PackageVersion Include="DS.Foundation" Version="8.4.1" />
<PackageReference Include="DS.Foundation" />
paket add DS.Foundation --version 8.4.1
#r "nuget: DS.Foundation, 8.4.1"
#:package DS.Foundation@8.4.1
#addin nuget:?package=DS.Foundation&version=8.4.1
#tool nuget:?package=DS.Foundation&version=8.4.1
DS.Foundation
Núcleo de las librerías DS.Foundation: clases de opciones compartidas (SystemOptions, ApplicationOptions, integración de datos), registro de servicios por escaneo de ensamblados, mensajes de usuario y eventos de aplicación, una base para procesos de integración de datos (extracción, transformación y carga) y utilidades (colas, rangos de fechas, conversión de textos, recursos embebidos, ejecución de comandos).
Úselo como dependencia común de las aplicaciones y de los demás paquetes DS.Foundation.*. Los paquetes de dominio (Data, WebApi, Authentication, etc.) lo referencian.
- Target framework:
netstandard2.0. - Dependencias:
Microsoft.Extensions.Configuration,Microsoft.Extensions.Logging.AbstractionsyMicrosoft.Extensions.Options.
Instalación
<PackageReference Include="DS.Foundation" Version="8.4.1" />
Registro
AddFoundationServices y AddApplicationServices recorren los ensamblados de los objetos IServiceRepository recibidos y registran como scoped cada clase que implementa IFoundationService o IApplicationService, respectivamente. Cada clase se registra por su tipo concreto, no por sus interfaces.
using DS.Foundation.Services;
using DS.Foundation.Services.Extensions;
builder.Services.AddFoundationServices(new IServiceRepository[]
{
new DS.Foundation.Services.ServiceRepository(), // DsCryptographyService, SystemDateTimeProviderService
new DS.Foundation.Authentication.Services.ServiceRepository(), // si usa DS.Foundation.Authentication
});
// Servicios propios: cualquier clase de su ensamblado que implemente IApplicationService.
builder.Services.AddApplicationServices(new IServiceRepository[] { new MiApp.ServiceRepository() });
Para que su ensamblado sea escaneado, declare una clase vacía que implemente IServiceRepository:
namespace MiApp
{
public class ServiceRepository : DS.Foundation.Services.IServiceRepository { }
}
Las clases de opciones (SystemOptions, ApplicationOptions, etc.) no se registran solas: la aplicación las enlaza con el patrón Options.
builder.Services.Configure<SystemOptions>(builder.Configuration.GetSection("System"));
// Obligatorio si la aplicación resuelve DsCryptographyService (ver Configuración).
builder.Services.Configure<CryptographyOptions>(builder.Configuration.GetSection(CryptographyOptions.SectionName));
Configuración
SystemOptions
| Propiedad | Tipo | Valor por defecto | Obligatoria |
|---|---|---|---|
Code |
string |
"" |
Sí, si usa CookieName |
Name |
string |
"" |
No |
Environment |
string |
"DEFAULT" |
No |
Scheduler |
SchedulerOptions (Enable: bool) |
instancia vacía | No |
Application |
ApplicationOptions |
instancia vacía | No |
Services |
Dictionary<string, ServiceOptions> (Code, Name, BaseUrl) |
vacío | No |
CookieName |
string (solo lectura) |
Code + "-USR-SID" |
- |
ApplicationOptions
| Propiedad | Tipo | Valor por defecto | Obligatoria |
|---|---|---|---|
Code |
string |
"" |
No |
Name |
string |
"" |
No |
Settings |
List<SettingOptions> (Key, Value) |
vacía | No |
DataStore |
DataStoreOptions |
instancia vacía | No |
DataStoreOptions (integración de datos)
| Propiedad | Tipo | Valor por defecto | Obligatoria |
|---|---|---|---|
Type |
DataStoreTypeEnum (Database, FileSystem, SecureFtp, RestApi, SoapWebService, DataLaneContext) |
Database |
Sí |
Host |
string |
"" |
Según el tipo |
Port |
int |
0 |
Según el tipo |
Path |
string |
"" |
Según el tipo (en bases de datos, el nombre de la base) |
IsPathDirectory |
bool |
false |
No |
Filter |
string |
"" |
No |
Timeout |
int (segundos) |
30 |
No |
Security |
DataSecurityOptions (usuario, contraseña, API key, client id/secret, Workspaces) |
instancia vacía | Según el tipo |
DataLaneOptions → DataTaskOptions → DataStepOptions describen la jerarquía carril → tarea → paso. Cada nivel tiene Code, Name, Type, Order y Enabled. Cada paso tiene Source y Destination (DataStoreOptions).
SystemDateTimeProviderService
Lee la clave System:Date de IConfiguration en el constructor.
| Clave | Valores | Obligatoria |
|---|---|---|
System:Date |
"TODAY" o "HOY": GetNow() devuelve DateTime.Now. Una fecha yyyy-MM-dd: GetNow() devuelve esa fecha con la hora actual (útil para pruebas). |
No: si falta o está vacía, se usa la fecha actual. |
GetNow() devuelve hora local del servidor (DateTime.Kind = Local), no UTC.
DsCryptographyService
Cifra y descifra textos con AES (Rijndael, clave de 256 bits) y calcula hashes SHA1. Recibe IOptions<CryptographyOptions> y no lee IConfiguration.
La aplicación que usa DS.Foundation debe cargar CryptographyOptions. No hay valores por defecto: si falta Key o InitializationVector, o alguno es inválido, el constructor lanza InvalidOperationException (el mensaje indica la propiedad) y el servicio no se puede resolver, ni siquiera para CreateHash.
| Propiedad | Valor | Obligatoria |
|---|---|---|
CryptographyOptions.Key |
32 bytes en hexadecimal (64 caracteres) | Sí |
CryptographyOptions.InitializationVector |
16 bytes en hexadecimal (32 caracteres) | Sí |
Desde una sección de configuración (CryptographyOptions.SectionName es "System:Cryptography"; puede usar otra):
using DS.Foundation.Configuration.Options;
builder.Services.Configure<CryptographyOptions>(
builder.Configuration.GetSection(CryptographyOptions.SectionName));
O con valores que la aplicación obtiene de otra fuente (por ejemplo, un almacén de secretos):
builder.Services.Configure<CryptographyOptions>(o =>
{
o.Key = secretos.ObtenerClave();
o.InitializationVector = secretos.ObtenerIV();
});
Cargue los valores desde variables de entorno (System__Cryptography__Key, System__Cryptography__InitializationVector) o un almacén de secretos, nunca desde un appsettings.json versionado. Para generarlos: Bytes.ByteArrayToHex(Bytes.GenerateKey()) y Bytes.ByteArrayToHex(Bytes.GenerateIV()) (DS.Foundation.Security.Cryptography.Effortless). Si cambia la clave, lo que se cifró con la anterior ya no se puede descifrar con el servicio.
Migración desde versiones anteriores a 8.4.0: esas versiones cifraban siempre con la clave y el IV por defecto que traía CryptographyOptions en DS.Foundation 8.3.2, y que ya no existen. Para seguir descifrando esos datos, cargue temporalmente esos valores (están en CryptographyOptions.cs de la versión 8.3.2). Son públicos, así que descifre los datos existentes y vuelva a cifrarlos con una clave propia.
Uso
Mensajes de usuario y eventos de aplicación
using DS.Foundation.Security;
using DS.Foundation.UserMessage;
public class MensajeDeUsuario : IUserMessage
{
public string Code { get; set; } = "";
public string Caption { get; set; } = "";
public string Text { get; set; } = "";
public string Type { get; set; } = "";
}
public class MensajesDeVentas : UserMessageSourceBase
{
public MensajesDeVentas()
{
Add(new MensajeDeUsuario { Code = "VTA-001", Caption = "Ventas", Text = "El cliente no existe.", Type = "ERROR" });
}
}
var repositorio = new UserMessageRepository();
repositorio.AddSource(new MensajesDeVentas());
var eventos = new AppEventFactory(repositorio);
AppEvent evento = eventos.Create("usuario", "VTA-001");
AppEvent puede completar un contrato de respuesta con FillWithAppEvent (paquete DS.Foundation.WebApi).
Integración de datos
DataLaneService, DataTaskService y DataStepService son clases base abstractas.
Setupguarda el contexto y, siDataLaneContext.WorkingDirectoryestá vacío, crea un directorio temporal nuevo y lo asigna.DataTaskService.Execute()llama aExtract(),Transform()yLoad()en ese orden. Cada uno toma deoptions.Stepsel único paso conType"E","T"o"L"y lo ejecuta con elDataStepServicecorrespondiente.- La clase derivada debe asignar los campos protegidos
extractor,transformeryloaderantes deExecute().
Utilidades
var cola = new SmartQueue<int>(Enumerable.Range(1, 1000));
IList<int> lote = cola.Dequeue(100); // hasta 100 elementos
using (var cmd = new RunCmd("git", "status"))
{
int exitCode = cmd.Execute(); // espera a que termine; -1 si no pudo iniciarse
string salida = cmd.GetOutput(); // salida estándar; la de errores se descarta
}
DateTimeRange hoy = DateTimeRange.GetTodayDateTimeRange();
DateTimeRange semana = DateTimeRange.GetThisWeekDateTimeRange(); // lunes 00:00:00 a domingo 23:59:59
string base64 = StringCodeConverter.ToBase64("texto");
// Seguro entre hilos; guarda hasta n - 1 elementos y Poner devuelve false si está lleno.
var buffer = new BufferProductorConsumidor<string>(n: 100, k: 10);
buffer.Poner("evento");
string[] loteDeDiez = buffer.Sacar(); // 10 elementos, o vacío si todavía hay menos de 10
string[] resto = buffer.SacarTodos();
Cifrado TripleDES con Cryptography
byte[] key = ...; // 16 o 24 bytes, desde configuración o un almacén de secretos
byte[] iv = ...; // 8 bytes
string cifrado = Cryptography.Encrypt256("texto", key, iv);
string texto = Cryptography.Decrypt256(cifrado, key, iv);
Encrypt256 y Decrypt256 usan TripleDES (bloques de 64 bits, CBC, PKCS7); el "256" del nombre se conserva por compatibilidad. Lanzan ArgumentException si la clave no tiene 16 o 24 bytes o el IV no tiene 8, y CryptographicException si la clave es débil o, al descifrar, no coincide.
Errores frecuentes
| Síntoma | Causa | Solución |
|---|---|---|
KeyNotFoundException en UserMessageRepository.Get o AppEventFactory.Create |
Ningún origen registrado contiene el código | Registrar el origen con AddSource o corregir el código |
InvalidOperationException en DataTaskService.Execute |
Falta un paso "E", "T" o "L", o hay más de uno del mismo tipo |
Definir exactamente un paso de cada tipo |
NullReferenceException en DataTaskService.Execute |
La clase derivada no asignó extractor, transformer o loader |
Asignarlos en el constructor o en Setup |
| Un servicio no se resuelve por su interfaz | AddFoundationServices/AddApplicationServices registran el tipo concreto |
Inyectar la clase concreta o registrar la interfaz manualmente |
NotSupportedException en Cryptography.Encrypt256(string)/Decrypt256(string) |
Las versiones sin clave están obsoletas y no funcionan | Usar Encrypt256(text, key, iv)/Decrypt256(text, key, iv) |
InvalidOperationException al resolver DsCryptographyService |
La aplicación no cargó CryptographyOptions.Key o InitializationVector, o el valor no es hexadecimal o no tiene 32/16 bytes. El mensaje indica la propiedad |
Cargar ambos valores con services.Configure<CryptographyOptions>(...) (ver DsCryptographyService) |
CryptographicException en DsCryptographyService.Decrypt |
El texto se cifró con otra clave o IV (por ejemplo, con los valores por defecto de una versión anterior a 8.4.0) | Descifrar con la clave original y volver a cifrar con la nueva |
Qué no hacer
- No cargar en
CryptographyOptionsla clave y el IV de versiones anteriores a 8.4.0 salvo para migrar datos antiguos: son públicos.DsCryptographyService.CreateHashusa SHA1, y los helpers MD5 deCryptographytampoco sirven para contraseñas. - No escribir en el código la clave ni el IV de
Cryptography.Encrypt256/Decrypt256. - No confiar en
AddMapsterTypeAdapters: no realiza ningún registro (se conserva por compatibilidad). - Los métodos de
DateTimeRangeusanDateTime.Now(hora local del servidor). - No guardar en
SystemOptionsni enDataSecurityOptionssecretos enappsettings.jsonversionado: use variables de entorno o un almacén de secretos.
Cambios
Ver CHANGELOG.md.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.Extensions.Configuration (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.3)
- Microsoft.Extensions.Options (>= 8.0.2)
NuGet packages (5)
Showing the top 5 NuGet packages that depend on DS.Foundation:
| Package | Downloads |
|---|---|
|
DS.Foundation.WebApi
Cliente HTTP, consumidores Web API, contratos y logging. |
|
|
DS.Foundation.Authentication
JWT, tokens y validación de API key (sin integración ASP.NET Core). |
|
|
DS.Foundation.Data
Acceso a datos, DbManagers multi-motor y FluentMigrator. |
|
|
DS.Foundation.NHibernate
Package Description |
|
|
DS.Foundation.Data.Tactica
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 8.4.1 | 364 | 10/19/2026 |
| 8.4.0 | 308 | 10/19/2026 |
| 8.3.3 | 246 | 10/8/2026 |
| 8.3.2 | 466 | 6/10/2026 |
| 8.3.1 | 551 | 5/31/2026 |
| 8.2.9 | 157 | 5/28/2026 |
| 8.2.8 | 214 | 5/28/2026 |
| 8.2.7 | 178 | 5/18/2026 |
| 8.2.6 | 1,259 | 1/7/2026 |
| 8.2.5 | 457 | 10/5/2025 |
| 8.2.4 | 324 | 10/3/2025 |
| 8.2.3 | 410 | 9/19/2025 |
| 8.2.2 | 587 | 8/19/2025 |
| 8.2.1 | 809 | 6/25/2025 |
| 8.2.0 | 762 | 6/22/2025 |
| 8.1.30 | 368 | 9/19/2025 |
| 8.1.29 | 249 | 7/18/2025 |
| 8.1.28 | 385 | 7/3/2025 |
| 8.1.27 | 489 | 5/25/2025 |
| 8.1.26 | 684 | 4/15/2025 |