Parallel using of WebView2 in async Task(WebView2在异步任务中的并行使用)
问题描述
我有一个简单的默认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 runtime。
--测试
在主线程中准备WebView2并将其发送到子线程中。
var bro = new List<WebView2>() { new WebView2(), new WebView2(), new WebView2() };创建WebView2inStart方法的列表,并将WebView2实例发送到...但这以相同的错误结束。
推荐答案
您可以尝试使用以下自定义方法替换代码中的Task.Run:
public static Task TaskRunSTA(Func<Task> action)
{
    var tcs = new TaskCompletionSource<object>(
        TaskCreationOptions.RunContinuationsAsynchronously);
    var thread = new Thread(() =>
    {
        Application.Idle += Application_Idle;
        Application.Run();
    });
    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
    return tcs.Task;
    async void Application_Idle(object sender, EventArgs e)
    {
        Application.Idle -= Application_Idle;
        try
        {
            await action();
            tcs.SetResult(null);
        }
        catch (Exception ex) { tcs.SetException(ex); }
        Application.ExitThread();
    }
}
此方法启动一个新的STA线程,并在该线程内运行专用的应用程序消息循环。作为参数传递的异步委托将在此消息循环上运行,并安装了适当的同步上下文。只要您的异步委托不包含任何使用.ConfigureAwait(false)配置的await,您的所有代码,包括由WebView2组件引发的事件,都应该在此线程上运行。
注意:tbh我不知道处理第一个Application.Idle事件是否是在消息循环中嵌入自定义代码的最佳方式,但它似乎工作得很好。值得注意的是,此事件是从内部类ThreadContext(source code)附加和分离的,并且此类每个线程有一个专用的实例。因此,每个线程都会接收与该线程上运行的消息循环相关联的Idle事件。换句话说,不存在接收源自其他不相关的消息循环的事件的风险,该消息循环在另一个线程上并发运行。
这篇关于WebView2在异步任务中的并行使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:WebView2在异步任务中的并行使用
 
				
         
 
            
        基础教程推荐
- 全局 ASAX - 获取服务器名称 2022-01-01
- 经典 Asp 中的 ResolveUrl/Url.Content 等效项 2022-01-01
- JSON.NET 中基于属性的类型解析 2022-01-01
- 是否可以在 asp classic 和 asp.net 之间共享会话状态 2022-01-01
- 首先创建代码,多对多,关联表中的附加字段 2022-01-01
- 如何动态获取文本框中datagridview列的总和 2022-01-01
- 从 VS 2017 .NET Core 项目的发布目录中排除文件 2022-01-01
- 在 VS2010 中的 Post Build 事件中将 bin 文件复制到物 2022-01-01
- 错误“此流不支持搜索操作"在 C# 中 2022-01-01
- 将事件 TextChanged 分配给表单中的所有文本框 2022-01-01
 
    	 
    	 
    	 
    	 
    	 
    	 
    	 
    	 
						 
						 
						 
						 
						 
				 
				 
				 
				