我有一个简单的默认Windows桌面表单Form1
,上面有一个按钮btn_Go
,作为测试。
我想要同时运行多个WebView2实例,并处理呈现页面的html代码。
为了并行运行WebView2,我使用SemaphoreSlim(设置为并行2)。另一个SemaphoreSlim用于等待WebView2呈现文档(带有一些时间延迟)。
但是我的代码在await webBrowser.EnsureCoreWebView2Async();
处失败。 调试器中来自WebView2
实例webBrowser
的内部异常是:
{"Cannot change thread mode after it is set. (Exception from HRESULT: 0x80010106 (RPC_E_CHANGED_MODE))"} System.Exception {System.Runtime.InteropServices.COMException}
如何调用多个WebView2并行处理所有url?
完整的演示代码:
using Microsoft.Web.WebView2.WinForms;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WebView2Test
{
public partial class Form1 : Form
{
public Form1() { InitializeComponent(); }
private void btn_Go_Click(object sender, EventArgs e) { Start(); }
private async void Start()
{
var urls = new List<string>() { "https://www.google.com/search?q=test1", "https://www.google.com/search?q=test2", "https://www.google.com/search?q=test3" };
var tasks = new List<Task>();
var semaphoreSlim = new SemaphoreSlim(2);
foreach (var url in urls)
{
await semaphoreSlim.WaitAsync();
tasks.Add(
Task.Run(async () => {
try { await StartBrowser(url); }
finally { semaphoreSlim.Release(); }
}));
}
await Task.WhenAll(tasks);
}
public async Task<bool> StartBrowser(string url)
{
SemaphoreSlim semaphore = new System.Threading.SemaphoreSlim(0, 1);
System.Timers.Timer wait = new System.Timers.Timer();
wait.Interval = 500;
wait.Elapsed += (s, e) =>
{
semaphore.Release();
};
WebView2 webBrowser = new WebView2();
webBrowser.NavigationCompleted += (s, e) =>
{
if (wait.Enabled) { wait.Stop(); }
wait.Start();
};
await webBrowser.EnsureCoreWebView2Async();
webBrowser.CoreWebView2.Navigate(url);
await semaphore.WaitAsync();
if (wait.Enabled) { wait.Stop(); }
var html = await webBrowser.CoreWebView2.ExecuteScriptAsync("document.documentElement.outerHTML");
return html.Length > 10;
}
}
}
我已经安装了WebView2 运行库。
-- 测试
在主线程中准备 WebView2
并将其发送到子线程。
我已经尝试过在主线程的Start
方法中创建WebView2
列表var bro = new List<WebView2>() { new WebView2(), new WebView2(), new WebView2() };
,并将 WebView2 实例发送到await StartBrowser(bro[index], url);
,但结果仍然出现相同的错误。
WebView2
组件在其生命周期内可能不喜欢被多个线程访问。 - Theodor Zoulias