Skip to content

ConjoinedMultiTenantedEfCore sample app + CrossTenantWriteException message fix (GH-3465) - #3515

Merged
jeremydmiller merged 2 commits into
mainfrom
sample/conjoined-efcore-tenancy-3465
Jul 20, 2026
Merged

ConjoinedMultiTenantedEfCore sample app + CrossTenantWriteException message fix (GH-3465)#3515
jeremydmiller merged 2 commits into
mainfrom
sample/conjoined-efcore-tenancy-3465

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

The full-tour sample app for the conjoined EF Core multi-tenancy epic, closing out the Wolverine-side work on #3465 for 6.21 (naming decisions recorded on the issue — both public names stay as shipped in #3498).

The sample (src/Samples/ConjoinedMultiTenantedEfCore)

Mirrors the motivating hand-rolled-tenancy blog scenario and shows Wolverine automating each pain point, validated live against dockerized Postgres with a scripted curl tour (README):

  • ITenanted Invoice + non-tenanted Product counter-example; deliberately vanilla DbContext
  • AddDbContextWithWolverineManagedConjoinedTenancy<T> + HTTP tenant detection (header/query/AssertExists())
  • Stamp-on-insert POST that never touches TenantId, cascading a tenant-scoped message to a durable local queue handler
  • A deliberate IgnoreQueryFilters() hijack endpoint demonstrating CrossTenantWriteException
  • Tenant isolation on reads (same table, different tenants, cross-tenant GET → 404)
  • wolverine_tenants registry CRUD via IDynamicTenantSource<string> ([NotTenanted] endpoints), seeded tenants
  • Commented PartitionPerTenant() opt-in

Validated: build clean, full-solution restore clean, live round trips for every bullet above.

Also in this PR

  • CrossTenantWriteException message grammar fix ("Cannot modified entity..." → "Cannot apply a 'Modified' change to an entity..."); no test asserts the text; the 34 conjoined compliance tests are green locally.

API-friction follow-ups from building the sample (DbContext body-inference footgun, RuntimeCompilation docs mention, Npgsql-EF net10 pin, partition-existing-table story) are recorded on #3465.

🤖 Generated with Claude Code

https://claude.ai/code/session_01J4XSARYV567q5Y3fW6iwiu

jeremydmiller and others added 2 commits July 19, 2026 19:38
…ulti-tenancy (GH-3465)

New sample app mirroring the motivating shared-database multi-tenancy
scenario (barretblake.dev multi-tenant series) and showing how Wolverine
automates every pain point:

- ITenanted Invoice entity + vanilla DbContext (tenant_id mapping and
  global query filter applied by Wolverine, zero tenancy code)
- AddDbContextWithWolverineManagedConjoinedTenancy registration with
  Wolverine.Http header/query-string tenant detection + AssertExists
- Stamp-on-insert POST endpoint that never touches TenantId, cascading
  a tenant-carrying message to a durable local queue handler
- Deliberate IgnoreQueryFilters hijack endpoint demonstrating
  CrossTenantWriteException rejection
- Tenant-scoped queries through both HTTP endpoints and handlers
- Commented opt-in Weasel-managed PG partitioning (PartitionPerTenant)
- wolverine_tenants registry endpoints (list/add/disable/enable/remove)
  via IDynamicTenantSource<string>, seeded with two demo tenants

net9.0 only, matching every other Npgsql-EF project in the repo until
the EF 10 Npgsql provider GAs. Validated against dockerized PostgreSQL
(5433): clean startup plus curl round trips for stamping, isolation,
missing-tenant 400, cross-tenant 404/rejection, and registry lifecycle.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J4XSARYV567q5Y3fW6iwiu
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