Skip to content

Improve Blazor reconnection experience after the server is restarted#8

Open
tomerqodo wants to merge 7 commits intocoderabbit_only-issues-20260113-coderabbit_base_improve_blazor_reconnection_experience_after_the_server_is_restarted_pr32from
coderabbit_only-issues-20260113-coderabbit_head_improve_blazor_reconnection_experience_after_the_server_is_restarted_pr32
Open

Improve Blazor reconnection experience after the server is restarted#8
tomerqodo wants to merge 7 commits intocoderabbit_only-issues-20260113-coderabbit_base_improve_blazor_reconnection_experience_after_the_server_is_restarted_pr32from
coderabbit_only-issues-20260113-coderabbit_head_improve_blazor_reconnection_experience_after_the_server_is_restarted_pr32

Conversation

@tomerqodo
Copy link

@tomerqodo tomerqodo commented Jan 16, 2026

Benchmark PR from qodo-benchmark#32

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Improved reconnection behavior when server-side state is unavailable; client-side logic now handles these scenarios.
    • Enhanced reconnect modal messaging and button visibility during reconnection and resume-failure states.
  • Tests

    • Added end-to-end tests for reconnection scenarios without server-side state preservation.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 16, 2026

Walkthrough

The changes modify circuit reconnection behavior when persisted state is unavailable. Instead of notifying the client and aborting the connection, the server now logs the condition and returns null. Client-side reconnection and display logic adapts to handle resume failures without forcing page reloads, delegating recovery to client reconnection mechanisms.

Changes

Cohort / File(s) Summary
Server Circuit State Handling
src/Components/Server/src/ComponentHub.cs
Removes client notification and connection abort when resumed persisted circuit state is null; logs invalid input and returns null instead.
Server Circuit Tests
src/Components/Server/test/Circuits/ComponentHubTest.cs
Removes assertion verifying error notification to client in CannotResumeAppWhenPersistedComponentStateIsNotAvailable test; only asserts null result.
Server Configuration
src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsStartup.cs
Adds conditional branch to disable in-memory persisted circuit retention when DisableCircuitPersistence is true, setting PersistedCircuitInMemoryMaxRetained to 0.
Client Reconnection Display Logic
src/Components/Web.JS/src/Platform/Circuits/DefaultReconnectDisplay.ts
Updates show/update/failed methods: hides resume button in initial state, hides both buttons on reconnecting, removes animation hiding on pause, conditionally shows resume button on failed state based on reconnecting context.
Client Reconnection Handler
src/Components/Web.JS/src/Platform/Circuits/DefaultReconnectionHandler.ts
Removes pause state update before resume attempt; proceeds directly to resume handling after failed reconnect.
Client Display State Tracking
src/Components/Web.JS/src/Platform/Circuits/UserSpecifiedDisplay.ts
Makes reconnect field public with default value true; introduces public remote boolean field; updates pause/failure event payloads to use and track remote state.
Blazor Template Reconnect UI
src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Components/Layout/ReconnectModal.razor
Adds components-resume-failed-visible class to pause-state resume button; updates resume failure message from "Please reload the page." to "Please retry or reload the page.".
Blazor Template Reconnect Logic
src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Components/Layout/ReconnectModal.razor.js
Changes resume failure handling to update modal class to components-reconnect-resume-failed instead of reloading page.
Reconnection E2E Tests
src/Components/test/E2ETest/ServerExecutionTests/ServerReconnectionWithoutStateTest.cs
Adds new test suite with ServerReconnectionWithoutStateTest and ServerReconnectionWithoutStateCustomUITest classes; includes tests for page reload validation after disconnection and resume capability across pause/reconnect cycles without server state.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant ReconnHandler as Reconnection<br/>Handler
    participant Server as ComponentHub
    participant Display as Reconnect<br/>Display
    
    Client->>ReconnHandler: Reconnect attempt
    ReconnHandler->>Server: Resume circuit
    Server-->>ReconnHandler: Returns null<br/>(no state available)
    ReconnHandler->>Display: Handle resume failure
    Display->>Display: Update UI state<br/>(show resume button)
    Display-->>Client: Display resume/retry option<br/>(no page reload)
    Client->>ReconnHandler: User clicks resume
    ReconnHandler->>Server: Retry resume
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A circuit reconnected, no state to restore,
We log and we pause, then let clients explore,
Resume buttons gleam where failures once failed,
With grace, not a crash, the connection prevailed! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description is significantly incomplete. It lacks required sections including a detailed summary of changes, description/detail, and the bug/issue reference format. It only provides a brief benchmark PR reference without substantive detail. Provide a proper description following the template: include a summary of changes under 80 characters, a detailed Description section explaining the reconnection improvements, and reference the related issue using the 'Fixes #{bug number}' format.
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main objective of the changeset—improving Blazor reconnection experience after server restart—which is reflected in the code changes across multiple components.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@src/Components/test/E2ETest/ServerExecutionTests/ServerReconnectionWithoutStateTest.cs`:
- Around line 61-64: The staleness check currently calls the extension
property/method IsStale directly which won't compile; change the wait assertion
to pass a lambda that evaluates initialElement.IsStale (e.g., Browser.True(() =>
initialElement.IsStale)) so the check is deferred and executed inside the wait;
locate the assertion using Browser.True and initialElement.IsStale in
ServerReconnectionWithoutStateTest and wrap the IsStale invocation in a lambda
expression.
🧹 Nitpick comments (1)
src/Components/Server/src/ComponentHub.cs (1)

319-323: Consider a more specific log for expected expired/evicted state.
InvalidInputData might read as client fault even though this is an expected expiration path. A dedicated log message could reduce noise.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c9d0750 and f287efa.

📒 Files selected for processing (9)
  • src/Components/Server/src/ComponentHub.cs
  • src/Components/Server/test/Circuits/ComponentHubTest.cs
  • src/Components/Web.JS/src/Platform/Circuits/DefaultReconnectDisplay.ts
  • src/Components/Web.JS/src/Platform/Circuits/DefaultReconnectionHandler.ts
  • src/Components/Web.JS/src/Platform/Circuits/UserSpecifiedDisplay.ts
  • src/Components/test/E2ETest/ServerExecutionTests/ServerReconnectionWithoutStateTest.cs
  • src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsStartup.cs
  • src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Components/Layout/ReconnectModal.razor
  • src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Components/Layout/ReconnectModal.razor.js
💤 Files with no reviewable changes (2)
  • src/Components/Server/test/Circuits/ComponentHubTest.cs
  • src/Components/Web.JS/src/Platform/Circuits/DefaultReconnectionHandler.ts
🧰 Additional context used
🧬 Code graph analysis (1)
src/Components/test/E2ETest/ServerExecutionTests/ServerReconnectionWithoutStateTest.cs (3)
src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsStartup.cs (2)
  • RazorComponentEndpointsStartup (22-309)
  • RazorComponentEndpointsStartup (24-27)
src/Shared/E2ETesting/WaitAssert.cs (1)
  • Click (83-87)
src/Components/test/E2ETest/Infrastructure/WebDriverExtensions/WebDriverExtensions.cs (1)
  • IsStale (122-133)
🪛 ast-grep (0.40.5)
src/Components/Web.JS/src/Platform/Circuits/DefaultReconnectDisplay.ts

[warning] 135-135: Direct HTML content assignment detected. Modifying innerHTML, outerHTML, or using document.write with unsanitized content can lead to XSS vulnerabilities. Use secure alternatives like textContent or sanitize HTML with libraries like DOMPurify.
Context: this.status.innerHTML = 'Failed to rejoin.
Please retry or reload the page.'
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://www.dhairyashah.dev/posts/why-innerhtml-is-a-bad-idea-and-how-to-avoid-it/
- https://cwe.mitre.org/data/definitions/79.html

(unsafe-html-content-assignment)


[warning] 138-138: Direct HTML content assignment detected. Modifying innerHTML, outerHTML, or using document.write with unsanitized content can lead to XSS vulnerabilities. Use secure alternatives like textContent or sanitize HTML with libraries like DOMPurify.
Context: this.status.innerHTML = 'Failed to resume the session.
Please retry or reload the page.'
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://www.dhairyashah.dev/posts/why-innerhtml-is-a-bad-idea-and-how-to-avoid-it/
- https://cwe.mitre.org/data/definitions/79.html

(unsafe-html-content-assignment)


[warning] 135-135: Direct modification of innerHTML or outerHTML properties detected. Modifying these properties with unsanitized user input can lead to XSS vulnerabilities. Use safe alternatives or sanitize content first.
Context: this.status.innerHTML = 'Failed to rejoin.
Please retry or reload the page.'
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://owasp.org/www-community/xss-filter-evasion-cheatsheet
- https://cwe.mitre.org/data/definitions/79.html

(dom-content-modification)


[warning] 138-138: Direct modification of innerHTML or outerHTML properties detected. Modifying these properties with unsanitized user input can lead to XSS vulnerabilities. Use safe alternatives or sanitize content first.
Context: this.status.innerHTML = 'Failed to resume the session.
Please retry or reload the page.'
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://owasp.org/www-community/xss-filter-evasion-cheatsheet
- https://cwe.mitre.org/data/definitions/79.html

(dom-content-modification)

🔇 Additional comments (14)
src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Components/Layout/ReconnectModal.razor.js (1)

55-55: Good shift to resume-failed UI state.
Avoids an unnecessary reload and keeps the user in the retry flow.

src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Components/Layout/ReconnectModal.razor (1)

29-33: UI copy and visibility updates look consistent.
The resume-failed messaging and button visibility match the new flow.

src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsStartup.cs (1)

54-61: Clear test-only switch for disabling circuit persistence.
The new configuration branch is straightforward and matches the test scenarios.

src/Components/Web.JS/src/Platform/Circuits/DefaultReconnectDisplay.ts (2)

99-112: Button visibility resets are consistent.
Hiding resume/reload during reconnect avoids stale controls.


134-140: Failure messaging/visibility split looks correct.
Resume vs reconnect failure states are clearly distinguished.

src/Components/Web.JS/src/Platform/Circuits/UserSpecifiedDisplay.ts (3)

30-33: Reconnect/remote flags are now explicit.
Clear defaults make the state visible to custom displays.


74-79: Pause event now carries remote context.
Good propagation for UI state updates.


88-96: Failure events include remote metadata.
Helps custom UI tailor messaging consistently.

src/Components/test/E2ETest/ServerExecutionTests/ServerReconnectionWithoutStateTest.cs (6)

23-31: Fixture flags align with the no‑state scenario.
Disabling reconnection cache and circuit persistence matches the test’s intent.


33-37: Init navigation and interactivity check look good.


39-41: Configurable defaults are handy for derived tests.


73-102: Covers persistent vs non‑persistent counters across reconnects.


104-148: UI flow assertions are clear and reusable.


151-168: Custom UI variant setup is clear.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +61 to +64
// Check for page reload using multiple conditions:
// 1. Previously captured element is stale
Browser.True(initialElement.IsStale);
// 2. Counter state is reset
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cat -n src/Components/test/E2ETest/ServerExecutionTests/ServerReconnectionWithoutStateTest.cs | head -80 | tail -30

Repository: qodo-benchmark/aspnetcore-combined-coderabbit

Length of output: 1836


🏁 Script executed:

rg "IsStale" --type cs -B 2 -A 2 | head -50

Repository: qodo-benchmark/aspnetcore-combined-coderabbit

Length of output: 5699


🏁 Script executed:

rg "Browser\.True" --type cs -B 1 -A 1 | head -40

Repository: qodo-benchmark/aspnetcore-combined-coderabbit

Length of output: 3292


🏁 Script executed:

rg "static.*IsStale|extension.*IsStale" --type cs -B 2 -A 5

Repository: qodo-benchmark/aspnetcore-combined-coderabbit

Length of output: 929


🏁 Script executed:

rg "class Browser|namespace.*Browser" --type cs | head -20

Repository: qodo-benchmark/aspnetcore-combined-coderabbit

Length of output: 2112


🏁 Script executed:

fd "Browser.cs" --type f

Repository: qodo-benchmark/aspnetcore-combined-coderabbit

Length of output: 71


🏁 Script executed:

fd "BrowserWait.cs|BrowserExtensions.cs" --type f

Repository: qodo-benchmark/aspnetcore-combined-coderabbit

Length of output: 149


🏁 Script executed:

rg "Browser\.True|void True|bool True" --type cs -B 2 -A 3 | grep -A 3 "True.*Func\|True.*Action" | head -40

Repository: qodo-benchmark/aspnetcore-combined-coderabbit

Length of output: 1255


🏁 Script executed:

rg "static.*True\(" --type cs -B 1 -A 4 | head -60

Repository: qodo-benchmark/aspnetcore-combined-coderabbit

Length of output: 2347


🏁 Script executed:

rg "class.*Browser|namespace.*BrowserWait" --type cs | grep -v "BrowserFile\|BrowserTab\|IBrowserFile\|BrowserTest" | head -20

Repository: qodo-benchmark/aspnetcore-combined-coderabbit

Length of output: 2873


🏁 Script executed:

find . -type f -name "*.cs" -path "*/test/*" -o -name "*.cs" -path "*/E2ETest/*" | xargs grep -l "Browser\.True" | head -5 | xargs grep -B 5 "static.*Browser" | head -40

Repository: qodo-benchmark/aspnetcore-combined-coderabbit

Length of output: 395


🏁 Script executed:

rg "public.*True" src/Shared/E2ETesting/ --type cs -B 2 -A 3

Repository: qodo-benchmark/aspnetcore-combined-coderabbit

Length of output: 1406


🏁 Script executed:

rg "public static.*True|public.*True\(" src/Shared/BrowserTesting/src/ --type cs -B 1 -A 5

Repository: qodo-benchmark/aspnetcore-combined-coderabbit

Length of output: 71


Fix staleness check invocation.
IsStale is an extension method, so the current usage won't compile; wrap it in a lambda to keep the wait behavior.

🐛 Proposed fix
-        Browser.True(initialElement.IsStale);
+        Browser.True(() => initialElement.IsStale());
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Check for page reload using multiple conditions:
// 1. Previously captured element is stale
Browser.True(initialElement.IsStale);
// 2. Counter state is reset
// Check for page reload using multiple conditions:
// 1. Previously captured element is stale
Browser.True(() => initialElement.IsStale());
// 2. Counter state is reset
🤖 Prompt for AI Agents
In
`@src/Components/test/E2ETest/ServerExecutionTests/ServerReconnectionWithoutStateTest.cs`
around lines 61 - 64, The staleness check currently calls the extension
property/method IsStale directly which won't compile; change the wait assertion
to pass a lambda that evaluates initialElement.IsStale (e.g., Browser.True(() =>
initialElement.IsStale)) so the check is deferred and executed inside the wait;
locate the assertion using Browser.True and initialElement.IsStale in
ServerReconnectionWithoutStateTest and wrap the IsStale invocation in a lambda
expression.

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.

2 participants