Skip to content
CAI
Software that uses CAICheck a score

huysentruitw/Aggregator

50.5

Adequate · 21 September 2026

1.3k

lines of production code

C#

with TypeScript

4

measurements over time

CAI band scale
CAI trend line
CAI lens gauges

What this system is

This system is an event-sourcing framework for .NET that manages aggregate roots and their state changes. It provides a command processing pipeline that dispatches domain events and persists them to an event store. The library supports multiple dependency injection containers and includes a fluent testing API for verifying aggregate behavior.

How it got here

2018 — Architecture modernization and DI integration

21 changes.

The project underwent a significant architectural refactoring to simplify the core AggregateRoot implementation and introduce asynchronous, dependency-injection-friendly patterns. This period saw the migration of the test suite to xUnit, the introduction of a custom event dispatcher, and the addition of Microsoft.Extensions.DependencyInjection support alongside a new EventStore persistence layer.

2019–2020 — Testing infrastructure and sample expansion

4 changes.

This period focused on enhancing the framework's testability by introducing a fluent testing library for aggregate roots and expanding the Kanban sample with comprehensive domain and integration tests. Additionally, the KanbanStyle sample was augmented with a full ASP.NET Core and Angular 6 frontend template.

Features

Add ASP.NET Core Angular application template

The KanbanStyle sample now includes a complete ASP.NET Core application template featuring an Angular 6.0.0 client-side application. This adds a new frontend structure with components for navigation, home, counter, and data fetching, alongside a backend WeatherForecast API endpoint. The project also includes standard configuration files for the Angular CLI, TypeScript, and build processes.

samples/KanbanStyle · high confidence

Add Aggregator DI extension methods for service registration

A new extension class, ServiceCollectionExtensions, has been added to the Microsoft.Extensions.DependencyInjection namespace. This provides two new methods, AddAggregator, which allow users to register the Aggregator library's core dependencies—including ICommandProcessor, IRepository, IEventDispatcher, and related context classes—directly on the IServiceCollection. This simplifies the setup process by bundling the necessary service registrations into a single, chainable call.

src/Aggregator.Microsoft.DependencyInjection/Extensions · high confidence

Add Aggregator.Testing library for fluent aggregate testing

The Aggregator.Testing library has been added, providing a fluent API for testing aggregate roots. This includes a new AggregatorTestingException, and fluent continuation classes (Scenario, GivenContinuation, WhenContinuation, ThenContinuation, ThrowsContinuation) that allow users to write tests by chaining method calls to verify expected events or exceptions.

src/Aggregator.Testing · high confidence

Add EventStore persistence implementation

Introduces a new EventStore-based persistence layer for the Aggregator framework. The \EventStore\ class provides methods to check if an aggregate root exists (\Contains\) and retrieve its event stream (\GetEvents\). The \EventStoreTransaction\ class handles buffering and committing or rolling back batches of events, supporting optimistic concurrency control via version checking. This adds a concrete, production-ready implementation for event sourcing using the EventStore database.

src/Aggregator.Persistence.EventStore · high confidence

Add Microsoft.Extensions.DependencyInjection integration

The Aggregator library now supports Microsoft's dependency injection container. This change introduces \ServiceScope\ and \ServiceScopeFactory\ implementations that wrap the standard \IServiceScope\ and \IServiceProvider\ interfaces, allowing users to resolve services and manage scopes within the Aggregator framework using the Microsoft.Extensions.DependencyInjection API.

src/Aggregator.Microsoft.DependencyInjection · high confidence

Introduce custom event dispatcher for command processing

Added a new \EventDispatcher\ class and its \IEventDispatcher\ interface to handle event dispatching within the \CommandProcessor\. This implementation uses reflection to invoke generic handler methods for each event, allowing the system to process multiple events generated by a single command execution.

src/Aggregator/Event · high confidence

Repository structure and configuration files added

The repository was initialized with core documentation and configuration files, including CONTRIBUTING.md, LICENSE.txt, and README.md. Additionally, build and CI configurations (appveyor.yml, .editorconfig, .gitignore) and solution structure (Aggregator.sln) were added to support the project's development workflow.

(repo-wide) · high confidence

Behavioural changes

Async persistence interfaces and repository implementation

