feat(blazor): Add navigation breadcrumbs for Blazor WebAssembly#4907
feat(blazor): Add navigation breadcrumbs for Blazor WebAssembly#4907bruno-garcia merged 8 commits intomainfrom
Conversation
Subscribe to NavigationManager.LocationChanged to automatically create navigation breadcrumbs with type/category "navigation" and from/to relative paths, matching the JS SDK behavior. Also keeps scope.Request.Url updated with the current route. Closes #4906 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Semver Impact of This PR⚪ None (no version bump detected) 📋 Changelog PreviewThis is how your changes will appear in the changelog. Features ✨
Dependencies ⬆️Deps
Other
🤖 This preview updates automatically when you update the PR. |
|
test/Sentry.AspNetCore.Blazor.WebAssembly.Tests/BlazorWasmOptionsSetupTests.cs
Outdated
Show resolved
Hide resolved
src/Sentry.AspNetCore.Blazor.WebAssembly/Internal/BlazorWasmOptionsSetup.cs
Outdated
Show resolved
Hide resolved
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4907 +/- ##
==========================================
- Coverage 73.85% 73.85% -0.01%
==========================================
Files 494 496 +2
Lines 17868 17921 +53
Branches 3509 3510 +1
==========================================
+ Hits 13197 13236 +39
- Misses 3815 3824 +9
- Partials 856 861 +5 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…empty message - BlazorWasmOptionsSetup now takes IHub via an internal constructor (defaults to HubAdapter.Instance in production). This allows tests to inject a mock hub instead of relying on SentrySdk global state. - Use the internal Breadcrumb constructor with message: null instead of sending message: "" (matching JS SDK which omits the message property). - Add InternalsVisibleTo from Sentry to the Blazor WASM project. - Rewrite tests to use NSubstitute IHub + real Scope (following MAUI test patterns) instead of SentrySdk.Init(). - Add test verifying breadcrumb message is null. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add the test project to the solution and regenerate all .slnf files so CI test-solution-filters passes. Add changelog entry for the navigation breadcrumbs feature. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds automatic navigation breadcrumb tracking to the Blazor WebAssembly integration so Sentry captures SPA route transitions similarly to the JavaScript SDK, and keeps scope.Request.Url aligned with the current route.
Changes:
- Introduces
BlazorWasmOptionsSetupto subscribe toNavigationManager.LocationChanged, emittype/category: "navigation"breadcrumbs with{ from, to }, and updatescope.Request.Url. - Registers the options setup in
WebAssemblyHostBuilderExtensions.UseSentry(). - Adds a new WASM test project with unit tests validating breadcrumb shape and URL updates.
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
src/Sentry.AspNetCore.Blazor.WebAssembly/Internal/BlazorWasmOptionsSetup.cs |
Implements LocationChanged subscription, breadcrumb creation, and scope.Request.Url updates. |
src/Sentry.AspNetCore.Blazor.WebAssembly/WebAssemblyHostBuilderExtensions.cs |
Registers the options setup in DI when UseSentry() is called. |
test/Sentry.AspNetCore.Blazor.WebAssembly.Tests/* |
Adds unit tests and a FakeNavigationManager for navigation simulation. |
src/Sentry/Sentry.csproj |
Grants internals access to the Blazor WASM assembly (needed for internal breadcrumb ctor usage). |
CHANGELOG.md |
Documents the new Blazor WASM navigation breadcrumb feature. |
*.slnf, Sentry.sln, .generated.NoMobile.sln |
Includes the new test project in solution/filters. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
test/Sentry.AspNetCore.Blazor.WebAssembly.Tests/FakeNavigationManager.cs
Outdated
Show resolved
Hide resolved
test/Sentry.AspNetCore.Blazor.WebAssembly.Tests/FakeNavigationManager.cs
Outdated
Show resolved
Hide resolved
src/Sentry.AspNetCore.Blazor.WebAssembly/Internal/BlazorWasmOptionsSetup.cs
Show resolved
Hide resolved
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 3 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
src/Sentry.AspNetCore.Blazor.WebAssembly/Internal/BlazorWasmOptionsSetup.cs
Show resolved
Hide resolved
src/Sentry.AspNetCore.Blazor.WebAssembly/Internal/BlazorWasmOptionsSetup.cs
Show resolved
Hide resolved
src/Sentry.AspNetCore.Blazor.WebAssembly/Internal/BlazorWasmOptionsSetup.cs
Show resolved
Hide resolved
- Remove unused using and hidden NavigateTo method in FakeNavigationManager - Add ArgumentNullException.ThrowIfNull(options) for consistency - Add _initialized guard to prevent duplicate event handlers Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Review Comments Summary
All fixes are in commit 11ada43. |
jamescrosswell
left a comment
There was a problem hiding this comment.
The PR looks good. I had a question about thread safety on the IConfigureOptions... maybe this is a non-concern in WASM apps though.
There was a problem hiding this comment.
FYI: We don't strictly require a changelog entry anymore - it should get generated automatically from the commit description since #4896
There was a problem hiding this comment.
Do I need to remove it? it's already there
There was a problem hiding this comment.
Nah you can leave it in... it would be generated automatically for the PR (from the title) when making a release otherwise. Just FYI that you don't need to add this anymore.
src/Sentry.AspNetCore.Blazor.WebAssembly/Internal/BlazorWasmOptionsSetup.cs
Show resolved
Hide resolved
| { | ||
| return; | ||
| } | ||
| _initialized = true; |
There was a problem hiding this comment.
Is there a potential race condition here? Does this need to be thread safe?
I think IOptions<T> gets evaluated lazily the first time it's requested... so if multiple requests hit the server concurrently after it starts, you could get two threads checking it _initialized is true, seeing that they're not and then setting up duplicate event handlers (resulting in duplicate breadcrumbs).
Better to use Interlocked.Exchange?
But if this is all compiling down to WASM, maybe there are no threads? There are none in javascript - I assume WASM is the same? @Flash0ver this sounds like your area of expertise...
edit: Turns out .NET does have experimental support for threading in WASM... maybe we use Interlocked here just to be on the safe side then (even though it might not be strictly required)? I think for navigation events in particular, it's extremely unlikely to cause problems, so not pushing super hard for this.
There was a problem hiding this comment.
This runs single threaded, since it runs on the main thread when the app starts up
There was a problem hiding this comment.
I'm a bit uncertain if this is (or may be) an issue,
but considering that the change using our InterlockedBoolean is both cheap in runtime and maintenance (would result in less code, actually),
I vote for a thread-safe guard here using our internal InterlockedBoolean.
| var from = ToRelativePath(previousUrl); | ||
| var to = ToRelativePath(args.Location); | ||
|
|
||
| _hub.AddBreadcrumb( |
There was a problem hiding this comment.
note: @Flash0ver
- update docs(dotnet): override automatic-breadcrumbs sentry-docs#16330 after merge
| _hub.ConfigureScope(scope => | ||
| { | ||
| scope.Request.Url = to; | ||
| }); |
There was a problem hiding this comment.
suggestion: we could avoid the closure here, as to is already a string-ified relative path, by passing it as "state"
| blazorOptions.IsGlobalModeEnabled = true; | ||
| }); | ||
|
|
||
| builder.Services.AddSingleton<IConfigureOptions<SentryBlazorOptions>, BlazorWasmOptionsSetup>(); |
There was a problem hiding this comment.
issue: with that change, Sentry.Samples.AspNetCore.Blazor.Wasm doesn't fully initialize any longer and just hangs
There was a problem hiding this comment.
however, the Unit Tests and Playwright Tests (#4908) do pass
Summary
navigationbreadcrumbs when users navigate between pages in a Blazor WebAssembly apptype: "navigation",category: "navigation", anddata: { from, to }with relative paths — matching the JS SDK behavior so the Sentry UI renders the navigation icon and from/to display correctlyscope.Request.Urlupdated with the current routeCloses #4906
Implementation
BlazorWasmOptionsSetup(IConfigureOptions<SentryBlazorOptions>) injectsNavigationManager, subscribes toLocationChanged, and creates breadcrumbs on each navigationWebAssemblyHostBuilderExtensions.UseSentry()NavigationManager.ToBaseRelativePath()to convert absolute URLs to relative paths (prepending/to match JS SDK format)Test plan
scope.Request.Urlis set correctly (root and with path)typeandcategoryfrom/tovalues are relative pathsscope.Request.Urlis updated on navigationfromcorrectly (previous → current)from🤖 Generated with Claude Code