ClientControllerCollectionTests: IndexOutOfRangeException from EF InMemory on multi-Include #3
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Status
Bug, pre-existing on
mainandfix/blog-detail. Not introduced by any recent commit. The four tests insrc/Yavsc.Org.Tests/Controllers/ClientControllerCollectionTests.cshave been red since their creation in commit6aaff740(the ClientController overhaul that introduced per-collection pages).Observed
Running
dotnet test src/Yavsc.Org.Tests/Yavsc.Org.Tests.csprojfails 4 tests with the same stack:The 4 failing tests are all in
ClientControllerCollectionTests:Edit_GET_returns_200_for_adminEditRedirectUris_GET_returns_200_and_lists_seeded_uriAddRedirectUri_POST_appends_to_databaseRemoveRedirectUri_POST_with_foreign_rowId_returns_NotFoundRoot cause
ClientController.LoadClientAsync(insrc/Yavsc.Org/Controllers/Administration/ClientController.Collections.cs) issues aSingleOrDefaultAsyncwith 9Includes on collections of theCliententity:The EF Core in-memory provider (used per the test policy in
doc/testing.md) cannot materialise this query: itsInMemoryShapedQueryCompilingExpressionVisitorreads a value buffer indexed by a slot counter that goes out of bounds when the same shape expression fans out across many collections. This is a long-standing limitation of the in-memory provider, documented in dotnet/efcore issues since 2019, and explicitly not fixed (the in-memory provider is "best effort", not a faithful mock).The test seeds a
Clientwith three populated collections (AllowedGrantTypes,AllowedScopes,RedirectUris) and six empty ones. The provider crashes on the include walk before any of the assertions can run.Reproduction
Result: 1 failed, 0 passed, 0 skipped. Same crash in isolation (no test-order dependence).
Options to fix
Data Source=:memory:) for this fixture. Faithful materialisation, no code change to the controller. Blocked by the test policy indoc/testing.md(UseInMemoryDatabaseis the only EF driver for unit tests; no SQLite, no real DB, no Docker).LoadClientAsyncto load collections in separate queries (one perInclude, orEntry(c).Collection(...).LoadAsync()for each). Trades one round-trip for nine in production, but the controller is admin-only and the row count is small. Would unblock the in-memory provider while keeping the test policy.AsSplitQuery()(EF Core 5+): changes the in-memory provider's expression tree to a sequence of per-collection queries. Worth a try as a one-line fix.Recommendation
Try option 3 first (cheapest). If
AsSplitQuery()doesn't satisfy the in-memory provider, refactor to option 2 (separate queries) — this is an admin endpoint, performance is not on the critical path.Investigation 2026-07-11: AsSplitQuery and Entry.LoadAsync both fail
Tried both recommendations from the issue body on a local branch
fix/issue-3-splitquery. Neither worked against the EF Core 10in-memory provider.
Attempt 1:
.AsSplitQuery()beforeSingleOrDefaultAsyncResult: still 4 failures. Stack trace identical to the original:
Reason:
AsSplitQueryis a no-op on the in-memory provider. Thereis no SQL LEFT JOIN to split — the provider still walks the same
multi-Include expression tree, with the same
IncludeCollectionslotcounter that overflows.
Attempt 2:
Entry().Collection().LoadAsync()per navigationRefactored
LoadClientAsyncto firstSingleOrDefaultAsynctheClientand then calldbContext.Entry(client).Collection(...).LoadAsync()once per navigation (9 calls). All
Includes removed.Result: still 4 failures. The crash moved:
Reason: the in-memory provider cannot materialise a query that
returns a navigation-property entity of
IdentityServer8.EntityFramework.Entities.The shape expression it builds references a slot that does not exist
in the value buffer, regardless of how the query is composed. The
issue is not the multi-Include shape — it is the entity type.
Next steps
(
Data Source=:memory:) for this fixture. This is the onlypath that materialises the
IdentityServer8entity modelfaithfully. Currently blocked by the test policy in
doc/testing.md("No SQLite, no real DB, no Docker" for unittests).
ClientControllertestsspecifically, since
IdentityServer8-shaped entities are out ofscope for a generic in-memory round-trip.
code is fine, the unit tests are not exercisable on InMemory.
No code change proposed yet. Awaiting policy decision.