Callbacks with return value not supported on server-side Blazor
See original GitHub issueWith #70 I have reworked the interop-layer once more to provide a type-safe way of invoking any delegate from JavaScript without writing much new code on either side for different callbacks. Apart from that I also implemented the first case of callbacks that return a value (namely Custom Ticks Format callback). The procedure of such a callback is as follows:
Chart.js will first call from JavaScript into C# with some arguments which will be deserialized (that’s why we need #84 and more). Then on the C# side, we can handle these arguments and produce a response that will be serialized again and returned to the JavaScript caller.
The chart.js callbacks are synchronous, not async (at least I haven’t seen any). That means they expect the actual value to be returned, not a promise (or generator). This obviously means that the value has to be returned to the chart.js handler synchronously. On client-side this is quite easy because the JavaScript dispatcher from wasm blazor has the ability to invoke C# from JavaScript synchronously. But now lets talk about server-side. Server-side blazor is built on SignalR which is built on websockets. JavaScript websockets and SignalR are async (I don’t know either very well but afaik they only work async). That means there is just no way to do synchronous JavaScript-C# interop.
What have I tried/considered without success:
- Flattening the
Promise
object of an async JavaScript function by synchronously waiting for it. This would be the equivalent of the C#Task.Wait()
. However, by the nature of JavaScript this just doesn’t seem to be possible. I have asked a StackOverflow question about this and it pretty much confirmed just that it’s not possible. - When searching for how to work with promises in a synchronous manner, I found out about an approach using generators. I have played around with it but this just shifts the issue from
Promise
objects toGenerator
objects which doesn’t help us. I wrote about that approach in this issue comment. - Rewriting chart.js; of course not feasible.
Now the question is what to do. In the current (#70) implementation of the interop layer, it just writes a warning in the browser with console.warn()
and falls back to the default handler if you supply a C# handler to a callback that expects a return value. JavaScript handlers are still fully supported and work perfectly fine even with return values.
Now I would like to know some opinions on this. What should happen when it’s not supported? Is there still hope to make this work? Because I genuinely don’t see any way to make this work for server-side. Is this warning enough? Where do we document this that it’s discoverable and no one wastes time trying to get it to work?
What do you think?
Additional stuff
- Similar explanation to this issue in an issue comment.
- Reworking the interop layer to be more robust and minimizing the boilerplate code required for new callbacks is the start of realizing #62, #41 and much more.
Issue Analytics
- State:
- Created 3 years ago
- Reactions:2
- Comments:6 (1 by maintainers)
Hey @Joelius300,
it’s a great question.
I don’t have a proper solution, but I can say that you’re not alone with this problem…
In one application I did a port of Ag-Grid to Blazor, and I had exactly the same issue. Everything works good, selection, column definitions etc. But the Ag-Grid allows also custom cell renderers. And these are synchronous JavaScript functions that return a piece of HTML.
I got it working without issues in Blazor WASM with synchronous JS calls. But in Blazor Server, I was tackling exactly the same problems like you.
Cheers, Thomas
From my side #70 is now complete. I’ve decided to keep the warning and document it accordingly once we’re done. It’ll be in the wiki and the readme as well. This change is part of release 2.0 where we’ll also need to invest some time into better documentation.
It’s unfortunate that this can’t be supported on server-side but as of today, there appears to be no way to make it possible.
I will remove the discussion label to this. However, it’ll stay open for any progress made in this area. I highly doubt that this is something we can support but it’s definitely something we want to support so it’ll stay. Because this will be a big question asked by many, this issue will be pinned again once the feature releases.
We’re very grateful for any insights you can share on this.