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

Webview2 applications blocks each other #1935

Closed
KSteinigke opened this issue Nov 16, 2021 · 12 comments
Closed

Webview2 applications blocks each other #1935

KSteinigke opened this issue Nov 16, 2021 · 12 comments
Labels
bug Something isn't working tracked We are tracking this work internally.

Comments

@KSteinigke
Copy link

KSteinigke commented Nov 16, 2021

Hello,

we have an VC++ application which use the webview2 as embedded HTML-Viewer.
If the application is started twice on the same computer, the applications blocks each other.
If e.g. on one application an longer lasting mysql jquery is running. Also the second application is blocked.
Or if one application is running in the visual studio in debug mode and an breakpoint is entered, also the second application is blocked.

This can be easliy reporduced with teh use of the WebView Sample projects.

  • Start the WebView2APISample.vcxproj in Visual Studio
  • Compile the project
  • Start the project outside of Visual Studio
  • Start the project a second time in Visual Studio in debugger mode
  • Set a breakpoint and run to the braekpoint
  • Now also the project outside of Visual Studie is blocked.

How can we overcome this blocking?

AB#37148781

@fvanheeswijk
Copy link

Also following, we're experiencing a similar issue.

@champnic champnic added bug Something isn't working tracked We are tracking this work internally. labels Nov 24, 2021
@champnic
Copy link
Member

@KSteinigke @fvanheeswijk WebView2 uses a shared browser process for each app instance that uses the same user data folder. This is likely what's causing the blocking when one of those apps is blocked and blocks the browser process. One workaround would be to use different user data folders for each app instance, which would create separate browser processes (but lose out on shared state like cookies and cache).

However, I think we probably want to understand more about what function specifically is causing the blocking and if there's any fix for it. My gut reaction is that blocking the host app process shouldn't block the out-of-proc browser process.

@KSteinigke
Copy link
Author

Thank you very much! This solves the blocking.

@kirsan31
Copy link

@champnic

WebView2 uses a shared browser process for each app instance that uses the same user data folder. This is likely what's causing the blocking when one of those apps is blocked and blocks the browser process. One workaround would be to use different user data folders for each app instance, which would create separate browser processes (but lose out on shared state like cookies and cache).

This is not true in many cases. Similar situation - one app but several WebView2 windows. Even if you will create each WebView2 with it's own user data folder, events handlers of one WebView2 will block others WebView2 to update. Here are some of them (most frequently used):

WebMessageReceived
NavigationCompleted

How to test:

For one window open some dialog (ShowDialog) in one of this events handlers, or simple:

while (_condition)
{
    Application.DoEvents();
}

And in other windows you will be able to initiate some navigation but you will never receive WebMessageReceived and NavigationCompleted. Even more you will be able to do

await WV.ExecuteScriptAsync("script").ConfigureAwait(false);

but it never complete too :(
This behavior was very surprising for the first time :((((
And yea, it's very strange design overall - different controls, different processes and same events query? 🤷‍♂️

@champnic
Copy link
Member

The events may be blocking the WebView2 from continuing execution. When a WebView2 is waiting on the completion of its NavigationCompleted event, for example, if your app thread is blocking that event from firing and returning, then the corresponding WebView2 control may be blocked, even if it would otherwise be able to continue. For this reason, you should not do long-running execution within the event handlers if avoidable. Some of our event args have a deferral object you can use to facilitate asynchronous execution. For example:
https://docs.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2webresourcerequestedeventargs.getdeferral?view=webview2-dotnet-1.0.1072.54

@kirsan31
Copy link

@champnic

The events may be blocking the WebView2 from continuing execution. When a WebView2 is waiting on the completion of its NavigationCompleted event, for example, if your app thread is blocking that event from firing and returning, then the corresponding WebView2 control may be blocked, even if it would otherwise be able to continue. For this reason, you should not do long-running execution within the event handlers if avoidable.

The behavior that you describe is absolutely logical and understandable for one instance of the control. And may be even for several instances that uses same user data folder (same browser process). But I am talking about several different instances of WebView2 that uses different user data folder (different browser process). In this situation blocking event from returning on one control will block all other WebView2 controls! And this behavior already is not so logical and understandable. Also, this approach greatly slows down the overall work with the WebView2 (as their numbers increase), even if we try to free the handlers as quickly as possible.

@kirsan31
Copy link

kirsan31 commented Feb 2, 2022

Any response? I just want to understand if this is a by design or is it a bug? /cc @champnic

@champnic
Copy link
Member

champnic commented Feb 2, 2022

If all of the WebView2 controls have event listeners on the same thread and are blocking each other, then that is By Design. It's the same thing as if you had multiple buttons with event handlers, but blocked execution while in one event handler, causing the other buttons to not work. In general, it's best practice to not block the UI thread. I'm not sure if that's exactly what is happening in your scenario though. If you don't block those event handlers, does stuff seem to work as expected, even with multiple WebView2 controls?

@kirsan31
Copy link

kirsan31 commented Feb 2, 2022

@champnic
I think I can guess why we can not understand each other. We are not talking here about GUI thread block - it's not blocked, it's continue to do message pumping, but WebView2 event handler is not returning. I described it in my 1 post. The key moment here is Application.DoEvents(); or ShowDialog. And your example with buttons and their events will just work fine in this case (all buttons will be functional and continue to rise events).
But in case of WebView2 as soon as one event handler of any WebView2 will not return then all WebView2 in the app will simple hang. And you still can call await WV.ExecuteScriptAsync("script").ConfigureAwait(**false**); from GUI thread (due to working message pumping) but it will never return (only after we return from our event handler).

If it's still unclear what I'm trying to say, I can open a new issue and make a demo?

---- UPD ---

Ah, found it in the docs - Reentrancy is not supported :( Sorry for offtopic here.

@thnordsam
Copy link

thnordsam commented Jan 5, 2024

I believe we are facing this same problem while trying to use a WebView based ActiveX control in a program called XMetal. XMetal has implemented their own ActiveX control which can be used to display web content inside their application with WebView. However, if we initialize two of these ActiveX controls, the NavigateWaitComplete command will timeout and the second WebView won't load up.

So, for example here is how we can initialize two of these WebView controls in XMetal:

// XMEdge.EdgeBrowserContainer is the WebView ActiveX control implemented by XMetal
ResourceManager.AddTab('tab1', 'XMEdge.EdgeBrowserContainer');
const tab1 = ResourceManager.ControlInTab('tab1');
// This works fine
tab1.NavigateWaitComplete('https://google.com', 5000);

ResourceManager.AddTab('tab2', 'XMEdge.EdgeBrowserContainer');
const tab2 = ResourceManager.ControlInTab('tab2');
// This command will timeout and google will not be shown
tab2.NavigateWaitComplete('https://google.com', 5000);

This is a problem when multiple users are using XMetal at the same time on a web server and thus the WebView component works for only one of them.

Is there something that we can do or something that people at XMetal could do to prevent this problem from happening? For now it would be best if we could solve this locally and we could leave XMetal to solve it for good in some future release.

@champnic
Copy link
Member

champnic commented Jan 6, 2024

@thnordsam In general an app can have multiple WebView2 controls. I'm not sure what XMetal is doing here to launch multiple WebView2s, and whether they are trying to use single UDF and shared WV2 processes, or doing something else that's causing the WV2 controls to block each other. Are you able to specify the user data folder used by XMetal's control? If not, you could try using the WEBVIEW2_USER_DATA_FOLDER environment variable to different folders before instantiating each of the XMEdge controls.

@thnordsam
Copy link

@champnic Thank you, giving each user their own data folder helped and the problem is now fixed!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working tracked We are tracking this work internally.
Projects
None yet
Development

No branches or pull requests

6 participants