Welcome Guest Search | Active Topics | Sign In | Register

WebView.Capture() hangs after waiting for JavaScript execution Options
svma
Posted: Thursday, November 23, 2023 8:35:09 AM
Rank: Member
Groups: Member

Joined: 10/19/2020
Posts: 12
EO.WebBrowser 23.3.84

We have the following scenario:
Our application (that uses async/await) creates a WebView (with ThreadRunner) that loads some HTML and scripts (using a custom resource handler), then it waits for a completion of some JavaScript (using TaskCompletionSource), then it captures the image.
I
Our application hangs when executed ThreadRunner.Send(() =>{image = webView.Capture();})

Can you help us to resolve the issue?

I created a model application to be more precise.
Please see the sample code below.

Code: C#
public async Task<System.Drawing.Image> GetImage(string url)
        {
            NavigationTask? navTask = null;

            TaskCompletionSource<object?> completionSourceNav = new TaskCompletionSource<object?>();
            TaskCompletionSource<object?> completionSourceJS = new TaskCompletionSource<object?>();

            using JSExecutor jsex = new JSExecutor("rendered", _webView, completionSourceJS);

            _webView.ThreadRunner.Send(() =>
            {
                navTask = _webView.LoadUrl(url);
                navTask.OnDone(() =>
                {
                    completionSourceNav.SetResult(null);
                });
            });

            await completionSourceNav.Task;

            Task timeoutTask = Task.Delay(TimeSpan.FromSeconds(30));

            Task completedOne = await Task.WhenAny(completionSourceJS.Task, timeoutTask);

            if (ReferenceEquals(timeoutTask, completedOne))
            {
                throw new InvalidOperationException("Did not complete in time.");
            }

            System.Drawing.Image? webImage = null;
            _webView.ThreadRunner.Send(() =>
            {
                webImage = _webView.Capture();
            });

            if (webImage == null)
            {
                throw new InvalidOperationException("Could not get image");
            }
            return webImage;
        }
        private class JSExecutor : IDisposable
        {
            private readonly string _funcName;
            private readonly WebView _webView;
            private readonly TaskCompletionSource<object?> _completion;

            private readonly List<string> _consoleMessages = new List<string>();

            internal IEnumerable<string> ConsoleMessages => _consoleMessages;

            internal JSExecutor(string funcName, WebView webView, TaskCompletionSource<object?> completion)
            {
                _funcName = funcName;
                _webView = webView;
                _completion = completion;
                _webView.JSExtInvoke += HandleJSExtInvoke;
                _webView.ConsoleMessage += HandleConsoleMessage;
            }

            private void HandleConsoleMessage(object sender, ConsoleMessageEventArgs e)
            {
                _consoleMessages.Add(e.Message);
            }

            public void Dispose()
            {
                _webView.ConsoleMessage -= HandleConsoleMessage;
                _webView.JSExtInvoke -= HandleJSExtInvoke;
            }

            private void HandleJSExtInvoke(object sender, JSExtInvokeArgs e)
            {
                if (_funcName.Equals(e.FunctionName))
                {
                    _completion.TrySetResult(null);
                }
            }
        }


eo_support
Posted: Thursday, November 23, 2023 10:55:25 AM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,217
Hi,

We are not able to reproduce the problem here with the code you provided. Can you provide a full test project and send the test project to us? See here for more details:

https://www.essentialobjects.com/forum/test_project.aspx

Thanks!
svma
Posted: Sunday, November 26, 2023 10:43:07 AM
Rank: Member
Groups: Member

Joined: 10/19/2020
Posts: 12
Hello, the test project was sent 24 Nov.
eo_support
Posted: Monday, November 27, 2023 11:00:14 PM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,217
Hi,

We did look into the test project. The root of the problem is JSExtInvoke blocks the render thread and Capture must also runs in render thread. The easiest way to fix this problem is to change the following code in HandleJSExtInvoke:

Code: C#
_completion.TrySetResult(null);

To:

Code: C#
_webView.ThreadRunner.Post(() =>
{
    _completion.TrySetResult(null);
});


This ensures JSExtInvoke returns first before _completion.TrySetResult(null) is called. After this you should be able to call Capture without any problem.

Please feel free to let us know if you still have any questions.

Thanks!
svma
Posted: Tuesday, November 28, 2023 10:21:17 AM
Rank: Member
Groups: Member

Joined: 10/19/2020
Posts: 12
Hello,
That helped,

Thank you!
eo_support
Posted: Tuesday, November 28, 2023 10:23:34 AM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,217
You are very welcome. Please feel free to let us know if you run into any other problems.


You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.