cefsharp / CefSharp

.NET (WPF and Windows Forms) bindings for the Chromium Embedded Framework

Home Page:http://cefsharp.github.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

OffScreen - ChromeRuntime doesn't work with LoadURL

GrabzIt opened this issue · comments

Is there an existing issue for this?

  • I have searched both open/closed issues, no issue already exists.

CefSharp Version

125.0.210

Operating System

Windows 10

Architecture

x64

.Net Version

.NET 6.0

Implementation

OffScreen

Reproduction Steps

        public static int Main(string[] args)
        {
            const string testUrl = "https://grabz.it/";

            Console.WriteLine("This example application will load {0}, take a screenshot, and save it to your desktop.", testUrl);
            Console.WriteLine("You may see Chromium debugging output, please wait...");
            Console.WriteLine();

            //Console apps don't have a SynchronizationContext, so to ensure our await calls continue on the main thread we use a super simple implementation from
            //https://devblogs.microsoft.com/pfxteam/await-synchronizationcontext-and-console-apps/
            //Continuations will happen on the main thread. Cef.Initialize/Cef.Shutdown must be called on the same Thread.
            //The Nito.AsyncEx.Context Nuget package has a more advanced implementation
            //should you wish to use a pre-build implementation.
            //https://github.com/StephenCleary/AsyncEx/blob/8a73d0467d40ca41f9f9cf827c7a35702243abb8/doc/AsyncContext.md#console-example-using-asynccontext
            //NOTE: This is only required if you use await

                var settings = new CefSettings()
                {
                    ChromeRuntime = true,
                    //By default CefSharp will use an in-memory cache, you need to specify a Cache Folder to persist data
                    CachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CefSharp\\Cache")
                };

                //Perform dependency check to make sure all relevant resources are in our output directory.
                var success = Cef.Initialize(settings, performDependencyCheck: true, browserProcessHandler: null);

                if (!success)
                {
                    throw new Exception("Unable to initialize CEF, check the log file.");
                }

                // Create the CefSharp.OffScreen.ChromiumWebBrowser instance
                using (var browser = new ChromiumWebBrowser(string.Empty))
                {
                    browser.FrameLoadEnd += Browser_FrameLoadEnd;
                    browser.LoadUrl(testUrl);
                    // Wait for user to press a key before exit
                    Thread.Sleep(20000);
                }

                // Clean up Chromium objects. You need to call this in your application otherwise
                // you will get a crash when closing.
                Cef.Shutdown();

            return 0;
        }

        private async static void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e)
        {
            if (e.Frame.IsValid && e.Frame.IsMain)
            {
                var bitmapAsByteArray = await ((ChromiumWebBrowser)sender).CaptureScreenshotAsync();

                // File path to save our screenshot e.g. C:\Users\{username}\Desktop\CefSharp screenshot.png
                var screenshotPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "CefSharp screenshot.png");

                Console.WriteLine();
                Console.WriteLine("Screenshot ready. Saving to {0}", screenshotPath);

                File.WriteAllBytes(screenshotPath, bitmapAsByteArray);

                Console.WriteLine("Screenshot saved. Launching your default image viewer...");

                // Tell Windows to launch the saved image.
                Process.Start(new ProcessStartInfo(screenshotPath)
                {
                    // UseShellExecute is false by default on .NET Core.
                    UseShellExecute = true
                });
                Console.WriteLine("Image viewer launched. Press any key to exit.");
            }
        }

Expected behavior

This should load the url and display a screenshot but when ChromeRuntime = true it never works. However, it does if you remove ChromeRuntime = true.

Actual behavior

It never fires the browser loaded event.

Regression?

No response

Known Workarounds

No response

Does this problem also occur in the CEF Sample Application

Yes using WPF/OffScreen command line args

Other information

No response

However, it does if you remove ChromeRuntime = true.

Given it works with the alloy runtime this likely needs to be fixed in CEF.

@GrabzIt Looking at the code in more detail, can you defer creation of the browser until after you've subscribed to the event? e.g.

// Create the CefSharp.OffScreen.ChromiumWebBrowser instance
using (var browser = new ChromiumWebBrowser(testUrl, automaticallyCreateBrowser:false))
{
  browser.FrameLoadEnd += Browser_FrameLoadEnd;
  browser.CreateBrowser();
  // Wait 
  Thread.Sleep(20000);
}

Thanks, this approach works and seems to work with further calls to LoadURL and adding and removing the event: e.g.

              using (var browser = new ChromiumWebBrowser(testUrl, automaticallyCreateBrowser: false))
              {
                    browser.FrameLoadEnd += Browser_FrameLoadEnd;
                    browser.CreateBrowser();
                    Thread.Sleep(20000);
                    browser.FrameLoadEnd += Browser_FrameLoadEnd;
                    browser.LoadUrl("https://grabz.it/about/");
                    Thread.Sleep(20000);
              }

        private async static void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e)
        {
            if (e.Frame.IsValid && e.Frame.IsMain)
            {
                Console.WriteLine(e.Url);
                ((ChromiumWebBrowser)sender).FrameLoadEnd -= Browser_FrameLoadEnd;
            }
        }

Is this the way it should be used from now or are the CEF changes to the chrome runtime going to fix the issue?

Is this the way it should be used from now

That would be my recommendation. Pretty sure I modified most of the examples/tests a while back to use this approach. If there are any outstanding then happy to update them.

are the CEF changes to the chrome runtime going to fix the issue?

From a CefSharp point of view it probably makes sense to defer browser creation automatically if you pass in string.Empty, create the browser on the next load call.

That sounds great thanks.