Upgrade AdHocReporting.BlazorWasm (Server/Client/Shared) to .NET 8#37
Upgrade AdHocReporting.BlazorWasm (Server/Client/Shared) to .NET 8#37devin-ai-integration[bot] wants to merge 5 commits into
Conversation
- Bump TargetFramework to net8.0 on all three projects
- Replace Microsoft.AspNetCore.ApiAuthorization.IdentityServer (removed in
.NET 8) with ASP.NET Core Identity cookie auth (AddDefaultIdentity +
Identity UI Razor Pages)
- Drop ApiAuthorizationDbContext for IdentityDbContext<ApplicationUser>
- Remove OidcConfigurationController (depended on removed package)
- Remove RemoteAuthenticatorView/SignOutSessionStateManager usage on the
client (obsolete in .NET 8); redirect /authentication/{action} to the
Identity Razor Pages
- Bump Microsoft.EntityFrameworkCore.* to 8.0.11
- Bump Microsoft.AspNetCore.Components.WebAssembly.* to 8.0.11
- Bump Microsoft.AspNetCore.Identity.* to 8.0.11
- Bump Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore to 8.0.11
- Add Microsoft.AspNetCore.Authentication.JwtBearer 8.0.11
- Bump Microsoft.Data.SqlClient to 5.2.2
- Bump Microsoft.IdentityModel.JsonWebTokens / System.IdentityModel.Tokens.Jwt to 7.6.0
- Remove Microsoft.VisualStudio.Web.CodeGeneration.Design,
System.Data.SqlClient, System.Net.Http, System.Text.RegularExpressions,
System.Drawing.Common (no longer needed; provided by .NET 8 BCL)
Co-Authored-By: Toby Drinkall <toby.drinkall@cognition.ai>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
… decouple Reports.razor from IAccessTokenProviderAccessor - Add EqDemo.Client.HostAuthenticationStateProvider that resolves auth state by calling a small /_auth/me endpoint on the server (which is authenticated via the ASP.NET Core Identity cookie). This restores the AuthenticationStateProvider DI registration that was previously provided by AddApiAuthorization() so <CascadingAuthenticationState> resolves at runtime. - Register HostAuthenticationStateProvider in Client/Program.cs alongside AddAuthorizationCore(). - Add /_auth/me minimal API endpoint in Server/Program.cs that returns the current cookie-authenticated user's claims. - Update Client/Pages/Reports.razor to drop the OIDC-only IAccessTokenProviderAccessor dependency. With cookie auth the auth cookie is sent automatically with same-origin requests, so no bearer token is needed for the EasyQuery JS bootstrap. Co-Authored-By: Toby Drinkall <toby.drinkall@cognition.ai>
…ink to avoid anti-forgery 400 The Blazor WASM client cannot inject Razor Pages anti-forgery tokens, so a direct POST to Identity/Account/Logout fails with 400 Bad Request. Use a plain <a> link to the server-rendered logout page instead — the page's own form has the anti-forgery token and signs the user out on click. Co-Authored-By: Toby Drinkall <toby.drinkall@cognition.ai>
…} and pass relative ReturnUrl
- LoginDisplay.razor: revert href values to authentication/{login|logout|
register|profile}. Plain absolute Identity/Account/* hrefs are
intercepted by Blazor's client-side Router and rendered as <NotFound>;
routing through Authentication.razor (which forceLoad-redirects to the
Identity Razor Pages) gives a real full-page navigation.
- RedirectToLogin.razor: pass PathAndQuery (relative) as ReturnUrl
instead of the full absolute URI, otherwise Login.cshtml's
LocalRedirect/IsLocalUrl rejects the value and throws after a
successful login.
Co-Authored-By: Toby Drinkall <toby.drinkall@cognition.ai>
AddDefaultIdentity<TUser>() registers UserClaimsPrincipalFactory<TUser>
via TryAddScoped, so the role-aware factory that AddRoles<IdentityRole>()
tries to register is silently dropped. Explicitly register
UserClaimsPrincipalFactory<ApplicationUser, IdentityRole> after
AddEntityFrameworkStores so User.IsInRole("eq-manager") is honoured both
in /_auth/me and in EasyQuery's auth provider.
Co-Authored-By: Toby Drinkall <toby.drinkall@cognition.ai>
Test report — cookie-auth + role projection verified end-to-endRan the upgraded Server project on .NET 8 SDK 8.0.420 locally ( Escalation (pre-existing, not a regression from this PR)
Results
Load-bearing assertion: role claims actually land in the cookie
Captured DOM of <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<a class="dropdown-item" id="NewReportButton" href="javascript:void(0)">New report</a>
<a class="dropdown-item" id="SaveReportButton" href="javascript:void(0)">Save as...</a>
<a class="dropdown-item" id="RemoveReportButton" href="javascript:void(0)">Remove report</a>
</div>
DB confirms Screenshots
The center screenshot's full-page "No license key for EasyQuery" overlay is pre-existing demo behaviour — Happy to do a follow-up for the |



Summary
Upgrades the three Blazor WebAssembly AdHocReporting sample projects from .NET 6 to .NET 8 and replaces the
Microsoft.AspNetCore.ApiAuthorization.IdentityServerauth stack (removed in .NET 8) with the standard ASP.NET Core Identity cookie auth (Razor Pages UI) shipped inMicrosoft.AspNetCore.Identity.UI.Projects modified
AspNetCore/Blazor/AdHocReporting.BlazorWasm/Server/EqDemo.BlazorWasm.AdhocReporting.Server.csprojnet6.0→net8.0AspNetCore/Blazor/AdHocReporting.BlazorWasm/Client/EqDemo.BlazorWasm.AdhocReporting.Client.csprojnet6.0→net8.0AspNetCore/Blazor/AdHocReporting.BlazorWasm/Shared/EqDemo.BlazorWasm.AdhocReporting.Shared.csprojnet6.0→net8.0Server (
Server/EqDemo.BlazorWasm.AdhocReporting.Server.csproj)Microsoft.AspNetCore.Components.WebAssembly.Server6.0.18.0.11Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore6.0.18.0.11Microsoft.AspNetCore.Identity.EntityFrameworkCore6.0.18.0.11Microsoft.AspNetCore.Identity.UI6.0.18.0.11Microsoft.EntityFrameworkCore.Tools6.0.18.0.11Microsoft.EntityFrameworkCore.SqlServer6.0.18.0.11Microsoft.EntityFrameworkCore.Sqlite6.0.18.0.11Microsoft.AspNetCore.Authentication.JwtBearer8.0.11Microsoft.Data.SqlClient2.1.75.2.2Microsoft.IdentityModel.JsonWebTokens6.34.07.6.0System.IdentityModel.Tokens.Jwt6.34.07.6.0Microsoft.AspNetCore.ApiAuthorization.IdentityServer6.0.1Microsoft.VisualStudio.Web.CodeGeneration.Design6.0.1System.Data.SqlClient4.8.6System.Drawing.Common4.7.2System.Net.Http4.3.4System.Text.RegularExpressions4.3.1Korzh.* / EasyData / NuGet.* packages are unchanged per the upgrade scope.
Client (
Client/EqDemo.BlazorWasm.AdhocReporting.Client.csproj)Microsoft.AspNetCore.Components6.0.258.0.11Microsoft.AspNetCore.Components.WebAssembly6.0.18.0.11Microsoft.AspNetCore.Components.WebAssembly.DevServer6.0.18.0.11Microsoft.AspNetCore.Components.WebAssembly.Authentication6.0.18.0.11Microsoft.Extensions.Http6.0.08.0.1Shared (
Shared/EqDemo.BlazorWasm.AdhocReporting.Shared.csproj)TFM bump only (
net6.0→net8.0); no package references.Code changes
Server
Server/Program.cs— removedAddIdentityServer().AddApiAuthorization<…>(…),AddAuthentication().AddIdentityServerJwt(),app.UseIdentityServer(), and theJwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role")line that supported the IdentityServer JWT pipeline. Cookie-based auth viaAddDefaultIdentity<ApplicationUser>is now the sole auth provider.Server/Program.cs— explicitly registeredUserClaimsPrincipalFactory<ApplicationUser, IdentityRole>afterAddEntityFrameworkStores<AppDbContext>().AddIdentityCore(called insideAddDefaultIdentity) pre-registers the role-blindUserClaimsPrincipalFactory<TUser>viaTryAddScoped, which silently wins over the role-aware factory thatAddRoles<IdentityRole>()tries to add — without this overrideUser.IsInRole("eq-manager")would always befalse, breaking theReports.razormanager-only UI and any server-side EasyQuery role checks.Server/Program.cs— added a smallapp.MapGet("/_auth/me", ...)minimal API endpoint that returns the current cookie-authenticated user's claims as JSON. The Blazor WASM client'sHostAuthenticationStateProviderconsumes this to populate the<CascadingAuthenticationState>/<AuthorizeView>cascade.Server/Data/AppDbContext.cs— switched the base class fromApiAuthorizationDbContext<ApplicationUser>(provided by the removedMicrosoft.AspNetCore.ApiAuthorization.IdentityServer/Duende.IdentityServer.EntityFramework.Options) toIdentityDbContext<ApplicationUser>fromMicrosoft.AspNetCore.Identity.EntityFrameworkCore. Constructor signature simplified to takeDbContextOptions<AppDbContext>.Server/Controllers/OidcConfigurationController.cs— deleted. The controller existed solely to expose IdentityServer client config viaIClientRequestParametersProvider; that type lives in the removed package.Server/appsettings.json— removed theIdentityServer.Clientsblock (no longer read).Client
Client/Program.cs— removedBaseAddressAuthorizationMessageHandlerregistration andAddApiAuthorization()(the OIDC client flow no longer has a backend to talk to); replaced withAddAuthorizationCore()plus a customAuthenticationStateProviderregistration so<CascadingAuthenticationState>,<AuthorizeRouteView>, and<AuthorizeView>continue to resolve at runtime.Client/HostAuthenticationStateProvider.cs— new file. Resolves the current user's auth state by GETing/_auth/me(sent with the Identity cookie, since same-origin) and projecting the returned claims into aClaimsPrincipal. Returns anonymous on 401/403/network errors. This replaces the OIDCRemoteAuthenticationService-backed provider that previously came withAddApiAuthorization().Client/Pages/Authentication.razor— removedRemoteAuthenticatorView(which depended on the OIDCRemoteAuthenticationService) and replaced with a small redirect that maps the legacy/authentication/{login,register,logout,profile}URLs onto theIdentity/Account/{Login,Register,Logout,Manage}Razor Pages viaNavigationManager.NavigateTo(..., forceLoad: true).Client/Shared/LoginDisplay.razor— kept the originalauthentication/{action}hrefs (rather than linking directly toIdentity/Account/...) so they route throughAuthentication.razorand trigger aforceLoadserver-side navigation. Plain<a>links toIdentity/Account/...would otherwise be intercepted by Blazor WASM's client-sideRouterand rendered as<NotFound>. Also removed theSignOutSessionStateManagerdependency (deprecated in .NET 7, removed in .NET 8).Client/Shared/RedirectToLogin.razor— points unauthorized users atIdentity/Account/Login?ReturnUrl=...(withforceLoad: true). TheReturnUrlisnew Uri(Navigation.Uri).PathAndQuery(relative path) soLogin.cshtml.cs'sLocalRedirect(returnUrl)/IsLocalUrl()accepts it after a successful login.Client/Pages/Reports.razor— dropped theIAccessTokenProviderAccessorandMicrosoft.AspNetCore.Components.WebAssembly.Authentication/.Internaldependencies. Cookie auth means the browser sends the auth cookie automatically with every same-origin request, soeasyquery.blazor.startAdhocReporting(...)is invoked without a bearer token. The role-gated UI still works via the newHostAuthenticationStateProvider.These changes keep the auth surface compatible enough that the project builds and the cookie-based login/register/logout flow continues to work via the existing Identity UI Razor Pages.
Build commands & results
Run from
AspNetCore/Blazor/AdHocReporting.BlazorWasm/with .NET SDK 8.0.420 (Linux x64):Result:
Build succeeded. 0 Warning(s) 0 Error(s)Build succeeded. 0 Warning(s) 0 Error(s)Build succeeded. 2 Warning(s) 0 Error(s)The two Server warnings are both
NU1901advisories onNuGet.Protocol 5.11.5, which is out of the upgrade scope (the prompt explicitly says "Do NOT bump unrelated dependencies just because newer versions exist"). They are unrelated to the .NET 8 upgrade itself.CI
Devin Review— flagged 5 functional issues during review; all addressed in follow-up commits and replied to in-thread (missingAuthenticationStateProvider, Reports.razorIAccessTokenProviderAccessorusage, anti-forgery POST issue, Blazor router intercepting Identity/Account/* links, missing role claims in cookie).security/snyk (Cognition-default)— failed (3 tests have failed). The Snyk dashboard requires authenticated access I do not have. The same Snyk failure mode appears on the parallel net8 upgrade PRs in this repo (e.g. PR chore(net8): upgrade AspNetCore/Vue2/AdvancedSearch to .NET 8 #35 noted the identical issue), so this looks like a pre-existing repo-wide Snyk configuration issue, not a regression introduced by this PR. This PR actually removes several historically vulnerable packages (System.Drawing.Common 4.7.2,System.Net.Http 4.3.4,System.Text.RegularExpressions 4.3.1,System.Data.SqlClient 4.8.6) and bumpsMicrosoft.Data.SqlClientto a fully patched 5.2.2.license/snyk (Cognition-default)— failed (3 tests have failed). Same situation as security/snyk above; flagging for human review since dashboard access is needed to see the specifics.Review & Testing Checklist for Human
This is a yellow-risk change (.NET 8 framework bump plus replacing the entire IdentityServer auth stack with cookie auth). Please verify:
dotnet build -c Releasesucceeds against all three projects on a clean checkout (with the .NET 8 SDK installed).Registerlink → log in → verify<AuthorizeView>flips toAuthorized(the LoginDisplay shows the username and a "Log out" link), and/reportsno longer redirects to login.eq-manager(or seed one) and confirm the "New report / Save as / Remove report" dropdown items become enabled. Without the explicit role-aware claims factory registration inServer/Program.cs, this would silently always be disabled — please confirm it actually works end-to-end.MapEasyQuery(...)endpoints (/api/adhoc-reporting/...) are reachable from the Blazor client and that the cookie-basedUserprincipal is correctly populated server-side.master) or actually introduced by this PR.Test plan recommendation:
dotnet run --project AspNetCore/Blazor/AdHocReporting.BlazorWasm/Serverto launch the demo against the bundled SQLite database.Server/Areas/Identity/Pages/Account/Register.cshtml.csstill adds the user to theeq-managerrole on first registration (it did pre-upgrade), verify the manager-only menu items are enabled on/reports./reportsredirects to login again.Notes
AspNetCore/Blazor/AdHocReporting.BlazorWasm/.global.json/Directory.Build.propswere added at the repo root (out of scope; owned by Session 7)..slnfiles were edited.IdentityServerconfig block inServer/appsettings.jsonwas removed because nothing reads it anymore.Microsoft.IdentityModel.JsonWebTokensandSystem.IdentityModel.Tokens.Jwtare pinned to7.6.0per the prompt's "latest stable 7.x" guidance.Link to Devin session: https://app.devin.ai/sessions/4209388e71e3468985471646a9440b95
Requested by: @tobydrinkall
Devin Review