Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix BlazorWebView disposal #7349

Merged
merged 4 commits into from
May 24, 2022
Merged

Conversation

MackinnonBuck
Copy link
Member

@MackinnonBuck MackinnonBuck commented May 19, 2022

Description of Change

BlazorWebViewHandler.DisconnectHandler() has not been getting invoked when the BlazorWebView gets unloaded. This was due to the incorrect assumption that DisconnectHandler() gets invoked automatically by the framework (see #3604). The result is that none of the *WebViewManager disposal logic was running, including the logic that ultimately runs Dispose() in Blazor components. This PR solves this problem in addition to a bug preventing disposal on Windows when the application closes.

Fixes an issue where DisconnectHandler() throws an exception on Android due to the double-closing of Android WebView message channel ports.

Issues Fixed

Fixes 7277

Repurposed to fix a potential future bug where DisconnectHandler() throws an exception on Android.

@MackinnonBuck MackinnonBuck requested a review from a team as a code owner May 19, 2022 23:14
Comment on lines -91 to -103
protected override async ValueTask DisposeAsyncCore()
{
await base.DisposeAsyncCore();

if (_nativeToJSPorts is not null)
{
foreach (var port in _nativeToJSPorts)
{
port?.Close();
}
}
}

Copy link
Member Author

Choose a reason for hiding this comment

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

Turns out that these ports get closed automatically when the WebView gets unloaded. Now that this logic was running for the first time, an exception was being thrown because the ports were being closed twice. Hence the removal of this method.

Copy link
Contributor

@TanayParikh TanayParikh left a comment

Choose a reason for hiding this comment

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

Great find!

Copy link
Member

@mkArtakMSFT mkArtakMSFT left a comment

Choose a reason for hiding this comment

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

Thanks @MackinnonBuck.
Don't we need unit-tests for these now?

@Eilon Eilon added the area-blazor Blazor Hybrid / Desktop, BlazorWebView label May 20, 2022
Comment on lines 27 to 28
// see: https://github.com/microsoft/microsoft-ui-xaml/issues/6872
// See: https://github.com/dotnet/maui/issues/7277
Handler?.DisconnectHandler();
Copy link
Member

Choose a reason for hiding this comment

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

@PureWeen will this cause issues at all?

Copy link
Member

Choose a reason for hiding this comment

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

@MackinnonBuck why is this specifically needed on Windows and not other platforms?

Copy link
Member Author

Choose a reason for hiding this comment

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

@Eilon The original issue that this PR is solving was reported for Windows. On Android and iOS, the Window.Destroying event does not get invoked when the app gets closed (#6993), so it wouldn't make a difference anyway. That said, we could make this line of code platform-independent, but that might introduce a risk that it doesn't work as expected on Android and iOS if/when #6993 gets fixed. Do you think it's worth investigating another way to make this work on other platforms?

Copy link
Member

Choose a reason for hiding this comment

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

Each platform has a version of Unloaded if you want to tie into those?
Android => ViewDetachedFromWindow
iOS => override WillMoveToWindow

It doesn't cover the window destroying case but it makes the behavior symmetrical for when a view is removed from the visual hierarchy.

Copy link
Member Author

Choose a reason for hiding this comment

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

@PureWeen this PR already adds a handler for the Unloaded event to invoke DisconnectHandler(). Just so I understand, is your suggestion to use the platform-specific APIs instead?

Copy link
Member Author

Choose a reason for hiding this comment

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

@PureWeen BlazorWebView retains hardly any state at all (it's managed by the underlying platform-specific WebView), so the user would basically be starting over from the beginning.

Copy link
Member

Choose a reason for hiding this comment

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

the primary use case of BlazorWebView will be MAUI Blazor apps where the WebView is basically the entire app

That might be the most common pattern, but certainly not the only one. I think optimizing for the most common pattern can make sense, but we have to be careful to not cause significant harm to less-common scenarios (I'm not saying any suggestion here violates that, but I want to make sure we don't end up there). This stuff is very hard for me to think through 😄

Copy link
Member Author

Choose a reason for hiding this comment

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

@Eilon, if we compare MAUI Blazor with Blazor WebAssembly for a minute, we don't call Dispose() for Blazor WebAssembly components when, for example, the browser window is closed. If someone needs some logic to run when the application window is closing, couldn't you argue that the resource being disposed exists in a context broader than the BlazorWebView, so therefore the disposal logic should be handled from that broader context (in MAUI lifecycle events, for example)? For example, @PureWeen brought up offline that the issue faced in #7277 could be fixed by running the disposal logic from within a MAUI context. This obviously has the downside that if you want to share Razor components between supported Blazor platforms, you would potentially need multiple versions of the component that manage state/disposal logic differently. But this comes back to what I said earlier about there not really being an equivalent case in Blazor WebAssembly, so maybe that concern isn't valid?

Copy link
Member Author

Choose a reason for hiding this comment

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

So basically, leaving it as-is where components don't get disposed with the WebView getting unloaded would actually maintain some level of parity with Blazor WebAssembly, for example.

Just throwing some ideas out there, because there is definitely a real risk of us breaking certain scenarios as you pointed out.

Copy link
Member Author

Choose a reason for hiding this comment

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

The conclusion we reached offline is that we're going to hold off on having BlazorWebView determine when to call DisconnectHandler() for now. The existing behavior is more acceptable than initially thought, so we feel comfortable revisiting this topic later when the general concept of disposal in MAUI is better understood.

@MackinnonBuck
Copy link
Member Author

Let's refrain from merging until this conversation is resolved.

@TanayParikh TanayParikh added blocked Work that is currently blocked do-not-merge Don't merge this PR and removed blocked Work that is currently blocked labels May 23, 2022
@MackinnonBuck
Copy link
Member Author

We're holding off on manually invoking DisconnectHandler() for now. The primary change in this PR is now fixing the double-closing of message channel ports on Android for when DisconnectHandler() does get invoked.

@MackinnonBuck MackinnonBuck merged commit 0ace122 into main May 24, 2022
@MackinnonBuck MackinnonBuck deleted the mbuck/fix-blazorwebview-disposal branch May 24, 2022 23:39
@github-actions github-actions bot locked and limited conversation to collaborators Dec 21, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-blazor Blazor Hybrid / Desktop, BlazorWebView
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants