0

When I try to read the content of one web page loaded into the webview2 control, task ExecuteScriptAsync blocks forever. After this the application does not respond, but the site is still operational. The site is posted on an corprate intranet, so I can't provide the URL here. It is Ivanti Service Desk.

private void bnNewReguest_Click(object sender, EventArgs e)
{
    var t = GetTextAsync();
    string sHtml = t.Result;
    if (!sHtml.Contains("shortcutItem_12345"))
    {
        MessageBox.Show("Please wait for the page to load");
        return;
    }
    webView21.ExecuteScriptAsync("document.getElementById('shortcutItem_12345').click()");
}

private async Task<string> GetTextAsync()
{

    if (webView21.CoreWebView2 == null)
    {
        MessageBox.Show("Wait a moment...");
        return "";
    }
    var script = "document.documentElement.outerHTML";
    string sHtml = await webView21.CoreWebView2.ExecuteScriptAsync(script);  // deadlock
    string sHtmlDecoded = System.Text.RegularExpressions.Regex.Unescape(sHtml);
    return sHtmlDecoded;
}

I also tried the code below, but the result is similar.

string sHtml = await webView21.CoreWebView2.ExecuteScriptAsync(script).ConfigureAwait(false);

The WebView2 version is 1.0.1418.22. How can I protect from deadlock? I found a thread about the same problem here, but none of the solutions work for me.

Zbyszko
  • 3
  • 5
  • This code has no context. When / where / how are you running it? Why do you have this: `if (webView21.CoreWebView2 == null) { }` in there? Did you initialize the Component (e.g., as shown [here](https://stackoverflow.com/a/68790332/7444103))? Did you handle the `NavigationCompleted` event? -- `.ConfigureAwait(false)` is not relevant – Jimi Nov 24 '22 at 10:25
  • Yes, I initialize the Component, wait for NavigationCompleted e.t.c. I call this function when a button is pressed to read the content of the page for further automation. For example to call webView21.ExecuteScriptAsync("document.getElementsById('some_button').click();") – Zbyszko Nov 24 '22 at 11:03
  • You need to show how this method is called. Post the code, do not just describe it – Jimi Nov 24 '22 at 11:16
  • You're right, I added the call code. – Zbyszko Nov 24 '22 at 11:35
  • You have to make the `bnNewReguest_Click` handler `async`, then you have `var t = await GetTextAsync();` -- Remove that `if` condition from that method – Jimi Nov 24 '22 at 11:38
  • I can't. This is a Button control event from WinForms, so it can't be async. Anyway, if I didn't call this function, it's always blocked. I also need to check if (!sHtml.Contains("shortcutItem_12345")) because after NavigationCompleted the content of the page is still changing due to scripts running in the background. – Zbyszko Nov 24 '22 at 11:48
  • 1
    Event handlers **can** be `async`, one of the primary uses of the async keyword in this platform -- I don't know what *is blocked*: you're asking to return the main Document's content, in a Button.Click event -- You also have to await `ExecuteScriptAsync()` in `bnNewReguest_Click` -- I hope you didn't follow this same *pattern* (not awaiting async calls) while you're initializing the Component – Jimi Nov 24 '22 at 11:52
  • 1
    There is a good read about [blocking async](https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html) calls, best advice is to use async await the whole way up. This means make the event handler async and use await to call other async methods. – martinstoeckli Nov 24 '22 at 11:59
  • Jimi, It's not relevant at this point, the program is in draft The point is how to get the content of the page when the following script blocks the app: string sHtml = await webView21.CoreWebView2.ExecuteScriptAsync("document.documentElement.outerHTML"); – Zbyszko Nov 24 '22 at 12:07
  • What is *not relevant*? How to call async methods? That's exceedingly relevant. Are you awaiting those calls? Are you awaiting the async methods used to initialize the WebView2 Component? If you're not, then nothing else matters, because it will fail in a way or another -- Since you have that weird `if (webView21.CoreWebView2 == null)` condition that really doesn't belong, you probably also have initialization issues that you were trying to *fix* – Jimi Nov 24 '22 at 12:18
  • You're right Jimi, the Button.Click event can be async. I read Stephen Cleary's blog and now I know how to fix the code. The error was that I was blocking the main thread, leading to deadlocks. – Zbyszko Nov 25 '22 at 08:08
  • Well, good to know. You have something new in your bag now -- Note that also applies to the WebView2 initialization procedure. See the link in my first comment. If you don't do it correctly, you may not notice while debugging, or in the VS environment, but you'll notice later – Jimi Nov 25 '22 at 15:58

1 Answers1

1

I describe this deadlock on my blog. The best solution is to not block on asynchronous code.

In your case, this could look like this:

private async void bnNewReguest_Click(object sender, EventArgs e)
{
    string sHtml = await GetTextAsync();
    if (!sHtml.Contains("shortcutItem_12345"))
    {
        MessageBox.Show("Please wait for the page to load");
        return;
    }
    await webView21.ExecuteScriptAsync("document.getElementById('shortcutItem_12345').click()");
}
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • You're right, I already know what's going on and how to fix the code. I would like to upvote the answer, but my reputation is too low. – Zbyszko Nov 25 '22 at 08:00