Cayaqui.MPS.Abstractions
0.2.0
dotnet add package Cayaqui.MPS.Abstractions --version 0.2.0
NuGet\Install-Package Cayaqui.MPS.Abstractions -Version 0.2.0
<PackageReference Include="Cayaqui.MPS.Abstractions" Version="0.2.0" />
<PackageVersion Include="Cayaqui.MPS.Abstractions" Version="0.2.0" />
<PackageReference Include="Cayaqui.MPS.Abstractions" />
paket add Cayaqui.MPS.Abstractions --version 0.2.0
#r "nuget: Cayaqui.MPS.Abstractions, 0.2.0"
#:package Cayaqui.MPS.Abstractions@0.2.0
#addin nuget:?package=Cayaqui.MPS.Abstractions&version=0.2.0
#tool nuget:?package=Cayaqui.MPS.Abstractions&version=0.2.0
Cayaqui.MPS.Abstractions
Zero-dependency domain contracts for .NET 10 MPS modules. Contiene los tipos base que el resto de los módulos del dominio implementan/heredan.
Contenido
| Categoría | Tipos |
|---|---|
| Entity base | IEntity<TId> · Entity<TId> · AuditableEntity<TId> · AggregateRoot<TId> |
| Behaviour markers | IAuditable · ISoftDeletable · IVersioned |
| Lookup markers | INamed · ICoded · IDescribed |
| Value Object | ValueObject (clásica con GetEqualityComponents) |
| Domain Events | IDomainEvent · IHasDomainEvents · DomainEvent (record base) |
| Tree / WBS 🌲 | ITreeNode<TSelf, TId> + TreeNodeExtensions (Traverse, FindPath) |
| Specification | ISpecification<T> · Specification<T> (criteria + includes + order + paging) |
| Requests | PagedRequest · SortedRequest · SearchRequest · SortOrder enum |
| CQRS markers | ICommand · ICommand<TResult> · IQuery<TResult> |
Distribución propietaria — requiere contrato comercial con Cayaqui. Ver
LICENSE.txt.
Instalación
dotnet add package Cayaqui.MPS.Abstractions
Patrón típico
Entidad con Id tipado y audit fields
public sealed class ControlAccount : AuditableEntity<Guid>, ICoded, INamed
{
public string Code { get; private set; }
public string Name { get; private set; }
private ControlAccount() { }
public ControlAccount(Guid id, string code, string name) : base(id)
{
Code = code;
Name = name;
}
}
Aggregate root con domain events
public sealed class Project : AggregateRoot<Guid>
{
public ProjectStatus Status { get; private set; }
public void Approve()
{
if (Status != ProjectStatus.Draft)
throw new InvalidOperationException("Only drafts can be approved.");
Status = ProjectStatus.Approved;
RaiseDomainEvent(new ProjectApprovedEvent(Id));
}
}
public sealed record ProjectApprovedEvent(Guid ProjectId) : DomainEvent;
Con Wolverine, los eventos se despachan desde un SaveChangesInterceptor:
var aggregates = context.ChangeTracker
.Entries<IHasDomainEvents>()
.Where(e => e.Entity.DomainEvents.Any())
.Select(e => e.Entity).ToList();
foreach (var agg in aggregates)
{
foreach (var ev in agg.DomainEvents) await bus.PublishAsync(ev);
agg.ClearDomainEvents();
}
ValueObject clásica
public sealed class Money : ValueObject
{
public decimal Amount { get; }
public string Currency { get; }
public Money(decimal amount, string currency) { Amount = amount; Currency = currency; }
protected override IEnumerable<object?> GetEqualityComponents()
{
yield return Amount;
yield return Currency;
}
}
Para un
Moneylisto para usar incluyendo arithmetic y validación ISO 4217, verCayaqui.MPS.Helpers.
Specification
public sealed class ActiveControlAccountsByProject : Specification<ControlAccount>
{
public ActiveControlAccountsByProject(Guid projectId)
{
Where(ca => ca.ProjectId == projectId && !ca.IsDeleted);
AddInclude(ca => ca.WorkPackages);
ApplyOrderBy(ca => ca.Code);
DisableTracking();
}
}
// en el handler / repository:
var spec = new ActiveControlAccountsByProject(projectId);
var list = await db.ControlAccounts.Apply(spec).ToListAsync(ct);
(El método Apply es un evaluador típico: itera spec.Includes/IncludeStrings, aplica Where, OrderBy/OrderByDescending, Skip/Take y AsNoTracking.)
WBS / hierarchical breakdown
public sealed class WbsNode : Entity<Guid>, ITreeNode<WbsNode, Guid>
{
public Guid? ParentId { get; private set; }
public int Level { get; private set; }
public string Path { get; private set; } = "";
public IReadOnlyCollection<WbsNode> Children { get; private set; } = Array.Empty<WbsNode>();
}
// enumerar descendientes en pre-orden:
var all = root.Traverse<WbsNode, Guid>().ToList();
// path ancestral hasta un nodo:
var pathToTarget = root.FindPath<WbsNode, Guid>(n => n.Code == "1.2.3");
CQRS markers con Wolverine
public sealed record CreateControlAccountCommand(Guid ProjectId, string Code) : ICommand<Guid>;
public sealed record GetControlAccountByIdQuery(Guid Id) : IQuery<ControlAccountDto>;
// Wolverine descubre el handler por convención:
public static class ControlAccountHandlers
{
public static async Task<Guid> Handle(CreateControlAccountCommand cmd, AppDbContext db) { ... }
public static async Task<ControlAccountDto?> Handle(GetControlAccountByIdQuery q, AppDbContext db) { ... }
}
Paged request
public sealed record ListControlAccountsQuery : SearchRequest, IQuery<PaginatedList<ControlAccountDto>>
{
public Guid ProjectId { get; init; }
}
// cliente:
var query = new ListControlAccountsQuery
{
ProjectId = projId,
PageNumber = 2,
PageSize = 50,
SortBy = "Code",
SortOrder = SortOrder.Ascending,
SearchTerm = "civil"
};
Diseño
- Zero dependencies — puro .NET 10 BCL. Cualquier consumidor puede tomarlo sin arrastrar EF Core, MediatR, Wolverine, etc.
- Sin opinión de persistencia — los markers y bases son agnósticos. EF Core se configura con
HasQueryFilterparaISoftDeletable,IsRowVersionparaIVersioned, interceptores paraIAuditable. - Equality predecible —
Entity(por Id + tipo runtime),ValueObject(estructural), con hashes deterministas. - Compatible con Wolverine — los CQRS markers son opcionales; Wolverine descubre handlers por convención sin requerirlos, pero hacer el marcado explícito mejora la intención en código.
Requisitos
- .NET 10.0 o superior
- Sin dependencias externas
| 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
- No dependencies.
NuGet packages (4)
Showing the top 4 NuGet packages that depend on Cayaqui.MPS.Abstractions:
| Package | Downloads |
|---|---|
|
Cayaqui.MPS.BuildingBlocks.EntityFrameworkCore
EF Core integration for Cayaqui.MPS.BuildingBlocks: transactional Outbox (EfOutboxStore with Postgres FOR UPDATE SKIP LOCKED + redispatch/purge hosted services + multi-store health check), audit + domain-event-dispatch SaveChanges interceptors, and Blazor Server-safe scoped CQRS handlers (ScopedQueryHandler/ScopedCommandHandler over IDbContextFactory returning Result<T>). Proprietary — requires a commercial agreement with Cayaqui. |
|
|
Cayaqui.MPS.Cqrs
CQRS handler-pipeline decorators (logging) for the MPS IHandler. Contains LoggingHandlerDecorator<TIn, TResult> which wraps any IHandler<TIn, Result<TResult>> with structured logging of entry/success/failure/exceptions. Kept separate from Cayaqui.MPS.Abstractions so that the zero-dependency core is preserved. Proprietary — requires a commercial agreement with Cayaqui. |
|
|
Cayaqui.MPS.Abstractions.Validation
FluentValidation cross-cutting decorator for the MPS CQRS IHandler pipeline. Wraps any IHandler<TIn, Result<TResult>> with an optional IValidator<TIn>; on validation failure returns a typed DomainError (ErrorType.Validation) with per-field Metadata — no control-flow exceptions. Kept as a separate package so FluentValidation is not forced on zero-dep consumers of Cayaqui.MPS.Abstractions. Proprietary — requires a commercial agreement with Cayaqui. |
|
|
Cayaqui.MPS.Authorization
Business authorization layer for MPS Blazor apps: project-scoped roles and granular permissions, AppUser entity, MpsRoles/MpsPermissions constants, IMpsCurrentUser, MpsAuthorizeView and MpsAccessDenied Blazor components, and AuthorizationDbContext (EF Core). Supports both Entra ID and local auth deployment models. |
GitHub repositories
This package is not used by any popular GitHub repositories.
0.2.0 — BREAKING: namespaces folder-matched (tipos movidos a sub-namespaces Entities/Messaging/Requests/Specifications; los consumidores deben actualizar usings). Agrega CQRS: IHandler<,> (MPS.Abstractions.Cqrs) y PagedResult<T>. LoggingHandlerDecorator movido a Cayaqui.MPS.Cqrs para restaurar zero-dependency. 0.1.0 — Initial release: Entity/AuditableEntity/AggregateRoot, ValueObject, behaviour markers, INamed/ICoded/IDescribed, ITreeNode, ISpecification, PagedRequest, CQRS markers.