TechsBCN.Platform.Application
0.0.37
dotnet add package TechsBCN.Platform.Application --version 0.0.37
NuGet\Install-Package TechsBCN.Platform.Application -Version 0.0.37
<PackageReference Include="TechsBCN.Platform.Application" Version="0.0.37" />
<PackageVersion Include="TechsBCN.Platform.Application" Version="0.0.37" />
<PackageReference Include="TechsBCN.Platform.Application" />
paket add TechsBCN.Platform.Application --version 0.0.37
#r "nuget: TechsBCN.Platform.Application, 0.0.37"
#:package TechsBCN.Platform.Application@0.0.37
#addin nuget:?package=TechsBCN.Platform.Application&version=0.0.37
#tool nuget:?package=TechsBCN.Platform.Application&version=0.0.37
TechsBCN.Platform.Application
TechsBCN.Platform.Application Es la capa de lógica de aplicación de Platform. Su objetivo es que los proyectos no tengan que implementar desde cero la gestión de usuarios, autenticación, tareas en background ni otras funcionalidades comunes, proporcionando los servicios base, contratos y DTOs que cada proyecto extiende o usa directamente.
Depende únicamente de TechsBCN.Platform.Domain.
Estructura
Application/
├── DTOs/
│ ├── Base.cs
│ ├── BasicItem.cs
│ ├── ListRequest.cs
│ ├── ListResponse.cs
│ ├── TaskMessage.cs
│ ├── User.cs
│ ├── Email/
│ │ ├── EmailData.cs
│ │ └── Attachment.cs
│ └── BlobStorage/
│ └── Blob.cs
├── Exceptions/
│ ├── TechsBcnException.cs
│ ├── EntityNotFoundException.cs
│ ├── DataValidationException.cs
│ └── MissingSetupException.cs
├── Repositories/
│ ├── IBaseRepository.cs
│ ├── IUserRepository.cs
│ ├── ITokenRepository.cs
│ ├── ITaskRepository.cs
│ ├── IEmailRepository.cs
│ ├── IMessagingRepository.cs
│ └── IBlobStorageRepository.cs
├── Services/
│ ├── Interfaces/
│ │ ├── ICrudService.cs
│ │ ├── IUserService.cs
│ │ ├── ISecurityService.cs
│ │ └── ITaskService.cs
│ └── Implementations/
│ ├── CrudService.cs
│ ├── UserService.cs
│ ├── SecurityService.cs
│ ├── TaskService.cs
│ ├── BaseTemplateService.cs
│ └── EmailBaseTemplateService.cs
└── Setup/
└── MapperProfile.cs
DTOs (DTOs/)
Los DTOs son objetos simples cuya función es trasladar datos entre las distintas capas de la aplicación y actúan como contratos para conseguir desacoplamiento entre la capa de dominio, de infraestructura y de API. Se usan únicamente en la capa Application y no contienen lógica de negocio.
Platform define los DTOs base que los proyectos reutilizan directamente.
Base
DTO base del que extienden el resto de DTOs de Platform. El objetivo es que todos los DTOs tengan un Id sin definirlo en cada uno.
public abstract class Base
{
public long Id { get; set; }
}
BasicItem
DTO que representa una referencia mínima a una entidad: solo su identificador y su nombre. El objetivo es proporcionar una estructura común para listas desplegables o referencias a entidades sin exponer todos sus datos. Extiende Base.
public class BasicItem : Base
{
public string? Name { get; set; }
}
ListRequest
DTO que define un contrato estándar de filtrado y paginación. El objetivo es que todos los listados reutilicen la misma estructura de entrada sin duplicarla en cada proyecto.
public class ListRequest
{
public string? Query { get; set; }
public int? Offset { get; set; }
public int? Limit { get; set; }
public string? OrderBy { get; set; }
public bool? OrderAsc { get; set; }
}
ListResponse<T>
DTO que define un contrato estándar de respuesta paginada. El objetivo es que todos los listados devuelvan la misma estructura sin duplicarla en cada proyecto. Solo se crea un DTO de listado propio cuando el flujo de negocio requiere campos adicionales, heredando de ListResponse<T> y añadiendo únicamente las propiedades necesarias para ese flujo.
public class ListResponse<T>
{
public IEnumerable<T>? Items { get; set; }
public int TotalCount { get; set; }
}
TaskMessage<TType>
DTO que permite consultar desde la API si una tarea en background está en curso, ha finalizado o ha fallado. La restricción where TType : Enum obliga a que el parámetro genérico sea siempre un enum, lo que garantiza que los tipos de tarea sean un conjunto cerrado y predecible. Extiende Base.
public class TaskMessage<TType> : Base where TType : Enum
{
public Guid Reference { get; set; }
public TType? Type { get; set; }
public string? Details { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime StartedOn { get; set; }
public DateTime? CompletedOn { get; set; }
public string? Errors { get; set; }
}
User
DTO que define la estructura base de usuario compartida en todos los proyectos para no reimplementarla cada vez. Se usa como contrato de UserService<TUser>.
public class User : Base
{
public string Name { get; set; } = default!;
public string Email { get; set; } = default!;
public string Password { get; set; } = default!;
}
EmailData y Attachment
DTOs que definen los datos necesarios para enviar un email de forma que los servicios funcionen igual independientemente del proveedor de envío configurado. El campo Guid de Attachment se usa como identificador inline: cuando el email tiene imágenes incrustadas en el HTML, se referencia cada imagen con ${guid} en el BodyHtml y se adjunta con ese mismo Guid.
public class EmailData
{
public string Subject { get; set; } = default!;
public string Recipient { get; set; } = default!;
public string Sender { get; set; } = default!;
public string BodyHtml { get; set; } = default!;
public string? Bcc { get; set; }
public IEnumerable<Attachment>? Attachments { get; set; }
}
public class Attachment
{
public string Name { get; set; } = default!;
public byte[] Content { get; set; } = default!;
public Guid Guid { get; set; } = Guid.Empty;
}
Servicios (Services/)
Las interfaces definidas en Services/Interfaces/ (ICrudService, IUserService, ISecurityService, ITaskService) son los contratos que los proyectos referencian para inyección de dependencias. Las implementaciones base están en Services/Implementations/ y se extienden desde el proyecto consumidor.
CrudService<TDTO, TEntity>
CrudService<TDTO, TEntity> es la clase base genérica para operaciones CRUD. Su objetivo es que los servicios del proyecto tengan Create, Read, Update y Delete sin implementarlo desde cero. Usa AutoMapper para el mapeo entre DTO y entidad.
Cuando una entidad sigue un patrón CRUD estándar, los servicios deben reutilizar CrudService. No aplica cuando el servicio implementa un proceso distinto de un CRUD, como autenticación, generación de documentos u orquestación de flujos.
Operaciones que proporciona
Create(TDTO dto)— mapea el DTO a entidad, la persiste y devuelve elIdgenerado.Read(long id)— devuelve el DTO correspondiente alid.Update(TDTO dto)— actualiza la entidad a partir del DTO.Delete(long id)— elimina la entidad.
public class AddressService(
IMapper Mapper,
IAddressRepository AddressRepository
) : CrudService<DTOs.Address, Address>(Mapper, AddressRepository), IAddressService
{
public new long Create(DTOs.Address dto)
{
EnsureValidAlias(dto.Alias);
return base.Create(dto);
}
}
SecurityService<TUser>
SecurityService<TUser> es el servicio base de autenticación y credenciales. Su objetivo es que los proyectos no reimplementen el hashing de contraseñas, la validación de complejidad ni la verificación de credenciales. El proyecto lo extiende añadiendo únicamente los métodos que necesite.
Operaciones que proporciona
CheckCredentials(string email, string password)— verifica credenciales y devuelve el usuario.Hash(string rawData)— genera hash SHA-256 de una contraseña.CheckPasswordComplexity(string password)— valida la complejidad mínima (6 caracteres, mayúsculas, minúsculas y dígito).UpdateCredentials(long userId, string newPassword)— valida complejidad, hashea y persiste la nueva contraseña buscando el usuario por id. LanzaDataValidationExceptionsi la contraseña no cumple la complejidad yEntityNotFoundExceptionsi el usuario no existe.
Requiere un IUserRepository<TUser> que el proyecto implementa extendiendo la interfaz de Platform:
public interface IUserRepository : IUserRepository<User> { }
Patrón de extensión
public interface ISecurityService : ISecurityService<User>
{
void ResetAccount(string token, string newPassword);
}
public class SecurityService(
IUserRepository UserRepository,
ITokenRepository TokenRepository,
IConfiguration Configuration
) : TechsBCN.Platform.Application.Services.Implementations.SecurityService<User>(UserRepository), ISecurityService
{
public void ResetAccount(string token, string newPassword)
{
var tokenEntity = TokenRepository.Get(t => t.Guid == token).FirstOrDefault()
?? throw new EntityNotFoundException($"Token [{token}] does not exist.");
var expirationMinutes = Configuration.GetValue<int?>("Security:TokenExpirationMinutes") ?? 30;
if (tokenEntity.CreatedOn.AddMinutes(expirationMinutes) < DateTime.UtcNow)
throw new DataValidationException($"Token [{token}] is expired.");
base.UpdateCredentials(Convert.ToInt64(tokenEntity.Content), newPassword);
TokenRepository.Delete(tokenEntity);
TokenRepository.Save();
}
}
UserService<TUser>
UserService<TUser> es el servicio CRUD de usuarios. Su objetivo es que los proyectos no reimplementen las validaciones habituales de usuario: formato y unicidad de email, seguridad de contraseña y hash. El proyecto solo lo extiende para añadir la lógica específica que necesite.
Operaciones que proporciona
Create(DTOs.User dto)— valida nombre, email (formato y unicidad) y hace hash de la contraseña antes de persistir.Update(DTOs.User dto)— valida nombre y email; si el email cambia comprueba unicidad; actualiza contraseña solo si se proporciona y cumple complejidad.Read(long id)— heredado deCrudService.Delete(long id)— heredado deCrudService.UpdatePassword(long userId, string newPassword)— actualiza solo la contraseña con hash.
Requiere IUserRepository<TUser> e ISecurityService<TUser> del proyecto.
Patrón de extensión
public interface IUserService : IUserService<User> { }
public class UserService(
IMapper Mapper,
IUserRepository UserRepository,
ISecurityService SecurityService
) : TechsBCN.Platform.Application.Services.Implementations.UserService<User>(Mapper, UserRepository, SecurityService), IUserService
{
}
TaskService<TTaskType>
TaskService<TTaskType> es el servicio de consulta de tareas en background. Su objetivo es que los proyectos puedan exponer el estado de sus tareas sin implementar esta lógica desde cero. Se usa directamente desde Platform o se extiende si el proyecto necesita lógica adicional.
Operaciones que proporciona
Read(Guid reference)— devuelve elTaskMessagede la tarea si existe;nullsi no se encuentra.
Hay que registrar ITaskRepository. Los proyectos que necesiten exponer el estado de tareas deben registrar también el servicio:
services.AddScoped<ITaskRepository<MyTaskType>, TechsBCN.Platform.Infrastructure.Repositories.TaskRepository<MyTaskType>>();
services.AddScoped<ITaskService<MyTaskType>, TechsBCN.Platform.Application.Services.Implementations.TaskService<MyTaskType>>();
Patrón de extensión
public interface ITaskService : TechsBCN.Platform.Application.Services.Interfaces.ITaskService<MyTaskType> { }
public class TaskService(
IMapper Mapper,
ITaskRepository TaskRepository
) : TechsBCN.Platform.Application.Services.Implementations.TaskService<MyTaskType>(Mapper, TaskRepository), ITaskService
{
}
BaseTemplateService
BaseTemplateService es la clase base para servicios de generación de documentos. Su objetivo es que los proyectos no reimplementen la lógica de sustitución de placeholders.
Una plantilla (template) es un fichero HTML con marcadores de posición llamados placeholders — cadenas con el formato ${NombrePropiedad} que se sustituyen por valores reales en tiempo de ejecución. Cada plantilla vive en su propio directorio y contiene un fichero template.html.
Operaciones que proporciona
FillTemplate(string template, object model)— sustituye los placeholders${PropertyName}con los valores de las propiedades públicas del modelo.ResolveTemplatePath(string templateRelativePath)— resuelve la ruta absoluta del directorio de la plantilla.
EmailDataBaseTemplateService
EmailDataBaseTemplateService es la clase base para servicios de generación de emails. Hereda de BaseTemplateService y su objetivo es que los proyectos no reimplementen la incrustación de imágenes ni la orquestación del flujo de generación de emails.
Los datos de cada plantilla se definen en un DTO propio que extiende EmailData, de modo que Subject y Recipient los establece quien llama al servicio, y el mismo objeto sirve de modelo para FillTemplate. Expone GenerateEmailData para orquestar la generación completa: resuelve la ruta, lee el template, aplica el reemplazo e incrusta internamente las imágenes como adjuntos inline.
Patrón de extensión
public class AccountRecoveryEmailData : EmailData
{
public string AccountRecoveryLink { get; set; } = default!;
}
public interface INotificationTemplateService
{
EmailData GetAccountRecoveryEmail(AccountRecoveryEmailData data);
}
public class NotificationTemplateService : EmailDataBaseTemplateService, INotificationTemplateService
{
public EmailData GetAccountRecoveryEmail(AccountRecoveryEmailData data)
{
return GenerateEmailData(data, "Templates/account-recovery");
}
}
Interfaces (Services/Interfaces/)
Su objetivo es separar el contrato de la implementación para que el resto del proyecto dependa de lo que hace un servicio, no de cómo lo hace. Así se puede cambiar o extender la implementación sin modificar el código que la consume. Cuando el servicio gestiona una entidad con operaciones CRUD, la interfaz extiende ICrudService<TDTO, TEntity>. Los métodos adicionales al CRUD se definen directamente en la interfaz del proyecto.
public interface IEntityService : ICrudService<DTOs.Entity, Entity>
{
/// <summary>Returns a paginated list of entities.</summary>
/// <param name="request">Filter and pagination parameters.</param>
EntityListResponse List(ListRequest request);
/// <summary>Enqueues a synchronization task for the entity.</summary>
/// <param name="id">Entity identifier.</param>
/// <returns>Reference of the enqueued task.</returns>
Guid EnqueueSync(long id);
}
Los métodos se documentan con XML docs: <summary>, <param> por cada parámetro y <returns> cuando el método devuelve un valor.
Interfaces de repositorios (Repositories/)
Los repositorios definen los contratos de acceso a datos que implementa la capa Infrastructure. Los servicios dependen de estos contratos, no de implementaciones concretas, lo que permite cambiar la implementación sin afectar a la lógica de negocio.
Los repositorios de entidades heredan de IBaseRepository<TEntity>. Si no necesitan métodos adicionales al contrato base, el cuerpo de la interfaz queda vacío. Los repositorios de integraciones externas definen su propio contrato según las operaciones que expone el sistema externo.
ITokenRepository e IUserRepository<TUser>
Su objetivo es que SecurityService y UserService puedan funcionar en cualquier proyecto sin que cada uno reimplemente el acceso a tokens y usuarios. El proyecto extiende IUserRepository<TUser> con su propio tipo y añade solo las consultas específicas que necesite.
public interface ITokenRepository<TTokenType> : IBaseRepository<Token<TTokenType>>;
public interface IUserRepository<TUser> : IBaseRepository<TUser> where TUser : User;
public interface IUserRepository : IUserRepository<User> { }
IEmailRepository
IEmailRepository es el contrato de envío de email. Su objetivo es que los servicios puedan enviar emails sin saber cómo se envían. La implementación concreta usa Microsoft Graph y se registra con services.AddScoped<IEmailRepository, MicrosoftGraphEmailRepository>().
SendAsync(EmailData emailData)— envía el email. Los adjuntos inline se referencian enBodyHtmlmediante${guid}.
public class MyService(IEmailRepository EmailRepository)
{
public async Task Notify(string recipient)
{
await EmailRepository.SendAsync(new EmailData
{
Subject = "Notification",
Recipient = recipient,
BodyHtml = "<p>Hello</p>"
});
}
}
IBlobStorageRepository
IBlobStorageRepository es el contrato de almacenamiento de ficheros. Su objetivo es que los servicios puedan subir y descargar blobs sin saber dónde se guardan. La implementación concreta usa Azure Blob Storage y se registra con services.AddScoped<IBlobStorageRepository, AzureBlobStorageRepository>().
UploadAsync(Blob blob)— sube el blob y devuelve elGuidasignado.DownloadAsync(Guid guid)— devuelve elBlobcorrespondiente al identificador.
public class MyService(IBlobStorageRepository BlobStorageRepository)
{
public async Task<Guid> Store(byte[] content) =>
await BlobStorageRepository.UploadAsync(new Blob
{
Name = "document.pdf",
Content = content
});
}
Excepciones (Exceptions/)
Platform define la jerarquía base de excepciones para que todos los proyectos comuniquen errores de forma consistente. ErrorMiddleware las mapea automáticamente a los códigos HTTP correspondientes sin necesidad de capturarlas manualmente en los controllers.
TechsBcnException es la clase base de todas las excepciones de Platform. Sus subclases directas son:
EntityNotFoundException— se lanza cuando no se encuentra una entidad por su identificador. Se traduce a HTTP 404.DataValidationException— se lanza cuando los datos de entrada no cumplen las reglas de negocio (email inválido, contraseña débil…). Se traduce a HTTP 400.MissingSetupException— se lanza al arrancar la aplicación cuando falta una clave de configuración obligatoria. Se traduce a HTTP 500.
Los proyectos pueden crear sus propios tipos heredando de estas subclases cuando necesitan distinguir errores específicos:
public class MyEntityNotFoundException(string message) : EntityNotFoundException(message) { }
public class MyValidationException(string message) : DataValidationException(message) { }
El nombre del tipo es lo que ErrorMiddleware devuelve en ApiError.Id, así que heredar de la subclase adecuada determina tanto el código HTTP como el identificador que recibe el cliente para traducir el error. Heredar directamente de TechsBcnException conserva el identificador pero se traduce a HTTP 500.
Setup (Setup/)
MapperProfile
Un perfil de AutoMapper es una clase que declara qué tipo se convierte en qué otro tipo. Al registrarlo, AutoMapper sabe cómo transformar un Task de dominio en un TaskMessage DTO, por ejemplo, sin que el código tenga que hacerlo manualmente.
MapperProfile centraliza los mappings entre entidades de dominio y DTOs de Platform. Los proyectos lo incluyen al configurar AutoMapper para no tener que redefinir los mappings base:
Task—TaskMessageDomain.User—DTOs.User
services.AddAutoMapper(cfg =>
{
cfg.AddProfile(new TechsBCN.Platform.Application.Setup.MapperProfile());
cfg.AddProfile(new MyProject.Application.Setup.MapperProfile());
cfg.AddProfile(new MyProject.Infrastructure.Persistence.Setup.MapperProfile());
mapperConfiguration?.Invoke(cfg);
});
El MapperProfile del proyecto se organiza por #region por entidad. Cuando el DTO y la entidad tienen el mismo nombre se usan aliases de namespace para disambiguar. Los mapeos con lógica personalizada usan ForMember. ReverseMap() siempre y cuando sea bidireccional y no requiera configuración específica distinta en cada sentido.
public class MapperProfile : Profile
{
public MapperProfile()
{
#region Entity
CreateMap<DTOs.Entity, Domain.Entities.Entity>();
CreateMap<Domain.Entities.Entity, DTOs.Entity>();
#endregion Entity
}
}
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.0
- AutoMapper (>= 16.1.1)
- TechsBCN.Platform.Domain (>= 0.0.37)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on TechsBCN.Platform.Application:
| Package | Downloads |
|---|---|
|
TechsBCN.Platform.Infrastructure
Platform base project for Infrastructure to be used in TechsBCN standard projects |
|
|
TechsBCN.Platform.API
Platform base project for API to be used in TechsBCN standard projects |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.0.37 | 38 | 9/18/2026 |
| 0.0.36 | 128 | 9/11/2026 |
| 0.0.35 | 188 | 8/25/2026 |
| 0.0.34 | 108 | 8/25/2026 |
| 0.0.33 | 112 | 8/25/2026 |
| 0.0.32 | 182 | 7/31/2026 |
| 0.0.31 | 508 | 7/10/2026 |
| 0.0.30 | 324 | 6/30/2026 |
| 0.0.29 | 150 | 6/18/2026 |
| 0.0.27 | 143 | 6/12/2026 |
| 0.0.26 | 133 | 6/12/2026 |
| 0.0.25 | 136 | 6/4/2026 |
| 0.0.24 | 133 | 6/1/2026 |
| 0.0.23 | 124 | 6/1/2026 |
| 0.0.22 | 234 | 5/27/2026 |