How to use timer to automatically run JavaScript in WebView2.

john zyd 421 Reputation points
2021-01-21T18:58:25.26+00:00

Hello:
For my project, I have to automatically run some JavaScript every minute in WebView2. Even I can manually click on the button to run the JavaScript and get the result, but I can’t figure out how to use timer to run the job automatically.

I have done the following:
I created one Windows Forms App (.NET) and set target to .NET 5.0; then I install WebView2 Nuget package: Install-Package Microsoft.Web.WebView2 -Version 1.0.664.37

I didn’t use Windows Forms Designer, but I write the following code by hand:
I use Visual Studio 2019 Version 16.8.4, my OS is Windows 10 (Version 20H2)

using Microsoft.Web.WebView2.WinForms;  
using System;  
using System.Diagnostics;  
using System.Drawing;  
using System.Threading.Tasks;  
using System.Windows.Forms;  
using Timer = System.Timers.Timer;    

namespace WebView2Buttons    
{    
    public partial class Form1 : Form  
    {  
        private readonly WebView2 BingWebView = new WebView2();  
        private readonly Button MinuteButton = new Button();  
        private readonly Button Button1 = new Button();  
        private static Timer MinuteTimer;  
    

    private async void MinuteTimerElapsedAsync(Object source, System.Timers.ElapsedEventArgs e)  
    {  
        try  
        {  
            MinuteButton.PerformClick();  
        }  
        catch (TimeoutException ex)  
        {  
            Debug.WriteLine("[MinuteTimerElapsedAsync]: " + ex.Message);  
            await Task.Delay(1);  
        }  
    }  

    private async void MinuteButton_Click(object sender, EventArgs e)  
    {  
        string xhr_request =  
            @"function reqXHR() { let r = new XMLHttpRequest();   
              r.open('GET', 'https://www.bing.com/', false);   
              r.send(); var reply = r.responseText; return reply;}; reqXHR(); ";  
        string raw_data =  
            await BingWebView.CoreWebView2.ExecuteScriptAsync(xhr_request);  
        Debug.WriteLine(raw_data);  
    }  

    private async void Button1_Click(object sender, EventArgs e)  
    {  
        string xhr_request =  
            @"function reqXHR() { let r = new XMLHttpRequest();   
              r.open('GET', 'https://www.bing.com/', false);   
              r.send(); var reply = r.responseText; return reply;}; reqXHR(); ";  
        string raw_data =  
            await BingWebView.CoreWebView2.ExecuteScriptAsync(xhr_request);  
        Debug.WriteLine(raw_data);  
    }  

    public Form1()  
    {  
        InitializeComponent();  
        Control.CheckForIllegalCrossThreadCalls = false;  
        BingWebView.CreationProperties = null;  
        BingWebView.Location = new Point(10, 65);  
        BingWebView.Name = "BingWebView";  
        BingWebView.Size = new Size(1750, 780);  
        BingWebView.Source = new Uri("https://www.bing.com/", UriKind.Absolute);  
        BingWebView.TabIndex = 0;  
        BingWebView.Text = "BingWebView";  
        BingWebView.ZoomFactor = 1D;  
        BingWebView.Visible = true;  
        this.SuspendLayout();  
        MinuteButton.Location = new Point(1500, 10);  
        MinuteButton.Name = "MinuteButton";  
        MinuteButton.Size = new Size(250, 50);  
        MinuteButton.TabIndex = 1;  
        MinuteButton.Text = "MinuteButton";  
        MinuteButton.UseVisualStyleBackColor = true;  
        MinuteButton.Click += new EventHandler(MinuteButton_Click);  
        Button1.Location = new Point(50, 10);  
        Button1.Name = "Button1";  
        Button1.Size = new Size(250, 50);  
        Button1.TabIndex = 2;  
        Button1.Text = "Button1";  
        Button1.UseVisualStyleBackColor = true;  
        Button1.Click += new EventHandler(Button1_Click);  
        ClientSize = new Size(1800, 800);  
        Controls.Add(BingWebView);  
        Controls.Add(MinuteButton);  
        Controls.Add(Button1);  
        Name = "Form1";  
        Text = "Form1";  
        Load += new EventHandler(Form1_Load);  
        ResumeLayout(false);  
    }  

    private void Form1_Load(object sender, EventArgs e)  
    {  
        MinuteTimer = new Timer(60000);  
        MinuteTimer.Elapsed += MinuteTimerElapsedAsync;  
        MinuteTimer.AutoReset = true;  
        MinuteTimer.Enabled = true;  
        MinuteTimer.Start();  
    }  
}  
}

If I click on either buttons of “Button1” or “MinuteButton”, my code works. But in the minute timer to automatically click “MinuteButton” did NOT work.
I saw the error:

System.InvalidCastException    
  HResult=0x80004002    
  Message=Unable to cast COM object of type 'System.__ComObject' to interface type 'Microsoft.Web.WebView2.Core.Raw.ICoreWebView2Controller'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{4D00C0D1-9434-4EB6-8078-8697A560334F}' failed due to the following error: No such interface supported (0x80004002 (E_NOINTERFACE)).    
  Source=System.Private.CoreLib    
  StackTrace:    
   at System.StubHelpers.StubHelpers.GetCOMIPFromRCW(Object objSrc, IntPtr pCPCMD, IntPtr& ppTarget, Boolean& pfNeedsRelease)    
   at Microsoft.Web.WebView2.Core.Raw.ICoreWebView2Controller.get_CoreWebView2()    
   at Microsoft.Web.WebView2.Core.CoreWebView2Controller.get_CoreWebView2()    
   at Microsoft.Web.WebView2.WinForms.WebView2.get_CoreWebView2()    
   at WebView2Buttons.Form1.<MinuteButton_Click>d__5.MoveNext() in C:\WebView2Buttons\WebView2Buttons\Form1.cs:line 37    

I don’t understand the difference between I click on the button by mouse and the statement MinuteButton.PerformClick()
Let me know if I can do this or not.
By the way, I don’t necessarily have to use click button code, but I think I have to use a Timer, as I have to run some JavaScript code every minute.
Thanks,
59170-timerclickbuttonissue.png

C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,249 questions
Visual Studio Debugging
Visual Studio Debugging
Visual Studio: A family of Microsoft suites of integrated development tools for building applications for Windows, the web and mobile devices.Debugging: The act or process of detecting, locating, and correcting logical or syntactical errors in a program or malfunctions in hardware. In hardware contexts, the term troubleshoot is the term more frequently used, especially if the problem is major.
939 questions
0 comments No comments
{count} votes

Accepted answer
  1. Timon Yang-MSFT 9,571 Reputation points
    2021-01-22T06:31:24.907+00:00

    This error has nothing to do with PerformClick(), but because the code is trying to operate across threads.
    System.Timers.Timer will use a new thread, and when you try to call MinuteButton.PerformClick(); in this thread, this error will occur.
    Please try this code:

                try  
                {  
                    MinuteButton.Invoke((MethodInvoker)delegate { MinuteButton.PerformClick(); });  
                }  
    

    If the response is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


0 additional answers

Sort by: Most helpful