KennanChan / Revit.Async

Use task-based asynchronous pattern (TAP) to run Revit API code from any execution context.
MIT License
223 stars 51 forks source link

Hanging when calling via CefSharp #8

Closed lawsonAGMT closed 3 years ago

lawsonAGMT commented 3 years ago

We've been using Revit.Async for a while on our project and generally it works great!

However, recently we've run into an issue where running a task from a CefSharp callback never terminates.

CefSharp is a utility that allows us to trigger C# code from an embedded browser in Revit. The callback must be synchronous, like so:

public string GetSomeData()
{
    var task = RevitTask.RunAsync(app => getSomethingFromRevit(app));
    task.Wait();
    return task.Result;
}

GetSomeData() will be invoked by CefSharp via our Javascript code (I have not been able to find information about how or where exactly it is invoked.)

This has been working fine for a while, but recently it has started hanging on task.Wait(). I suspect this is related to the well-known issue of deadlock when calling async code from a synchronous context.

However, I've tried pretty much every workaround I have found on the internet, including adding .ConfigureAwait(false) to all of the await calls in the Revit.Async code.

If anyone has any ideas of what might be going on, it would be greatly appreciated.

lawsonAGMT commented 3 years ago

Update: It seems that this occurs when the UI in CefSharp is continuously updated while the callback is being executed (loading animation). The weird thing is, the freezing only occurs when the addin is run without a visual studio debugger attached...

KennanChan commented 3 years ago

Calling Wait() is not wise in UI thread, generally you can push result back when an asynchromous task finishes. If there isn't a way to do that, just do some polling to get the result periodically. I did some research and it seems CEFSharp has supported returning Task from .NET, see https://github.com/cefsharp/CefSharp/issues/2758 You can also use a callback to resolve this issue

lawsonAGMT commented 3 years ago

Unfortunately, Revit doesn't support the newest version of CefSharp that natively supports async :(

I suppose polling would work, thanks for the suggestion!

What exactly do you mean by using a callback to resolve it?

KennanChan commented 3 years ago

@lawsonAGMT https://github.com/cefsharp/CefSharp/wiki/Advanced-Async-JavaScript-Binding-(JSB)

KennanChan commented 3 years ago

If you pass a js function down to .NET, you will get an IJavascriptCallback object by which you can pass data back. In your javascript code, you can do some wrapping using Promise to use async fashion

lawsonAGMT commented 3 years ago

Thanks. I tried the polling method which surprisingly didn't work either.

But, an interesting turn of events.. I switched from using CefSharp with WPF to CefSharp with WinForms and everything is working again. Notably, the web page performance is much better. I think the WPF off-screen rendering technique is just so resource hungry it wasn't letting anything else get scheduled...

Looks like this is more of a CefSharp issue than Revit.Async so will close. Thanks for sharing your thoughts!