Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invoke async method from JS in CefSharp

How can I invoke an .NET async method from JS in CefSharp. I'd like to invoke a method that waits for a console application call.

My idea is the following: I invoke a method with the signature below:

public async Task<int> Calculate(){

and when it's finished then its result is given back by a promise on the JS side. Currently, it doesn't work. When it's finished there is no callback and then I'm not able to invoke it again.

Thank you

like image 666
Lajos Avatar asked Jul 27 '26 23:07

Lajos


1 Answers

I came up against the same issue.

An ugly workaround seems to be mangling your method to async void and accepting two IJavascriptCallback arguments (resolve and reject).

For example:

public class MyCalculator
{
    public async void CalcAsync(
        string name,
        IJavascriptCallback resolve,
        IJavascriptCallback reject)
    {
        try
        {
            if (resolve.IsDisposed)
                return;

            int i = /* compute i */;

            if (!resolve.IsDisposed)
               await resolve.ExecuteAsync(i);
        }
        catch (Exception e)
        {
            if (!reject.IsDisposed)
                await reject.ExecuteAsync(e.ToString());
        }
    }
}

Registered as:

browser.RegisterAsyncJsObject("myCalculator", new MyCalculator());

Then in your JavaScript:

function doThingAsync(name) {
    return new Promise(function (resolve, reject) {
        window.myCalculator.calcAsync(name, resolve, reject);
    });
}

var result = await doThingAsync("foo")

You can pull the pattern out as something like:

private static async Task Promisify(IJavascriptCallback resolve, IJavascriptCallback reject, Func<Task> action)
{
    try
    {
        if (!resolve.IsDisposed)
            await action();

        if (!resolve.IsDisposed)
            await resolve.ExecuteAsync();
    }
    catch (Exception e)
    {
        if (!reject.IsDisposed)
            await reject.ExecuteAsync(e.ToString());
    }
}

private static async Task Promisify<T>(IJavascriptCallback resolve, IJavascriptCallback reject, Func<Task<T>> action)
{
    try
    {
        var result = default(T);

        if (!resolve.IsDisposed)
            result = await action();

        if (!resolve.IsDisposed)
            await resolve.ExecuteAsync(result);
    }
    catch (Exception e)
    {
        if (!reject.IsDisposed)
            await reject.ExecuteAsync(e.ToString());
    }
}

The bound object's methods would then resemble:

public class MyCalculator
{
    public async void CalcAsync(
        string name,
        IJavascriptCallback resolve,
        IJavascriptCallback reject)
    {
        Promisify(resolve, reject, () => /* compute i */);
    }
}

The (hypothetical) API I'd like to use would resemble:

public class MyCalculator
{
    public async Task<int> CalcAsync(string name) => /* compute i */;
}

And:

var result = await window.myCalculator.calcAsync("foo")
like image 115
Drew Noakes Avatar answered Jul 29 '26 13:07

Drew Noakes



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!