206 lines
12 KiB
Markdown
206 lines
12 KiB
Markdown
# Team Brief — AuthBlocks: Register `ModelView`'s Missing Dependency via `ConfigureAuthServices`
|
|
|
|
**Audience:** an orchestrator (and its implementers) working **only** in the AuthBlocks repository at
|
|
`C:\Development\AuthBlocks`. You do not need, and should not assume, any knowledge of the products that
|
|
consume AuthBlocks. Everything you need is in this brief or in that one repo (plus a single new BlazorBlocks
|
|
package version — see §2, the blocking prerequisite).
|
|
|
|
**Status:** ✅ RESOLVED — shipped in `Cerebellum.BlazorBlocks.Web` 10.3.33 + `Cerebellum.AuthBlocks.Web` 10.3.36 (2026-06-20). ~~scoped request, blocked on a BlazorBlocks publish (see §2). Confirmed at runtime against `Cerebellum.AuthBlocks.Web` 10.3.33 / `Cerebellum.BlazorBlocks.Web` 10.3.32. Author: product-designer (for a downstream consumer team). Date: 2026-06-19.~~
|
|
|
|
> **Resolution (2026-06-20):** `AddBlazorBlocksWeb()` landed in `Cerebellum.BlazorBlocks.Web` 10.3.33 and `ConfigureAuthServices` calls it in `Cerebellum.AuthBlocks.Web` 10.3.36; DeepDrftManager picked up 10.3.36 and removed its local `EditModalSaveContextHolder` stopgap.
|
|
> This brief is retained as historical record — no further action required.
|
|
|
|
**This is one half of a two-team, ordered fix. AuthBlocks ships second — see §2 and §9.**
|
|
|
|
---
|
|
|
|
## 1. The defect in one sentence
|
|
|
|
`AuthBlocksWeb` ships `Users.razor` and `Registrations.razor`, both of which render BlazorBlocks'
|
|
`<ModelView>` component — but `ConfigureAuthServices` (the single DI entry point consumers call to light up
|
|
the AuthBlocks Web surface) does **not** ensure `ModelView`'s required service
|
|
`Web.Maintenance.Entities.EditModalSaveContextHolder` is registered. So a consumer that wires up AuthBlocks
|
|
the normal way gets an unhandled `InvalidOperationException` that **terminates the Blazor circuit on
|
|
navigation** to either page, unless that consumer manually hand-registers an internal BlazorBlocks service
|
|
in its own `Program.cs`.
|
|
|
|
The fix: have `ConfigureAuthServices` call BlazorBlocks' new `AddBlazorBlocksWeb()` extension (which
|
|
registers the holder), so AuthBlocks stays self-contained for *its* consumers.
|
|
|
|
---
|
|
|
|
## 2. Blocking prerequisite — BlazorBlocks must ship first
|
|
|
|
This fix **cannot land until BlazorBlocks publishes a new `Cerebellum.BlazorBlocks.Web` version that
|
|
exposes a Web-side registration extension** (working name `AddBlazorBlocksWeb()`). That extension is what
|
|
actually registers `EditModalSaveContextHolder`; AuthBlocks' job is only to *call* it.
|
|
|
|
- AuthBlocks is currently on `Cerebellum.BlazorBlocks.Web` **10.3.32**, which has **no** such extension.
|
|
- The BlazorBlocks team is shipping the extension and bumping the package as the first half of this fix.
|
|
- **Reference the specific new version BlazorBlocks publishes for this fix** — fill in the exact version
|
|
number once the BlazorBlocks team reports it. Do not proceed against 10.3.32; the method will not exist.
|
|
|
|
If you reach this work before the BlazorBlocks version is available, stop and wait for the published version
|
|
number. The AuthBlocks change is small once the prerequisite is in hand.
|
|
|
|
---
|
|
|
|
## 3. The confirmed failure
|
|
|
|
### Stack trace (captured from a consuming app on navigation to the Users admin page)
|
|
|
|
```
|
|
System.InvalidOperationException: Cannot provide a value for property 'SaveContextHolder' on type
|
|
'Web.Maintenance.Entities.ModelView`5[[AuthBlocksModels.InputModels.UserInputModel, ...],
|
|
[AuthBlocksModels.Models.UserModel, ...],[AuthBlocksWeb.Components.Pages.UserAdmin.Users.UserEditModal, ...],
|
|
[AuthBlocksWeb.Components.Pages.UserAdmin.Users.UsersViewModel, ...],
|
|
[AuthBlocksModels.Converters.UserModelToInputConverter, ...]]'.
|
|
There is no registered service of type 'Web.Maintenance.Entities.EditModalSaveContextHolder'.
|
|
at Microsoft.AspNetCore.Components.ComponentFactory...CreatePropertyInjector...
|
|
```
|
|
|
|
`ModelView` declares `SaveContextHolder` as `required` with `[Inject]`, so Blazor's component factory
|
|
throws during component activation. There is no try/catch around component instantiation in the render path,
|
|
so the exception propagates and tears down the circuit. The user sees a dead page / "An unhandled error has
|
|
occurred" and must reload.
|
|
|
|
### Which AuthBlocks pages trigger it
|
|
|
|
`AuthBlocksWeb` ships two user-admin pages that render `<ModelView>`:
|
|
|
|
- `AuthBlocksWeb/Components/Pages/UserAdmin/Users/Users.razor`
|
|
- `AuthBlocksWeb/Components/Pages/UserAdmin/Registrations/Registrations.razor`
|
|
|
|
Any consumer that routes to either page hits the defect on first navigation.
|
|
|
|
---
|
|
|
|
## 4. Why this is AuthBlocks' gap to close (not the consumer's)
|
|
|
|
`AuthBlocksWeb/Startup.cs` exposes `ConfigureAuthServices(IServiceCollection, string apiBaseUrl)` — the
|
|
**single DI entry point** consumers call to light up the AuthBlocks Web surface. It already registers all
|
|
the user-admin viewmodels and clients (`UsersViewModel`, `RegistrationsViewModel`, `PermissionsViewModel`,
|
|
their clients, auth state, hierarchical authorization, etc.). It does **not** register
|
|
`EditModalSaveContextHolder` and does **not** call any BlazorBlocks Web extension.
|
|
|
|
So AuthBlocks ships pages that depend on `ModelView` while leaving one of `ModelView`'s required services
|
|
unregistered. The consumer is silently expected to fill the gap — and that is exactly what happened:
|
|
**two independent downstream products** each had to hand-register the internal BlazorBlocks service
|
|
(`AddScoped<Web.Maintenance.Entities.EditModalSaveContextHolder>()`) in their own `Program.cs` to make
|
|
AuthBlocks' shipped pages work. The whole value of a single `ConfigureAuthServices` entry point is that a
|
|
consumer calling it (plus the already-required `AddMudServices`) gets a working surface with zero manual
|
|
registrations. Today they don't. Closing this gap inside `ConfigureAuthServices` restores that promise.
|
|
|
|
Note: `IDialogService` / `ISnackbar` (also injected by `ModelView`) come from MudBlazor's
|
|
`AddMudServices()`, which every AuthBlocks Web consumer already calls as a documented prerequisite — those
|
|
are not the gap. The single library-owned gap is `EditModalSaveContextHolder`.
|
|
|
|
---
|
|
|
|
## 5. The fix
|
|
|
|
### 5.1 Bump the BlazorBlocks reference
|
|
|
|
Update the `Cerebellum.BlazorBlocks.Web` package reference (currently 10.3.32) to the new version
|
|
BlazorBlocks publishes for this fix (see §2 — fill in the exact version). This is what makes
|
|
`AddBlazorBlocksWeb()` available.
|
|
|
|
### 5.2 Call the extension from `ConfigureAuthServices`
|
|
|
|
```csharp
|
|
// AuthBlocksWeb/Startup.cs, inside ConfigureAuthServices(...)
|
|
services.AddBlazorBlocksWeb(); // registers EditModalSaveContextHolder for the ModelView-based pages
|
|
```
|
|
|
|
Order does not matter for this scoped service; place it near the other registrations. The
|
|
`AddBlazorBlocksWeb()` extension registers `EditModalSaveContextHolder` as scoped per circuit (its correct
|
|
lifetime — the holder is per-circuit mutable state that `ModelView` writes and `EditModelModal` reads).
|
|
|
|
### 5.3 Why this belongs in `ConfigureAuthServices`, not pushed onto consumers
|
|
|
|
- `ConfigureAuthServices` is AuthBlocks' **single DI entry point**. A consumer calling only
|
|
`AddMudServices()` + `ConfigureAuthServices(...)` should get a fully working user-admin surface. Folding
|
|
the BlazorBlocks call into the existing entry point keeps that promise; introducing a second method the
|
|
consumer must remember to call (or expecting them to call `AddBlazorBlocksWeb()` themselves) just relocates
|
|
the leaked registration one layer up.
|
|
- AuthBlocks must **not** register `EditModalSaveContextHolder` directly (reaching into BlazorBlocks'
|
|
internal `Web.Maintenance.Entities` namespace) — that is the same smell the two consumers exhibited,
|
|
merely relocated. Compose BlazorBlocks' own `Add*` extension instead; the registration lives with its
|
|
owner, and AuthBlocks stays self-contained by calling it. This is the standard ASP.NET Core layering:
|
|
each library exposes an `Add*` for its own services, and a higher-level library's `Add*` calls the lower
|
|
one's.
|
|
|
|
---
|
|
|
|
## 6. Constraints
|
|
|
|
- **Do not register `EditModalSaveContextHolder` directly** in AuthBlocks. Call `AddBlazorBlocksWeb()`;
|
|
let BlazorBlocks own its type (§5.3).
|
|
- **Keep `ConfigureAuthServices` the single AuthBlocks entry point.** Do not introduce a second method
|
|
consumers must remember to call; fold the BlazorBlocks call into the existing one.
|
|
- **MudBlazor remains a caller-owned prerequisite.** AuthBlocks already relies on consumers calling
|
|
`AddMudServices()` for all its MudBlazor-based pages; do not absorb it into `ConfigureAuthServices`.
|
|
- **Versioning:** AuthBlocks Web packs/pushes via its `pack.ps1` / packaging script. `AuthBlocksWeb` is
|
|
currently `Cerebellum.AuthBlocks.Web` **10.3.33**; bump to the next version after referencing the new
|
|
BlazorBlocks version and adding the `AddBlazorBlocksWeb()` call. **Record the new version** so consumers
|
|
can pin.
|
|
|
|
---
|
|
|
|
## 7. Acceptance criteria
|
|
|
|
1. The `Cerebellum.BlazorBlocks.Web` package reference is bumped to the new version BlazorBlocks published
|
|
for this fix, and `ConfigureAuthServices` calls `AddBlazorBlocksWeb()`.
|
|
2. A fresh consumer that calls **only** `AddMudServices()` and
|
|
`AuthBlocksWeb.Startup.ConfigureAuthServices(...)` — and **registers nothing else by hand** — can
|
|
navigate to the Users admin page and the Registrations admin page with **no `InvalidOperationException`**
|
|
and **no circuit teardown**.
|
|
3. Working behavior means not just page load: opening the edit dialog on a user, saving a valid change,
|
|
**succeeds** — i.e. the save bridge actually works end-to-end through AuthBlocks' pages.
|
|
4. No AuthBlocks consumer needs to touch `Web.Maintenance.Entities` directly; no manual registrations are
|
|
required beyond the documented `AddMudServices`.
|
|
5. `AuthBlocksWeb` is published as a version bump from 10.3.33, and the new version number is recorded.
|
|
|
|
---
|
|
|
|
## 8. Open questions for the implementing team / its sponsor
|
|
|
|
1. **Exact BlazorBlocks version to reference.** Pending the BlazorBlocks team's publish (§2). Confirm the
|
|
published version number and the exact extension method name (proposed `AddBlazorBlocksWeb()`) before
|
|
landing the call.
|
|
2. **Placement within `ConfigureAuthServices`.** Anywhere in the method works (scoped service, order-
|
|
independent). Confirm there is no existing convention in `Startup.cs` for grouping third-party `Add*`
|
|
calls that this should follow.
|
|
3. **Any other AuthBlocks pages built on `ModelView`/`NewModelView`?** This brief identified Users and
|
|
Registrations. If the team expects to add more maintenance pages, note that calling `AddBlazorBlocksWeb()`
|
|
once covers them all (it is the single home for the maintenance-component deps).
|
|
|
|
---
|
|
|
|
## 9. Suggested reading order in the repo
|
|
|
|
1. `AuthBlocksWeb/Startup.cs` — `ConfigureAuthServices`, the single entry point; add the
|
|
`AddBlazorBlocksWeb()` call here.
|
|
2. `AuthBlocksWeb/Components/Pages/UserAdmin/Users/Users.razor` — renders `<ModelView>`; triggers the
|
|
defect on navigation.
|
|
3. `AuthBlocksWeb/Components/Pages/UserAdmin/Registrations/Registrations.razor` — the second page that
|
|
renders `<ModelView>`.
|
|
4. The AuthBlocks Web `.csproj` — the `Cerebellum.BlazorBlocks.Web` package reference to bump.
|
|
5. The AuthBlocks `pack.ps1` / packaging script — to bump and publish `AuthBlocksWeb` after referencing the
|
|
new BlazorBlocks version.
|
|
|
|
---
|
|
|
|
## 10. Cross-team ordering (important — you ship second)
|
|
|
|
This fix is layered across two repos and **must land in order**:
|
|
|
|
1. **BlazorBlocks ships first.** It adds `AddBlazorBlocksWeb()`, bumps `Cerebellum.BlazorBlocks.Web` from
|
|
10.3.32, packs/pushes, and reports the new version number.
|
|
2. **Then AuthBlocks (this team)** bumps its `Cerebellum.BlazorBlocks.Web` reference to that published
|
|
version, calls `AddBlazorBlocksWeb()` from `ConfigureAuthServices`, bumps `Cerebellum.AuthBlocks.Web` from
|
|
10.3.33, and publishes.
|
|
|
|
This team **cannot complete its part until the BlazorBlocks version is published** (§2). Confirm that
|
|
version number is in hand before starting.
|