Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebView.CoreWebView2.ExecuteScriptAsync does not fill the fields on the page

Tags:

c#

webview2

I have a code like below,

public partial class LawView : UserControl
{
    public LawView()
    {
        InitializeComponent();
        InitializeAsync();
    }

    async void InitializeAsync()
    {
        await webView.EnsureCoreWebView2Async(null);
        webView.Source = new System.Uri("https://blahblah.com.pl/");
        webView.Focus();
        await webView.CoreWebView2.ExecuteScriptAsync("(function() { document.getElementById('user').value = 'blahblahusername'; document.getElementById('password').value = 'blahpassword'; })()");
        await webView.CoreWebView2.ExecuteScriptAsync("(function() { document.getElementsByName('wp-submit')[0].click(); })()");
    }
}

in the console, the scripts run without any problems, but when I run them in the application, the fields in the open page do not fill me up. What am I doing wrong? Is there something missing?

I've already searched stackoverflow and other sites. I found nothing to lead me to a solution. I will be grateful for any help.

like image 508
Pepe Avatar asked Oct 20 '25 08:10

Pepe


2 Answers

After setting the Source property you need to wait for the page to actually load. You can use the NavigationCompleted event or the DOMContentLoaded for this. Note that NavigationCompleted is called for successful and unsuccessful navigations.

  1. The example below uses a simple extension method to wrap the NavigationCompleted event. The method uses the Navigate method instead of setting the Source property.
// Create a static class and add the following extension method
// Add using System.Threading.Tasks;
public static Task NavigateToAsync(this CoreWebView2 coreWebView2, string url)
{
    var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);

    EventHandler<CoreWebView2NavigationCompletedEventArgs> evt = null;

    evt = async (s, args) =>
    {
        coreWebView2.NavigationCompleted -= evt;

        if (args.IsSuccess)
        {
            tcs.TrySetResult(true);
        }
        else
        {
            tcs.TrySetException(new Exception("Nav Failed With Error:" + args.WebErrorStatus.ToString()));
        }
    };

    coreWebView2.NavigationCompleted += evt;

    coreWebView2.Navigate(url);

    return tcs.Task;
}

// Use extension method in your code.
async void InitializeAsync()
{
    await webView.EnsureCoreWebView2Async(null);
    
    try
    {
        await webView.CoreWebView2.NavigateToAsync("https://klimedsoft.pl/strefa-klienta/");
        webView.Focus();

        // now execute your javascript
        await webView.CoreWebView2.ExecuteScriptAsync("(function() { document.getElementById('user').value = 'blahblahusername'; document.getElementById('password').value = 'blahpassword'; })()");
        await webView.CoreWebView2.ExecuteScriptAsync("(function() { document.getElementsByName('wp-submit')[0].click(); })()");
    }
    catch (Exception ex)
    {
        //TODO: Handle error
    }
}
  1. Alternatively you can use the DOMContentLoaded event directly, it's only called upon successful navigation.
async void InitializeAsync()
{
  await webView.EnsureCoreWebView2Async(null);
  webView.CoreWebView2.DOMContentLoaded += OnWebViewDOMContentLoaded;
  webView.Source = new System.Uri("https://klimedsoft.pl/strefa-klienta/");

}

private async void OnWebViewDOMContentLoaded(object sender, CoreWebView2DOMContentLoadedEventArgs arg)
{
  webView.CoreWebView2.DOMContentLoaded -= OnWebViewDOMContentLoaded;

  webView.Focus();
  
 // now execute your javascript
 await webView.CoreWebView2.ExecuteScriptAsync("(function() { document.getElementById('user').value = 'blahblahusername'; document.getElementById('password').value = 'blahpassword'; })()");
 await webView.CoreWebView2.ExecuteScriptAsync("(function() { document.getElementsByName('wp-submit')[0].click(); })()");
}
like image 123
amaitland Avatar answered Oct 21 '25 22:10

amaitland


You didn't indicate if the web view navigated to the page at all.

Try using the Navigate(string url) on the Core viewer. The main issue is generally that we need to wait for the page load to complete before it will be ready to execute scripts. When you run this in the web console, you are doing so only after the page has loaded.

This response from @amaitland is generally the accepted solution for converting an event based API (EAP) to a Task based API (TAP). This pattern is generally referred to as a TAP Wrapper or TAP Extension. Find more information on that here:

  • From APM to TAP

My previous solution (which I will leave below) was a quick and dirty wait loop, we should however use SemiphoreSlim instead of thread blocking logic to achieve the same thing. You can find out more information here:

  • Waiting for an event to fire while using SemaphoreSlim

This is a solution using SemaphoreSlim:

private SemaphoreSlim _waitForWebViewToLoad;
async void InitializeAsync()
{
    await webView.EnsureCoreWebView2Async(null);
    _waitForWebViewToLoad = new SemaphoreSlim(0,1);
    webView.CoreWebView2.NavigationCompleted += CoreWebView2_NavigationCompleted;
    webView.CoreWebView2.Navigate("https://klimedsoft.pl/strefa-klienta/");
    webView.Focus();
    await _waitForWebViewToLoad.WaitAsync();

    // now execute your javascripts
    await webView.CoreWebView2.ExecuteScriptAsync("(function() { document.getElementById('user').value = 'blahblahusername'; document.getElementById('password').value = 'blahpassword'; })()");
    await webView.CoreWebView2.ExecuteScriptAsync("(function() { document.getElementsByName('wp-submit')[0].click(); })()");
}

private void CoreWebView2_NavigationCompleted(object sender, Microsoft.Web.WebView2.Core.CoreWebView2NavigationCompletedEventArgs e)
{
    webView.CoreWebView2.NavigationCompleted -= CoreWebView2_NavigationCompleted;
    _waitForWebViewToLoad.Release();
}

The following is a similar approach that uses a simple boolean flag to indicate when the event has fired, the difference here it uses an infinite loop that blocks and then waits for 100 milliseconds. If you find yourself using this style of code, then SemaphoreSlim was designed specifically to solve this problem without blocking the current thread:

async void InitializeAsync()
{
    await webView.EnsureCoreWebView2Async(null);
    webView.CoreWebView2.NavigationCompleted += CoreWebView2_NavigationCompleted;
    navComplete = false;
    webView.CoreWebView2.Navigate("https://klimedsoft.pl/strefa-klienta/");
    webView.Focus();
    while(!navComplete)
    {
        await Task.Delay(100);
    }
    
    // now execute your javascripts
    await webView.CoreWebView2.ExecuteScriptAsync("(function() { document.getElementById('user').value = 'blahblahusername'; document.getElementById('password').value = 'blahpassword'; })()");
    await webView.CoreWebView2.ExecuteScriptAsync("(function() { document.getElementsByName('wp-submit')[0].click(); })()");
}

bool navComplete = false;
private void CoreWebView2_NavigationCompleted(object sender, Microsoft.Web.WebView2.Core.CoreWebView2NavigationCompletedEventArgs e)
{
    webView.CoreWebView2.NavigationCompleted -= CoreWebView2_NavigationCompleted;
    navComplete = true;
}
like image 33
Chris Schaller Avatar answered Oct 21 '25 22:10

Chris Schaller



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!