Skip to content

Port framework improvements from backend and split into eleven packages - #1

Merged
KRSogaard merged 1 commit into
masterfrom
port-from-backend
Sep 7, 2026
Merged

KRSogaard merged 1 commit into
masterfrom
port-from-backend

Conversation

@KRSogaard

Copy link
Copy Markdown
Contributor

MagicCSharp was extracted from the backend in June and the two diverged; every shared file differed. This brings the backend's improvements across and splits the packages so a consumer takes only what it uses.

Packages
Six new: AspNetCore, Scheduling, Data.EntityFramework, Data.Postgres, Testing and Testing.Database. Core drops from six dependencies to three and no longer pulls in ASP.NET Core or distributed locking; Data no longer pulls in Entity Framework, so a domain project can reference the repository interfaces without taking on a persistence library; Testing has no xUnit or Testcontainers, so wanting FakeClock does not mean wanting Docker.

Data
One IRepository<TEntity, TKey, TEdit, TFilter> replaces the two interfaces that hardcoded long. Soft delete, pagination and search become opt-in interfaces with base classes for both key shapes. Adds GetKeys, batch update by dictionary and by list, delete by filter, untracked reads, and the re-read after write that populates navigation properties.

MagicDbContext stores enums by name (including inside JSON columns) so inserting an enum member no longer changes what existing rows mean, and normalizes timestamps to UTC. The Postgres package adds a pooled context factory that fails at startup on a bad connection string, a design-time factory for dotnet ef, and a command interceptor covering the query predicates and ExecuteUpdate/Delete that never reach SaveChanges.

Testing
New. A clock you move by hand, ids derived from it, an event dispatcher that runs handlers inline so assertions need no sleeping, a re-entrant in-memory lock, and a base class for repository tests against real PostgreSQL in Testcontainers.

Fixes

  • AddMagicUseCases picked implementations with FirstOrDefault, so two implementations meant one was chosen silently by reflection order. Now throws and names both.
  • The same scan only saw already-loaded assemblies, so use cases in an untouched project were never registered.
  • LocalEventDispatcher blocked while Kafka and SQS are fire-and-forget, so a handler re-entering its emitter's lock worked locally and deadlocked in production.
  • ScheduledBackgroundService logged its next run from the wall clock while scheduling from the injected IClock.
  • Core pinned Microsoft.AspNetCore.Http.Abstractions 2.2.0.

Tooling
tools/ holds AddEntity, ValidateConventions and SyncAllProjects as single-file programs, keyed off magiccsharp.json rather than hardcoded paths so they work in any repository using the layout.

Tests
47, where there were none.

Libraries stay on net9.0 so net9 and net10 apps can both consume them. See CHANGELOG.md for the full list and the migration guide.

MagicCSharp was extracted from the backend in June and the two diverged;
every shared file differed. This brings the backend's improvements across
and splits the packages so a consumer takes only what it uses.

Packages
Six new: AspNetCore, Scheduling, Data.EntityFramework, Data.Postgres,
Testing and Testing.Database. Core drops from six dependencies to three
and no longer pulls in ASP.NET Core or distributed locking; Data no longer
pulls in Entity Framework, so a domain project can reference the repository
interfaces without taking on a persistence library; Testing has no xUnit or
Testcontainers, so wanting FakeClock does not mean wanting Docker.

Data
One IRepository<TEntity, TKey, TEdit, TFilter> replaces the two interfaces
that hardcoded long. Soft delete, pagination and search become opt-in
interfaces with base classes for both key shapes. Adds GetKeys, batch
update by dictionary and by list, delete by filter, untracked reads, and
the re-read after write that populates navigation properties.

MagicDbContext stores enums by name (including inside JSON columns) so
inserting an enum member no longer changes what existing rows mean, and
normalizes timestamps to UTC. The Postgres package adds a pooled context
factory that fails at startup on a bad connection string, a design-time
factory for dotnet ef, and a command interceptor covering the query
predicates and ExecuteUpdate/Delete that never reach SaveChanges.

Testing
New. A clock you move by hand, ids derived from it, an event dispatcher
that runs handlers inline so assertions need no sleeping, a re-entrant
in-memory lock, and a base class for repository tests against real
PostgreSQL in Testcontainers.

Fixes
- AddMagicUseCases picked implementations with FirstOrDefault, so two
  implementations meant one was chosen silently by reflection order.
  Now throws and names both.
- The same scan only saw already-loaded assemblies, so use cases in an
  untouched project were never registered.
- LocalEventDispatcher blocked while Kafka and SQS are fire-and-forget,
  so a handler re-entering its emitter's lock worked locally and
  deadlocked in production.
- ScheduledBackgroundService logged its next run from the wall clock
  while scheduling from the injected IClock.
- Core pinned Microsoft.AspNetCore.Http.Abstractions 2.2.0.

Tooling
tools/ holds AddEntity, ValidateConventions and SyncAllProjects as
single-file programs, keyed off magiccsharp.json rather than hardcoded
paths so they work in any repository using the layout.

Tests
47, where there were none.

Libraries stay on net9.0 so net9 and net10 apps can both consume them.
See CHANGELOG.md for the full list and the migration guide.
@KRSogaard
KRSogaard merged commit a551ea4 into master Sep 7, 2026
@KRSogaard
KRSogaard deleted the port-from-backend branch September 7, 2026 00:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant