Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OffScreen - Clarify BrowserInitialized may not be called if Browser created automatically #3552

Closed
ghost opened this issue May 13, 2021 · 12 comments

Comments

@ghost
Copy link

ghost commented May 13, 2021

Hello,

I don't know how to exactly reproduce this but the code I came up with creates a new window and after finishing initialization disposes it. The problem is after some time the chromium browser doesn't get initialized anymore which happens after a random amount of successful initializations.

using System;
using System.Threading;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            CefSharp.Cef.Initialize(new CefSharp.OffScreen.CefSettings());
            int ok = 0;
            while (true)
            {
                bool init = false;

                var chrome = new CefSharp.OffScreen.ChromiumWebBrowser();
                chrome.BrowserInitialized += (s, e) =>
                {
                    init = true;
                };

                while (!init)
                {
                    Thread.Sleep(5);
                }

                chrome.Dispose();

                ok++;
                Console.WriteLine("Init OK: " + ok);
            }
        }
    }
}
@amaitland
Copy link
Member

Please edit your original question and fill out the bug report temple available at https://github.com/cefsharp/CefSharp/blob/master/.github/ISSUE_TEMPLATE/bug_report.md#bug-report

@ghost
Copy link
Author

ghost commented May 13, 2021

What version of the product are you using?
Nuget 90.6.5

What architecture x86 or x64?
x64

What version of .Net?
.Net 4.x

On what operating system?
Win10

Are you using WinForms, WPF or OffScreen?
OffScreen

What steps will reproduce the problem?
Described in the issue.

What is the expected output? What do you see instead?
I expect every new offscreen browser to be initialized successfully without being stuck in the while loop as per in my reproduce code

Please provide any additional information below.
There are no exceptions or any other noticable feedback of failure.

@amaitland
Copy link
Member

Does the cef log provide any relevant information? (By default there should be a debug.log file in your bin directory)

As per the bug report, did you check the log file?

Have you tested on different hardware?

@ghost
Copy link
Author

ghost commented May 13, 2021

As per the bug report, did you check the log file?
There is nothing relevant in the log files. that's all the content in it

[0513/044556.066:VERBOSE1:pref_proxy_config_tracker_impl.cc(186)] 000000CB121E42C0: set chrome proxy config service to 000000CB12140340
[0513/044556.078:VERBOSE1:webrtc_internals.cc(118)] Could not get the download directory.
[0513/044556.106:VERBOSE1:pref_proxy_config_tracker_impl.cc(186)] 000000CB121E5080: set chrome proxy config service to 000000CB1230F020

Have you tested on different hardware?
I tested it on my windows 10 and my windows 10 vps (which has different hardware and not hosted by me) and both have the same problem.

@amaitland
Copy link
Member

The behaviour suggests a problem with CEF/Chromium. I'd suggest trying the following command line args.

settings.CefCommandLineArgs.Add("disable-gpu");
settings.CefCommandLineArgs.Add("disable-gpu-compositing");

Are you upgrade from a previous version that was working?

@ghost
Copy link
Author

ghost commented May 13, 2021

The behaviour suggests a problem with CEF/Chromium. I'd suggest trying the following command line args.
I already tried this but it but it doesn't fix the problem

Are you upgrade from a previous version that was working?
No I started using cefsharp for like a week.

The reason I want to do this is to create a fresh new incognito window using this code

chrome.Dispose();
var context = new RequestContext();
chrome = new CefSharp.OffScreen.ChromiumWebBrowser("",new BrowserSettings(),context);

is there a workaround that has the same effect as destroying the window and creating a new one?

amaitland added a commit that referenced this issue May 14, 2021
Create/Dispose of 1000 OffScreen ChromiumWebBrowser instances

Issue #3552
@amaitland
Copy link
Member

I already tried this but it but it doesn't fix the problem

On average how many iterations of the loop are you seeing? I've run the following five times now without issues and it creates 2000 browser instances.

// Copyright © 2021 The CefSharp Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

using CefSharp.OffScreen;
using CefSharp.Web;
using System;
using System.Threading.Tasks;

namespace CefSharp.MinimalExample.OffScreen
{
    public static class Program
    {
        public static async Task<int> Main(string[] args)
        {
            for (int i = 0; i < 2000; i++)
            {
                Console.WriteLine("Create ChromiumWebBrowser #" + i);

                using (var browser = new ChromiumWebBrowser(new HtmlString("Testing")))
                {
                    await browser.LoadPageAsync();

                    var source = await browser.GetSourceAsync();

                    if(source.Contains("Testing"))
                    {
                        Console.WriteLine("Source Loaded Successfully");
                    }
                    else
                    {
                        throw new Exception("Html Source doesn't match expected output.");
                    }
                }
            }

            Console.WriteLine("Press enter to continue.");
            Console.ReadLine();

            return 0;
        }

        public static Task LoadPageAsync(this IWebBrowser browser)
        {
            //If using .Net 4.6 then use TaskCreationOptions.RunContinuationsAsynchronously
            //and switch to tcs.TrySetResult below - no need for the custom extension method
            var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);

            EventHandler<LoadingStateChangedEventArgs> handler = null;
            handler = (sender, args) =>
            {
                //Wait for while page to finish loading not just the first frame
                if (!args.IsLoading)
                {
                    browser.LoadingStateChanged -= handler;
                    //This is required when using a standard TaskCompletionSource
                    //Extension method found in the CefSharp.Internals namespace
                    tcs.TrySetResult(true);
                }
            };

            browser.LoadingStateChanged += handler;

            return tcs.Task;
        }
    }
}

is there a workaround that has the same effect as destroying the window and creating a new one?

What exactly are you trying to achieve by creating a new RequestContext? Clean cache? Deleting cookies? Local storage? Need more detail.

@amaitland amaitland added the unable-to-reproduce The problem could not be reproduced by developers label May 14, 2021
@ghost
Copy link
Author

ghost commented May 14, 2021

On average how many iterations of the loop are you seeing? I've run the following five times now without issues and it creates 2000 browser instances.
Sometimes it stops working after 10-1000 but sometimes can take a couple of 1000s without restarting the program. You can easily reproduce it using my code

using System;
using System.Threading;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            CefSharp.Cef.Initialize(new CefSharp.OffScreen.CefSettings());
            int ok = 0;
            while (true)
            {
                bool init = false;

                var chrome = new CefSharp.OffScreen.ChromiumWebBrowser();
                chrome.BrowserInitialized += (s, e) =>
                {
                    init = true;
                };

                while (!init)
                {
                    Thread.Sleep(5);
                }

                chrome.Dispose();

                ok++;
                Console.WriteLine("Init OK: " + ok);
            }
        }
    }
}

What exactly are you trying to achieve by creating a new RequestContext? Clean cache? Deleting cookies? Local storage? Need more detail.
I want to clear everything as if you are creating a fresh new incognito window

@amaitland
Copy link
Member

Sometimes it stops working after 10-1000 but sometimes can take a couple of 1000s without restarting the program. You can easily reproduce it using my code

Did you run the code example I provided?

There's a potential for your code to be problematic, theoretically the underlying CEF browser could be created before you subscribe to the BrowserInitialized event thus leaving your code unresponsive. You can defer creation of the browser until after you've subscribed to the event, see code below for an example.

int ok = 0;
while (true)
{
	bool init = false;

	var chrome = new ChromiumWebBrowser(automaticallyCreateBrowser:false);
	chrome.BrowserInitialized += (s, e) =>
	{
		init = true;
	};

	chrome.CreateBrowser();

	while (!init)
	{
		Thread.Sleep(5);
	}

	chrome.Dispose();

	ok++;
	Console.WriteLine("Init OK: " + ok);
}

I only have an old Dell i3-3240, I suspect faster hardware (even a new VPS would be much faster) might be required to reproduce the problem. At least in theory.

amaitland added a commit that referenced this issue May 16, 2021
Create/Dispose of 1000 OffScreen ChromiumWebBrowser instances

Issue #3552
@amaitland amaitland changed the title CefSharp.OffScreen.ChromiumWebBrowser doesn't initialize OffScreen - Clarify BrowserInitialized may not be called if Browser created automatically May 18, 2021
@amaitland amaitland added offscreen and removed unable-to-reproduce The problem could not be reproduced by developers labels May 18, 2021
@amaitland
Copy link
Member

I've updated the title as I believe the problem is related to timing and the xml doc should be updated to clarify this behaviour. The browser created automatically via the constructor may result in the browser created before the BrowserInitialized even has been subscribed resulting in the event never firing.

@ghost
Copy link
Author

ghost commented May 18, 2021

I have tried your code and for now it looks like it solved the issue. I'll update you if it stops working again or if i encounter an issue or find more information about it. You can close the issue for the time being but if not that's fine. Thank you for the help tho.

@amaitland amaitland added this to the 91.1.x milestone May 20, 2021
amaitland added a commit that referenced this issue May 22, 2021
…rowserCreated delegate

Use the constructor overload as an alternative to the BrowserInitialized event

Follow up to #3552
@amaitland
Copy link
Member

Xml doc has been updated in commit 2568236

Open to suggestions on wording improvements.

I've also added a constructor overload in commit 4ebe7de that takes an Action<IBrowser> which can be used as an alternative.

using (var browser = new ChromiumWebBrowser(TestUrl, browserSettings, requestContext, onAfterBrowserCreated: (b) =>
{
    //Browser has been created (initialized)
    var ident = b.Identifier;
}))
{
    await LoadPageAsync(browser);
}

amaitland added a commit that referenced this issue May 22, 2021
amaitland added a commit that referenced this issue May 22, 2021
…rowserCreated delegate

Use the constructor overload as an alternative to the BrowserInitialized event

Follow up to #3552
@amaitland amaitland removed this from the 91.1.x milestone Jun 4, 2021
@amaitland amaitland added this to the 90.6.x milestone Jun 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant