WebView2: Calling ExecuteScriptAsync method as sync. #3960
Replies: 6 comments
-
Using To synchronously block waiting for a WebView2 async task, you'd need to wait in a way where window messages are still processed. However, depending on your scenario, processing window messages could result in unwanted reentrancy or other issues and is not a generally acceptable solution. Another option would be to use the WebView2 on its own separate UI thread, run the async methods as async methods, and create your own cross thread communication back to the calling thread that does allow for synchronously blocking the calling thread. |
Beta Was this translation helpful? Give feedback.
-
Hi David, Thanks for your response! This is a kind of showstopper for us. We tried almost everything to resolve this issue. Thank you, |
Beta Was this translation helpful? Give feedback.
-
There's no great solution. The first suggestion I had above is perhaps less reliable because of reentrancy and out of order processing of window messages compared to other kinds of events. For the second suggestion, if you're able to run the WebView2 on a different UI thread than the caller's thread you can try something like the following. We convert the async call on the UI thread into a sync call on the caller's thread. private void Button_Click(object sender, RoutedEventArgs e)
{
var t = new Thread(() =>
{
string result = ExecuteScriptSync("1 + 1");
Trace.WriteLine("The Result Is: " + result);
});
t.Name = "My Thread";
t.Start();
}
// Must be called from thread other than UI thread
public string ExecuteScriptSync(string script)
{
// If we run this on the UI thread we will deadlock
if (Application.Current.Dispatcher.Thread == Thread.CurrentThread)
{
throw new Exception("ExecuteScriptSync cannot be called from the UI thread");
}
string successValue = null;
Exception failureValue = null;
AutoResetEvent autoResetEvent = new AutoResetEvent(false);
// Use the Dispatcher to run on the app's UI thread
// which is also the WebView2 UI thread.
App.Current.Dispatcher.InvokeAsync(async () =>
{
try
{
// We have to run async on the UI thread or else
// we will deadlock
successValue = await TheWebView2.ExecuteScriptAsync(script);
}
catch (Exception e)
{
failureValue = e;
}
// Using AutoResetEvent to communicate completion back
// to the caller. InvokeAsync doesn't wait for an async
// operation to complete before returning to the caller.
autoResetEvent.Set();
}).Wait();
autoResetEvent.WaitOne();
if (failureValue != null)
{
throw failureValue;
}
return successValue;
} |
Beta Was this translation helpful? Give feedback.
-
Is there a way to achieve this from the UI thread? For example, to execute when the user clicks a button and you need a sync response? As an example, https://stackoverflow.com/questions/69990798/issue-with-async-code-when-using-webview2-control-inside-vsto-outlook-plugin uses the windows message loop, but you say that isnt great? |
Beta Was this translation helpful? Give feedback.
-
Synchronously running the message loop to wait for an async method to complete on the UI thread can cause problems depending on your app. It can result in messages running out of order, or messages being processed in a reentrant manner where your code does not expect to run. If you can account for that in your app then you can try doing that. You can use window messages APIs like stackoverflow suggests or check if your UI framework (WPF) has a way to do the same to run its message loop. |
Beta Was this translation helpful? Give feedback.
-
Another option to call WebView2 in sync way is to do it within ShowDialog, based on solution that is described here: https://stackoverflow.com/a/53510363/6537984. This can also be wrapped to STA thread as well. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hello All,
We are stuck in one place, while integrating webview2 in our WPF application. We have third parties libraries from where we have to call ExecuteScriptAsync method in synchronous way.
We have the dependencies on third party libraries and they support only synchronous methods and we can not make any changes to their method definition.
While we have tried lots of things to get the result from ExecuteScriptAsync synchronously. But we are getting only the task as a result and it is not waiting for the result and pointer moves away to the next line.
If the caller method is Async, we are getting the proper result and it is waiting for the execution to complete.
Below are the two example for your reference.
`public string FetchTextFromUI()
{
var result = WebView2.CoreWebView2.ExecuteScriptAsync("JSScript").Result;
// It hangs the application.
}
public async string FetchTextFromUIAsync()
{
var result = await WebView2.CoreWebView2.ExecuteScriptAsync(script);
}`
We are using below Webview2 version package: 1.0.1108.44
Please let me know if there is any workaround of this issue.
Thank you,
Vaibhav
Beta Was this translation helpful? Give feedback.
All reactions