The Aggregator.Persistence layer introduces a new IRepository interface and concrete Repository class for managing aggregate roots, including methods to check existence, retrieve, and add aggregates. The IEventStore interface is updated to support asynchronous operations, adding a Contains method and a GetEvents method that accepts a minimum version. Additionally, the IEventStoreTransaction interface is modified to make Commit, Rollback, and StoreEvents methods asynchronous (returning Task) and renames the expected revision parameter to expectedVersion with a long type.

src/Aggregator/Persistence · medium confidence

Refactor internal aggregate root tracking to use a new AggregateRootEntity wrapper

The internal unit of work now tracks aggregate roots using a new AggregateRootEntity class, which encapsulates the identifier, the aggregate root, and the expected version. This replaces the previous approach of storing the raw IAggregateRootChangeTracker in the unit of work's dictionary. Additionally, the IAggregateRootChangeTracker interface has been simplified by removing the Identifier and ExpectedRevision properties (now handled by the wrapper) and changing the GetChanges method to return a TEventBase\[\] array instead of an IEnumerable.

src/Aggregator/Internal · high confidence

Refactored Autofac integration and command handling scope

The Autofac module has been refactored to simplify dependency injection and remove the previous command-handling scope mechanism. The old \CommandHandlingScope\ and \CommandHandlingScopeFactory\ classes have been removed in favor of a simpler \ServiceScope\ and \ServiceScopeFactory\ implementation. Additionally, the \ICommandHandler\ interface was moved to the \Aggregator.Abstractions\ project and updated to include a \CancellationToken\ in its \Handle\ method, allowing commands to be cancelled. The \AggregatorModule\ now registers the \CommandProcessor\ and \Repository\ types directly, streamlining the container setup.

src/Aggregator.Autofac · medium confidence

Refactored command processing to use dependency injection and event dispatching

The command processor now resolves command handlers via a service scope rather than a custom scope factory, and explicitly dispatches events through an IEventDispatcher. This change introduces transactional event storage with automatic rollback on failure, adds configurable notification handlers for pre-processing and event enrichment, and supports cancellation via CancellationToken.

src/Aggregator/Command · medium confidence

Refine exception hierarchy and add new domain-specific exceptions

The exception handling in the Aggregator module has been refactored to simplify the base class and introduce new, specific exceptions. The base \AggregateRootException\ and its generic variant \AggregateRootException\<TIdentifier\>\ have been simplified by removing the \innerException\ constructor overloads, meaning inner exceptions are no longer supported for these types. Additionally, three new exception types have been introduced: \AggregateRootAlreadyAttachedException\ (thrown when an aggregate root is attached twice), \AggregateRootAlreadyExistsException\ (thrown when adding a duplicate aggregate root), and \AggregateRootNotFoundException\ (thrown when an aggregate root is not found). Furthermore, \HandlerForEventAlreadyRegisteredException\ and \UnhandledEventException\ have been decoupled from the generic \AggregateRootException\<TIdentifier\>\ base class, removing the generic type parameter and the associated identifier property, simplifying their signatures to focus on the event type.

src/Aggregator/Exceptions · high confidence

Simplified AggregateRoot base class and changed change tracking to a queue

The generic AggregateRoot class no longer requires a separate identifier type parameter, as the identifier and expected version have been removed from this base class. Internally, the collection of pending changes has been switched from a List to a Queue, and the GetChanges method now returns an array instead of an IEnumerable. These changes streamline the aggregate root implementation by removing redundant state and enforcing a first-in-first-out order for change tracking.

Aggregator · medium confidence

Updated assembly visibility configuration for test projects

The internal visibility attributes in the Aggregator assembly have been updated to include strong-name public key tokens for the test projects. This change ensures that the test assemblies can access internal members of the Aggregator library, which is necessary for unit testing internal implementation details.

src/Aggregator · high confidence

Test coverage

Added domain model and command handler tests for the Kanban sample; Added unit tests for EventDispatcher; Added unit tests for EventStore and EventStoreTransaction; Added unit tests for Microsoft DI integration; Added unit tests for command handling, processing, and dependency injection; Added unit tests for the Aggregator testing framework; Added unit tests for the persistence layer's Repository class; Migrate Aggregator.Tests to xUnit and add coverage for AggregateRootEntity; Migrate Aggregator.Tests to xUnit and expand test coverage; Migrated Autofac test suite to xUnit.

Dependencies

Update .NET target frameworks and test dependencies

