|
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);
}
}
}
|
|
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.aspxThanks!
|
|
Rank: Member Groups: Member
Joined: 10/19/2020 Posts: 12
|
Hello, the test project was sent 24 Nov.
|
|
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!
|
|
Rank: Member Groups: Member
Joined: 10/19/2020 Posts: 12
|
Hello, That helped,
Thank you!
|
|
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.
|
|