无法获取浏览器网页的 HTML 来源,异步到同步问题

Cannot get HTML source of browser web page, async to sync problem

Visual Studio 2017,Windows 10,.NET Framework 4.8,CefSharp WinForms 83.4.20,平台目标 x64

创建了新的非常简单的 CefSharp Windows Forms 应用程序。我无法获取网页的 html 来源。我想我已经查看了 Whosebug 上的每个 CefSharp 和异步同步问题 - 尝试了很多解决方案 - 我的头已经变成糊状了。这是我看的第一个问题-我也有同样的问题。

'browser.ViewSource();' 确实会弹出一个带有网页来源的记事本。但是当我尝试获取带有源代码的字符串时 - 任务似乎从来没有 运行。 运行 获取网页源的任务说 ---> Status = WaitingForActivation ---> 从来没有 returns 与源。

我已经尝试过异步到同步的转换——可能有十种不同的方法。 None 工作。一个 Whosebug 解决方案建议 Application.DoEvents() - 所以我什至试过了。

希望有人有一些想法。这个浏览器似乎有很多潜力 - 但我需要获取网页源 html.

using System;
using System.Threading.Tasks;
using System.Windows.Forms;
using CefSharp;
using CefSharp.WinForms;
using System.Diagnostics;
namespace Test1
{
    public partial class Form1 : Form
    {
        public ChromiumWebBrowser browser;
        public Form1()
        {
            InitializeComponent();
            InitBrowser();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
        }
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            browser.Dispose();
            Cef.Shutdown();
        }
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }
        public void InitBrowser()
        {
            Cef.Initialize(new CefSettings());
            browser = new ChromiumWebBrowser("https://google.com/");
            this.Controls.Add(browser);
            browser.Dock = DockStyle.Fill;
            browser.FrameLoadEnd += OnWebBrowserFrameLoadEnded;
        }
        void OnWebBrowserFrameLoadEnded(object sender, FrameLoadEndEventArgs e)
        {
            ChromiumWebBrowser BrowserSender = (ChromiumWebBrowser)sender;
            if (this.InvokeRequired)
            {
                this.Invoke(new MethodInvoker(() => { WebBrowserFrameLoadEnded(BrowserSender, e); }));
            }
            else
            {
                WebBrowserFrameLoadEnded(BrowserSender, e);
            }
        }
        void WebBrowserFrameLoadEnded(ChromiumWebBrowser BrowserSender, FrameLoadEndEventArgs e)
        {
            string html1 = null;
            Task<String> taskString1;

            if (e.Frame.IsMain)
            {
                //browser.ViewSource();
                taskString1 = Task.Run(() => GetBrowserSource(browser));
                while (taskString1.Status != TaskStatus.RanToCompletion)
                {
                    Application.DoEvents();
                    System.Threading.Thread.Sleep(100);
                }
                html1 = taskString1.Result;
                Debug.WriteLine("");
            }
        }

        async Task<string> GetBrowserSource(ChromiumWebBrowser Browser)
        {
            return await Browser.GetMainFrame().GetSourceAsync();
        }
    }
}

我的app.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
    </startup>
</configuration>

我的packages.config

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="cef.redist.x64" version="83.4.2" targetFramework="net452" />
  <package id="cef.redist.x86" version="83.4.2" targetFramework="net452" />
  <package id="CefSharp.Common" version="83.4.20" targetFramework="net452" />
  <package id="CefSharp.WinForms" version="83.4.20" targetFramework="net452" />
</packages>

看起来像死锁。这是一个正确的 async/await usage 问题。

private async void WebBrowserFrameLoadEnded(ChromiumWebBrowser BrowserSender, FrameLoadEndEventArgs e)
{
    if (e.Frame.IsMain)
    {
        string html1 = await GetBrowserSource(BrowserSender);
        Debug.WriteLine(html1);
    }
}

但为什么不简单地这样做呢?

private async void OnWebBrowserFrameLoadEnded(object sender, FrameLoadEndEventArgs e)
{
    if (e.Frame.IsMain)
    {
        ChromiumWebBrowser browserSender = (ChromiumWebBrowser)sender;
        string html = await browserSender.GetMainFrame().GetSourceAsync();
        Debug.WriteLine(html);
    }
}

请注意 Application.DoEvents() isn't safe to use