The project files for the Aggregator library and its samples have been updated to target .NET Standard 2.0 and 2.1, replacing the previous .NET Core 2.0/4.7.1 targets. Additionally, the test projects have been migrated from NUnit to xUnit, and dependencies such as Autofac and Moq have been updated to their latest compatible versions.

(dependencies) · high confidence

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

How this codebase got here

This is the PUBLIC form of this artifact. Findings are listed in full, but the details of SECURITY findings — which rule fired, in which file, on which line, and how to fix it — are deliberately withheld, and any secret-scanner results are excluded entirely. Where detail is absent here it was REMOVED FOR PUBLICATION; it is not missing from the analysis. The complete artifact is available from the repository owner.

Score

  • CAI 55 → 51 (-4.1)
  • Rubric changed (rubric-2026.08.18 → rubric-2026.09.15) — scores are not directly comparable.

Lenses

  • Code Health 84 → 78 (-5.2)
  • Architecture 91 → 91 (-0.3)
  • Maturity 47 → 47 (+0.0)
  • Readiness 45 → 41 (-3.6)
  • Security 99 → 64 (-35.5)
  • Performance 66 → 66 (+0.0)

Resolved (10)

  • Bounded contexts not declared
  • Coverage not measured — analyzer environment
  • Low XML-doc coverage: Aggregator.Testing(netstandard2.0) (src/Aggregator.Testing/Aggregator.Testing.csproj)
  • Low: security finding (details withheld)
  • Low: security finding (details withheld)
  • Monorepo: only 1 of 2 solutions was scored
  • No exposed public API
  • Test runner surfaced no tests
  • dormant codebase — no living knowledge left to concentrate
  • redundant comment (tests/Aggregator.Autofac.Tests/ServiceScopeFactoryTests.cs)

New (28)

  • CoverageExclusion (src/Aggregator.Autofac/AggregatorModule.cs)
  • CoverageExclusion (src/Aggregator.Autofac/AggregatorModule.cs)
  • CoverageExclusion (src/Aggregator.Microsoft.DependencyInjection/Extensions/ServiceCollectionExtensions.cs)
  • CoverageExclusion (src/Aggregator.Persistence.EventStore/EventStore.cs)
  • CoverageExclusion (src/Aggregator.Persistence.EventStore/EventStore.cs)
  • CoverageExclusion (src/Aggregator.Persistence.EventStore/EventStore.cs)
  • CoverageExclusion (src/Aggregator.Persistence.EventStore/EventStoreTransaction.cs)
  • Documentation: no usage examples (README.md)
  • End-of-life runtime: .NET netcoreapp3.1
  • High secret: WD-SECRET-0001 (src/Aggregator.Abstractions/keyfile.snk)
  • High secret: WD-SECRET-0001 (src/Aggregator.Autofac/keyfile.snk)
  • High secret: WD-SECRET-0001 (src/Aggregator.Microsoft.DependencyInjection/keyfile.snk)
  • High secret: WD-SECRET-0001 (src/Aggregator.Persistence.EventStore/keyfile.snk)
  • High secret: WD-SECRET-0001 (src/Aggregator/keyfile.snk)
  • Leaked secret: private-key-blob (src/Aggregator.Abstractions/keyfile.snk)
  • Leaked secret: private-key-blob (src/Aggregator.Autofac/keyfile.snk)
  • Leaked secret: private-key-blob (src/Aggregator.Microsoft.DependencyInjection/keyfile.snk)
  • Leaked secret: private-key-blob (src/Aggregator.Persistence.EventStore/keyfile.snk)
  • Leaked secret: private-key-blob (src/Aggregator/keyfile.snk)
  • Low: security finding (details withheld)
  • …and 8 more

API surface

  • Unchanged — 1 HTTP endpoints

Architecture

  • Unchanged — 0 containers · 1 contexts · 0 edges

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

Survey your own repository

huysentruitw/Aggregator was measured the same way every project in this corpus was: the same rubric, at a pinned commit, with the result published in full. Point a surveyor at a repository you know and see whether you agree with it.

About this page

  • The score is its most recent published measurement, taken on 21 September 2026 at a pinned commit. It is not a live figure and does not change until the project is measured again.
  • Measured at commit d78423b561164d4ba568a1dd2931e8599fd09fd6 — the exact code this score is about.
  • Scored under rubric-2026.09.15 — the same rubric and the same method as every other entry in this index.
  • Measured by watchdog.canine.dev using codehealth-analyzer preprod-28e75b8e3254.