Skip to content

About

Opinionated .NET framework inspired by fractals: entities, aggregates, domain events, CQRS dispatchers and configuration helpers.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

41 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Fractalize .NET Framework

CI CodeQL OpenSSF Scorecard Latest release NuGet NuGet downloads License: MIT Conventional Commits

An opinionated, open source .NET framework for building elegant, robust applications inspired by fractals. Simple, repeated structures (entities, aggregates, domain events, commands and queries with their dispatchers) keep systems modular, scalable and easy to maintain.

πŸ“¦ Packages

Package Contents
Efc.Fractalize.Domain Building blocks with no dependencies: EntityBase, AggregateRootBase, IDomainEvent, EventBase, and the ICommand / IQuery contracts with their handlers and dispatchers
Efc.Fractalize.Ddd Domain-driven design core with no dependencies: EntityBase with identity equality, AggregateRootBase with domain events, DomainEventBase, ValueObjectBase, DateRange, and the IReadRepository / IRepository / IUnitOfWorkBase contracts. It overlaps with Efc.Fractalize.Domain until the maintainers decide which types survive
Efc.Fractalize.Application CommandDispatcher and its fluent configurator, CommandDispatcherConfigurator (AddCommandDispatcher)
Efc.Fractalize.Infrastructure QueryDispatcher and QueryDispatcherConfigurator (AddQueryDispatcher), CqrsConfigurator (AddCqrsDispatchers: commands and queries in one call) and OptionsConfigurator (AddValidatedOptions: options validated at startup). Depends on Efc.Fractalize.Application

The libraries target net10.0 and are published to NuGet.

πŸš€ Getting started

dotnet add package Efc.Fractalize.Infrastructure

Define a query and its handler, register them and dispatch the query:

using Efc.Fractalize.Domain.Queries;
using Efc.Fractalize.Infrastructure.Extensions;

public sealed record GetGreeting(string Name) : IQuery<string>;

public sealed class GetGreetingHandler : IQueryHandler<GetGreeting, string>
{
    public Task<string> HandleAsync(GetGreeting query, CancellationToken cancellationToken = default) =>
        Task.FromResult($"Hello, {query.Name}!");
}

// At startup: register the command and query dispatchers and the handlers of this assembly.
services.AddCqrsDispatchers(typeof(GetGreetingHandler).Assembly);

// Anywhere: resolve the dispatcher for the query and send it.
var greeting = await provider
    .GetRequiredService<IQueryDispatcher<GetGreeting, string>>()
    .DispatchAsync(new GetGreeting("Fractalize"));

Commands work the same way with ICommand, ICommandHandler<TCommand> and ICommandDispatcher<TCommand>. Each configurator can also be used on its own: AddCommandDispatcher(...) (Efc.Fractalize.Application.Commands) and AddQueryDispatcher(...) (Efc.Fractalize.Infrastructure.Queries) register the dispatcher and scan the handlers of the given assemblies (every application dependency when none is given), and AddCommandDispatcher<TCommand>() / AddQueryDispatcher<TQuery, TResult>() register the dispatcher of a single message. Every registration uses TryAdd*, so a host can replace any implementation and calling a configurator twice is harmless.

Options are bound and validated with data annotations when the application starts, as the engineering standards require:

using Efc.Fractalize.Infrastructure.Extensions;

// From configuration (appsettings + environment variables)...
services.AddValidatedOptions<ShipmentRepositoryOptions>(configuration, ShipmentRepositoryOptions.SectionName);

// ...or from code (tests, other hosts, values read from a database).
services.AddValidatedOptions<ShipmentRepositoryOptions>(o => o.ConnectionString = connectionString);

Migrating from 2.x helpers

The 2.x registration helpers still work with the same behaviour, but they are marked [Obsolete] and will be removed in the next major version. Replace them as follows:

2.x helper (obsolete) Replacement
AddCqrs() AddCqrsDispatchers(assemblies) (CqrsConfigurator, Efc.Fractalize.Infrastructure)
AddCommandHandlers(), AddCommandDispatchers() AddCommandDispatcher(assemblies) (CommandDispatcherConfigurator)
TryAddCommandDispatcher<TCommand>(), ConfigureCommandHandler<TCommand>() AddCommandDispatcher<TCommand>()
AddQueryHandlers(), AddQueryDispatchers() AddQueryDispatcher(assemblies) (QueryDispatcherConfigurator)
TryAddQueryDispatcher<TQuery, TResult>(), ConfigureQueryHandler<TQuery, TResult>() AddQueryDispatcher<TQuery, TResult>()
AddConfigurationSection<T>(configuration, sectionName) AddValidatedOptions<T>(configuration, sectionName) (OptionsConfigurator)

Differences to keep in mind:

  • The new configurators use TryAdd*: a handler or dispatcher registered earlier is kept, not duplicated.
  • AddCommandDispatcher(...) and AddQueryDispatcher(...) also register the dispatcher for every message type, so the per-message AddCommandDispatcher<TCommand>() / AddQueryDispatcher<TQuery, TResult>() calls are optional.
  • AddValidatedOptions always registers the options and validates them at startup: a missing or invalid section fails when the host starts, while AddConfigurationSection skipped missing sections and never validated.

πŸ› οΈ Building from source

Prerequisites, commands and the checks every pull request must pass are in CONTRIBUTING.md. In short:

dotnet build src/Efc.Fractalize.Framework.sln -c Release -warnaserror
dotnet test src/Efc.Fractalize.Framework.sln -c Release

πŸ›‘οΈ Standards

  • Engineering standards: file-scoped namespaces and no unused code (build errors), minimum 80 % line coverage (CI gate), low coupling and high cohesion, Options pattern and fluent *Configurator classes.
  • English only in code, comments, docs, commits and pull requests.
  • Conventional Commits for every commit and pull request title; releases follow Semantic Versioning and CHANGELOG.md is generated by release-please.
  • Protected main: pull requests only, required checks, code-owner approval, resolved conversations, signed commits, merge commit or squash (no rebase merges), no force pushes or deletion.
  • Protected release tags: v* tags can't be moved or deleted.
  • Least-privilege workflows: read-only token by default, explicit per-job permissions, every action pinned to a full commit SHA, checkouts without persisted credentials.
  • Supply chain: CodeQL, dependency review, Dependabot and OpenSSF Scorecard.
  • Secrets never in Git: secret scanning with push protection, .env files ignored.

These standards come from the public-repo-template.

🀝 Contributing

Read CONTRIBUTING.md before opening a pull request, follow the Code of Conduct, and report vulnerabilities privately as described in SECURITY.md. For questions, see SUPPORT.md.

πŸ“„ License

MIT Β© 2025 Dev Cracks

About

Opinionated .NET framework inspired by fractals: entities, aggregates, domain events, CQRS dispatchers and configuration helpers.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages