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.