2

I'm trying to use EvaluateScriptAsPromiseAsync with CefSharp.

It seems to work in the browser, but I get a null result in cefSharp.

Javascript:

(async function() {
    const result = await $.ajax({ type: 'GET', url: './robots.txt' });
    return result;
})();

CSharp Code:

var result = await browser.EvaluateScriptAsPromiseAsync(script);
Debug.Assert(result.Result != null);

Full Code:


public partial class Form1 : Form
    {
        ChromiumWebBrowser browser;
        public Form1()
        {
            InitializeComponent();
            browser = new ChromiumWebBrowser("jquery.com");
            this.Controls.Add(browser);

            browser.FrameLoadEnd += Browser_FrameLoadEnd;

        }

        private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e)
        {
            const string script = @"(async function() {
                const result = await $.ajax({ type: 'GET', url: './robots.txt' });
            return result;
        })();";
            if (e.Frame.IsMain)
            {
                // Get us off the main thread
                Task task = new Task(async () =>
                {
                    var result = await browser.EvaluateScriptAsPromiseAsync(script);
                    Debug.Assert(result.Result != null);
                });
                task.Start();
            }
        }

    }
Peter Godwin
  • 77
  • 11
  • When you pass your JavaScript to Promise.resolve does it return a promise? CEF doesn't have first class support for promises so I'm relying on Promise.resolve to turn the JavaScript into a promise https://github.com/cefsharp/CefSharp/blob/cefsharp/86/CefSharp/WebBrowserExtensions.cs#L1049 possibly it returns null – amaitland Dec 10 '20 at 07:58
  • Does it work if you remove the async and await statements from your JavaScript? Basically directly return the promise – amaitland Dec 10 '20 at 07:59
  • No luck removing the await/async, and good idea testing with Promise.resolve. Changing the script to `return new Promise((resolve)=>$.ajax({ type: 'GET', url: './robots.txt' }).then(r=>resolve(r)));` worked though! – Peter Godwin Dec 10 '20 at 23:02
  • Does $.ajax return an ES6 promise or a promise like object? CefSharp uses Promise.resolve internally, the result of the script execution is passed directly to Promise.resolve – amaitland Dec 11 '20 at 00:05
  • An overload on `EvaluateScriptAsPromiseAsync` with isASync might work. I'll send through a PR. – Peter Godwin Dec 11 '20 at 00:18
  • Can you clarify please – amaitland Dec 11 '20 at 00:20
  • $.ajax is supposed to return a promise. Return $.ajax directly wouldn't work, it would just result in a null result. – Peter Godwin Dec 11 '20 at 00:27
  • I'm not sure what an isAsync overload looks like. You are welcome to submit a PR. – amaitland Dec 11 '20 at 00:32
  • https://stackoverflow.com/a/38447990/4583726 suggests that it should work directly. I'm not in front of a computer at the moment so I cannot test. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve#Resolving_thenables_and_throwing_Errors – amaitland Dec 11 '20 at 00:39
  • [PR raised](https://github.com/cefsharp/CefSharp/pull/3314). Thanks again for your assistance. – Peter Godwin Dec 11 '20 at 01:38

1 Answers1

5

So the IIFE in the example above evaluates as a Promise, the extra step required is to actually return the promise. Scripts passed to EvaluateScriptAsPromiseAsync MUST return a value otherwise you'll get null.

Differs from other EvaluateScriptAsync methods in that you must return a result.

//This will return 42
await browser.EvaluateScriptAsPromiseAsync("return 42");
//This will return undefined
await browser.EvaluateScriptAsPromiseAsync("42");

As per https://github.com/cefsharp/CefSharp/pull/3251

Because it's wrapped in an IIFE which is then passed to Promise.resolve, you need to return the result. e.g.

return (async function() {
    const result = await $.ajax({ type: 'GET', url: './robots.txt' });
    return result;
})();
private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e)
{
    const string script = @"return (async function() { const result = await $.ajax({ type: 'GET', url: './robots.txt' }); return result; })();";
    if (e.Frame.IsMain)
    {
        // Use the Thread Pool
        Task.Run(async () =>
        {
            var result = await browser.EvaluateScriptAsPromiseAsync(script);
            Debug.Assert(result.Result != null);
        });
    }
}
amaitland
  • 4,073
  • 3
  • 25
  • 63