You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Reloading page with some Blazor Blueprint components in standalone WebView2 app throws JSException JS object instance with ID X does not exist (has it been disposed?). It appears to be related to MAUI as I found the very same subject elsewhere - expected to be fixed but no ETA for this 2-3 year old issue.
Added code only to catch JSException on component disposals. Might not be needed here though.
Type of Change
Bug fix (non-breaking change that fixes an issue)
New feature (non-breaking change that adds functionality)
Breaking change (fix or feature that would cause existing functionality to change)
Hi @SimonDD7, thanks for tracking this one down! The WebView2 reload crash has been a known pain point and your reproduction matches the upstream dotnet/maui issue. The pattern you're applying is the right one in spirit, just want to talk through the implementation before we merge.
A few things to address:
1. ex.Message.Contains("does not exist") is fragile
String-matching on the exception message is brittle. If the runtime ever changes that text we'd silently stop catching the case (or worse, start catching unrelated JSExceptions that share a similar message). I'd like to keep the message check (it's the only signal we have) but pull it into one place so we have a single point of truth, and tighten it up.
Something along these lines:
privatestaticboolIsExpectedDisposeException(Exceptionex)=>exisJSDisconnectedException
or TaskCanceledException
or ObjectDisposedException||(exisJSExceptionjsEx&&jsEx.Message.Contains("does not exist",StringComparison.Ordinal));
That way the existing exception types stay in their own bucket and the WebView2 case is explicitly tagged as a JSException with the known message. If the message ever changes we update one method, not 30+ files.
2. The same catch block is duplicated across ~30 files
This is the bigger one. The current approach copy-pastes the same 4 lines into every DisposeAsync we have. Each new component will need to remember to add it, and any future change (logging, a different message, telemetry) becomes a 30-file PR.
Let's centralize it as an extension method on IJSObjectReference. Something like:
// src/BlazorBlueprint.Components/Internal/JSObjectReferenceExtensions.csinternalstaticclassJSObjectReferenceExtensions{/// <summary>/// Disposes a JS module, swallowing exceptions that are expected during/// circuit disconnect (Blazor Server) or page reload (MAUI WebView2)./// </summary>publicstaticasyncValueTaskSafeDisposeAsync(thisIJSObjectReference?module){if(moduleisnull){return;}try{awaitmodule.DisposeAsync();}catch(Exceptionex)when(IsExpectedDisposeException(ex)){// Expected during circuit disconnect or WebView2 page reload}}privatestaticboolIsExpectedDisposeException(Exceptionex)=>exisJSDisconnectedException
or TaskCanceledException
or ObjectDisposedException||(exisJSExceptionjsEx&&jsEx.Message.Contains("does not exist",StringComparison.Ordinal));}
For the components that do an InvokeVoidAsync("dispose", id) before tearing the module down, we can either wrap the whole block in one try and reuse IsExpectedDisposeException, or add a second helper that does invoke-then-dispose. Happy to discuss what shape works best, the main thing is that the WebView2 fix lives in one file rather than thirty.
3. The catch in BbTabsList.OnAfterRenderAsync you flagged yourself
You mentioned in the PR description that this one might not be needed. Agreed, let's drop it. The fix should stay scoped to dispose paths.
Once those are sorted this should be good to go. Thanks again for raising it and putting the work in!
I haven't found a solution that targets this issue directly. There's a quality rule from Microsoft CA1065-Dispose methods. Many projects I've checked just dismiss all exceptions on component disposal - it will work but I'm not sure if that's a good practice. JSException doesn't really help here, that's why I figured string comparsion must be enough for now. Maybe drop all JSExceptions on disposals?
I've seen you already discussed this with someone elsewhere and while I agree, I haven't mentioned that to not bother you with the same observation.
Yea, I was checking where you dispose js stuff and I don't really have an explanation why I've put it there. Then I started PR, saw it and just pointed out in description, sorry. I should've ask AI to do it xD
Thanks for you work, this project is really cool.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Reloading page with some Blazor Blueprint components in standalone WebView2 app throws JSException
JS object instance with ID X does not exist (has it been disposed?). It appears to be related to MAUI as I found the very same subject elsewhere - expected to be fixed but no ETA for this 2-3 year old issue.Added code only to catch JSException on component disposals. Might not be needed here though.
Type of Change
Testing Checklist
Related Issues
Fixes similar case to #77 but with WebView2