从CEFSharp

时间:2018-03-22 19:18:11

标签: c# async-await chromium-embedded cefsharp

我正在使用CEFSharp开发一个项目,它基本上是Chromium Embedded Framework的互操作包装器。该应用程序的目的是使用Chrome引擎的内置转换器加载许多URL并将网页保存为PDF文件。

有时,我尝试加载的其中一个网址会导致问题,而Chromium Web Browser实例将不再有效。由于我不知道API中的任何重新初始化方法,我只需处理当前实例并创建一个新实例。下面的代码说明了我是如何做到的。

代码似乎工作得很好,但有时甚至重新初始化并不能解决我的问题。我想知道我是否做了一些在我的例子中不合适的事情。任何建议都会有用。

另外几个注意事项:在Windows 7计算机上运行它(不要问,我别无选择),我必须将其编译为x86 32位应用程序,因为我正在利用一些较旧的COM互操作组件在应用程序中(不,我不能编译为x64),我使用最新的Nuget版本63.0.2,并不完全确定哪个版本的CEF正在使用。

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using CefSharp;
using CefSharp.OffScreen;
using CEFNotes.Domain;
using log4net;

namespace CEFNotes.Browser
{
    public sealed class WebBrowser : IDisposable
    {
        private static WebBrowser _webBrowser;
        private readonly ILog _log = LogManager.GetLogger(typeof(WebBrowser));

        private readonly Dictionary<string, bool> _badHosts = new Dictionary<string, bool>();

        private readonly PdfPrintSettings _printSettings = new PdfPrintSettings
        {
            HeaderFooterEnabled = false,
            HeaderFooterTitle = string.Empty, //Constants.Library,
            HeaderFooterUrl = "",
            PageHeight = 0,
            PageWidth = 0,
            Landscape = "Landscape".Equals(Constants.Orientation),
            MarginType = CefPdfPrintMarginType.Default,
            MarginBottom = 0,
            MarginLeft = 0,
            MarginRight = 0,
            MarginTop = 0,
            SelectionOnly = false,
            BackgroundsEnabled = true
        };

        private ChromiumWebBrowser _browser;
        private bool _disposed;

        private WebBrowser()
        {
            _browser = new ChromiumWebBrowser(string.Empty, new BrowserSettings {WindowlessFrameRate = 1})
            {
                RequestHandler = new BrowserRequestHandler()
            };
            var result = Task.Run(async () => await BrowserInitializedAsync()).Result;
            if (!result) throw new ApplicationException("Unable to initialize browser.");
        }

        public static WebBrowser Instance => _webBrowser ?? (_webBrowser = new WebBrowser());

        public async Task<string> GetHtml()
        {
            return await _browser.GetSourceAsync();
        }

        private Task<bool> BrowserInitializedAsync()
        {
            var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
            EventHandler handler = null;
            handler = (sender, args) =>
            {
                _browser.BrowserInitialized -= handler;
                tcs.TrySetResult(true);
            };
            if (!_browser.IsBrowserInitialized)
                _browser.BrowserInitialized += handler;
            else
                tcs.TrySetResult(true);
            return tcs.Task;
        }

        public bool Reinitialize()
        {
            try
            {
                _browser.Dispose();
                _browser = null;
                _browser = new ChromiumWebBrowser(string.Empty, new BrowserSettings {WindowlessFrameRate = 1})
                {
                    RequestHandler = new BrowserRequestHandler()
                };
                return Task.Run(async () => await BrowserInitializedAsync()).Result;
            }
            catch (Exception ex)
            {
                _log.Error("Unable to reinitialize", ex);
            }

            return false;
        }

        /// <summary>
        ///     Retrieve the HTML document for the specified URL
        /// </summary>
        /// <param name="address">The URL for the specific document being retrieved.</param>
        /// <returns>Returns a Task with bool value associated with it.</returns>
        /// <remarks>
        ///     https://github.com/cefsharp/CefSharp/issues/1415
        /// </remarks>
        public Task<bool> LoadPageAsync(string address = null)
        {
            var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);

            const int timeout = 20000; // 20 seconds
            var timer = new Timer(obj =>
                {
                    try
                    {
                        if (!tcs.Task.IsCompleted) tcs.TrySetResult(false);
                    }
                    catch (Exception ex)
                    {
                        tcs.TrySetException(ex);
                    }
                }
                , null, timeout, Timeout.Infinite);

            var timer1 = timer;
            tcs.Task.ContinueWith(t =>
                {
                    //Console.WriteLine("Dispose Continuation ran value is " + t.Status.ToString());
                    timer1.Dispose();
                }
            );

            EventHandler<LoadingStateChangedEventArgs> handler = null;
            handler = (sender, args) =>
            {
                //Wait for while page to finish loading not just the first frame
                if (!args.IsLoading)
                {
                    if (handler != null) _browser.LoadingStateChanged -= handler;
                    tcs.TrySetResult(true);
                }
            };

            _browser.LoadingStateChanged += handler;

            if (!string.IsNullOrEmpty(address)) _browser.Load(address);

            return tcs.Task;
        }

        public Task<bool> PrintToPdfAsync(string path)
        {
            var browser = _browser.GetBrowser();
            var host = browser.GetHost();
            var callback = new PrintToPdfCallbackAsync();
            host.PrintToPdf(path, _printSettings, callback);
            return callback.Task;
        }

        public void BadHostCallback(string host)
        {
            if (!_badHosts.ContainsKey(host)) _badHosts.Add(host, true);
        }

        public bool IsBadHost(string host)
        {
            return _badHosts.ContainsKey(host);
        }

        #region IDisposable

        ~WebBrowser()
        {
            Dispose(false);
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing)
        {
            if (_disposed) return;

            if (disposing) _browser.Dispose();

            _disposed = true;
        }

        #endregion
    }
}

0 个答案:

没有答案
相关问题