Skip to content

[Blazor Hybrid] Consider guarding HandleComponentException when Renderer is Disposed #66322

@ScarletKuro

Description

@ScarletKuro

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

I originally reported this issue on the .NET MAUI side: dotnet/maui#34855. While investigating, I encountered several exceptions, and I believe the specific case described below belongs in this repository.

Consider the following:

@code {
    private bool _loading;

    protected override async Task OnInitializedAsync()
    {
        await base.OnInitializedAsync();
        _ = BackgroundWork();
    }

    private async Task BackgroundWork()
    {
        _loading = true;
        await InvokeAsync(StateHasChanged);

        try
        {
            await Task.Delay(5000);
            throw new Exception("Exception");
        }
        catch (Exception exception)
        {
            // MainLayout needs to be wrapped in ErrorBoundary
            await DispatchExceptionAsync(exception);
        }
        finally
        {
            _loading = false;
            await InvokeAsync(StateHasChanged);
        }
    }
}

If the browser is closed while Task.Delay is still in progress and the WebView is explicitly disposed(!!!) via BlazorWebView.DisposeAsync(), an exception Renderer does not have a component with ID XX is thrown.
If the WebView is not explicitly disposed, a different exception occurs instead, related to the WebView2 control already being disposed.

This behavior has been reproduced in WPF. I have not tested WinForms, but I expect similar behavior since most of the code is shared (aside from the dispatcher). I have also not verified whether this affects MAUI Hybrid.

Expected Behavior

Not to throw exception when webview is disposed.

Steps To Reproduce

This issue can be reproduced using a shared sample with .NET MAUI.

  1. Fork the repository: https://github.com/ScarletKuro/WpfIssueThreading
  2. In App.xaml.cs, uncomment the line mainWindow.DisposeAsync();
  3. Run the application
  4. Close the window while it says loading
  5. Observe the exception: Renderer does not have a component with ID XX

Exceptions (if any)

Exception has been thrown by the target of an invocation. System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.ArgumentException: The renderer does not have a component with ID 15.
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetRequiredComponentState(Int32 componentId)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.HandleComponentException(Exception exception, Int32 componentId)
   at Microsoft.AspNetCore.Components.RenderHandle.<>c__DisplayClass22_0.<DispatchExceptionAsync>b__0()
   at Microsoft.AspNetCore.Components.WebView.Wpf.WpfDispatcher.InvokeAsync(Action workItem)
   at SalesSystem.Web.Pages.Kiosk.GetCouponsInBackground() in C:\Users\Kuro\source\repos\kiisu\src\SalesSystem.Web\Pages\Kiosk.razor.cs:line 129
   at SalesSystem.Web.Pages.Kiosk.GetCouponsInBackground() in C:\Users\Kuro\source\repos\kiisu\src\SalesSystem.Web\Pages\Kiosk.razor.cs:line 138
   at Microsoft.AspNetCore.Components.WebView.Wpf.WpfDispatcher.<>c.<.cctor>b__8_0(Exception exception)
   at InvokeStub_Action`1.Invoke(Object, Span`1)
   at System.Reflection.MethodBaseInvoker.InvokeWithOneArg(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   --- End of inner exception stack trace ---
   at System.Reflection.MethodBaseInvoker.InvokeWithOneArg(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Delegate.DynamicInvokeImpl(Object[] args)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
System.Object: 
System.ArgumentException: The renderer does not have a component with ID 15.
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetRequiredComponentState(Int32 componentId)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.HandleComponentException(Exception exception, Int32 componentId)
   at Microsoft.AspNetCore.Components.RenderHandle.<>c__DisplayClass22_0.<DispatchExceptionAsync>b__0()
   at Microsoft.AspNetCore.Components.WebView.Wpf.WpfDispatcher.InvokeAsync(Action workItem)
   at SalesSystem.Web.Pages.Kiosk.GetCouponsInBackground() in C:\Users\Kuro\source\repos\kiisu\src\SalesSystem.Web\Pages\Kiosk.razor.cs:line 129
   at SalesSystem.Web.Pages.Kiosk.GetCouponsInBackground() in C:\Users\Kuro\source\repos\kiisu\src\SalesSystem.Web\Pages\Kiosk.razor.cs:line 138
   at Microsoft.AspNetCore.Components.WebView.Wpf.WpfDispatcher.<>c.<.cctor>b__8_0(Exception exception)
   at InvokeStub_Action`1.Invoke(Object, Span`1)
   at System.Reflection.MethodBaseInvoker.InvokeWithOneArg(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)

.NET Version

10.0.201

Anything else?

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-blazorIncludes: Blazor, Razor ComponentsbugThis issue describes a behavior which is not expected - a bug.investigate

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions