Matios.Forge is a family of BCL-only .NET packages — one building block for each ring of Clean Architecture. Mediator, specification, state machine, strategy, repository and more. MIT, à la carte.
Not a framework you adopt whole. Each Clean Architecture concern is its own tiny, dependency-free package — take only what you need. Real machinery ships as code; trivial patterns ship as documented recipes, not empty classes.
Every module is BCL-only. The single exception is the opt-in DI adapter. No transitive surprises.
The mediator wires up with an explicit, zero-reflection builder. Dependency injection is optional, not required.
Install one module or all eight. No license tier, no revenue threshold, no all-or-nothing framework.
Define a request and its handler. Wire it with a container — or without one. Add pipeline behaviors. Publish notifications to many.
using Matios.Forge.Mesh;
public sealed record GetUser(string Id) : IRequest<User>;
public sealed class GetUserHandler(IUserRepository repo)
: IRequestHandler<GetUser, User>
{
public Task<User> Handle(GetUser request, CancellationToken ct)
=> repo.Find(request.Id, ct);
}// No DI container, no reflection — explicit and immutable.
IMediator mediator = new MediatorBuilder()
.AddBehavior<GetUser, User>(new LoggingBehavior())
.AddRequestHandler<GetUser, User>(new GetUserHandler(repo))
.Build(); // immutable, thread-safe
User user = await mediator.Send(new GetUser("42"));// Prefer a container? The DI adapter scans and registers for you.
services.AddForgeMesh(cfg =>
cfg.RegisterServicesFromAssemblyContaining<Program>());
IMediator mediator = provider.GetRequiredService<IMediator>();// A notification goes to 0..N handlers. Business errors are values, not throws.
public sealed record OrderPlaced(Guid Id) : INotification;
public Task<Result<Guid>> Handle(PlaceOrder cmd, CancellationToken ct)
=> cmd.Amount <= 0
? Task.FromResult(Result.Failure<Guid>(Error.Of("order.invalid_amount")))
: /* create, persist, publish, Result.Success(id) */;Handlers are resolved by type (O(1)) and the compiled, strongly-typed pipeline is invoked directly — no reflection on the hot path. The mediator itself adds almost nothing.
SendPublish| Scenario | Latency (ns/op) | Alloc (bytes/op) |
|---|---|---|
Send (no behavior) | ~15 | 72 |
Send (1 behavior) | ~31 | 176 |
Publish (3 handlers) | ~21 | 0 |
BenchmarkDotNet on .NET 10 Release, one machine (i9-13950HX). The 72 bytes on Send are the handler's own returned Task — the mediator adds ~0. Hardware-dependent; treat as a relative reference.
Each is its own package. Start with the mediator; add the rest as your architecture needs them.
.Mesh in automatically.Every module is implemented, tested and published, with an end-to-end sample crossing every ring.
dotnet add package Matios.Forge.Mesh.Open source · MIT · .NET 10 · zero dependencies
dotnet add package Matios.Forge.Mesh