Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blazor/Microsoft.JSInterop compatibility #710

Open
mmarinchenko opened this issue May 3, 2023 · 1 comment
Open

Blazor/Microsoft.JSInterop compatibility #710

mmarinchenko opened this issue May 3, 2023 · 1 comment

Comments

@mmarinchenko
Copy link
Contributor

Issue background

We are experimenting with cross-platform 3D visualization running inside Uno.WinUI shell. This issue covers WebAssebly case, so if we forget about other platforms, some kind of JavaScript 3D engine, such as Babylon.js, could be used as a workaround. But ideally, we would like to go Uno-way as much as possible, so the 3D engine should be cross-platform and run on .NET.

One potentially possible third-party option is Plain Concepts' Evergine. Like most Blazor-related libraries, Evergine uses Microsoft.AspNetCore.Components.WebAssembly package, which, in turn, relies on Microsoft.JSInterop to interact with JavaScript API. As a result, we basically need a JavaScript infrastructure that would be compatible with both Uno.Wasm.Bootstrap and Microsoft.JSInterop.

Please note that Evergine is just an example to provide the issue background. We are not part of Evergine team or any other Plain Concepts affiliate. Feel free to provide us with any other cross-platform .NET 3D visualization solution compatible with Uno, if you have one.

Why might this be important for Uno?

Number of .NET libraries, ported to WebAssembly, is constantly growing.

Some of them require interaction with JavaScript API. Microsoft.JSInterop, for obvious reasons, is used by default unless they assume compatibility specifically with Uno.

Some of them have a proprietary license (like Evergine still has) and cannot be modified by third party. The lack of compatibility between the two technologies may slow down Uno/.NET adoption in WebAssembly world.

Our investigations

dotnet.js bundled with Uno has the following functions (see 0004-restore-jsinterop-invokejsunmarshalled.patch):

function mono_wasm_invoke_js_blazor(e, t, r, n, o) {
    try {
        const e = globalThis.Blazor;
        if (!e)
            throw new Error("The blazor.webassembly.js library is not loaded.");
        return e._internal.invokeJSFromDotNet(t, r, n, o)
    } catch (t) {
        const r = t.message + "\n" + t.stack, n = mono_wasm_new_root();
        return js_string_to_mono_string_root(r, n), n.copy_to_address(e), n.release(), 0
    }
}

function mono_wasm_invoke_js_unmarshalled(e, t, r, n, o) {
    try {
        const e = conv_string(t), s = globalThis.DotNet;
        if (!s)
            throw new Error("The Microsoft.JSInterop.js library is not loaded.");
        const _ = undefined;
        return s.jsCallDispatcher.findJSFunction(e).call(null, r, n, o)
    } catch (t) {
        const r = t.message + "\n" + t.stack, n = wrapped_c_functions.mono_wasm_string_from_js(r);
        return Module.setValue(e, n, "i32"), 0
    }
}

The first mentioned function invokes Blazor._internal.invokeJSFromDotNet(...) which isn't present in Uno. It could be added in an additional JS script as EmbeddedResource, but the problem is that the Blazor._internal object, on the other hand, is present in Uno and written in a non-extensible way: it uses direct assignment of anonymous object, which overwrites any additions.

We've tried to customize this code to add Blazor._internal.invokeJSFromDotNet(...), but it isn't clear to us which implementation should be used here. The ASP.NET Core implementation (as of version 6.0) uses DotNet.jsCallDispatcher object, which is also present in Uno, but has a completely different implementation (including DotNet.jsCallDispatcher.findJSFunction(...) which is invoked by the second mentioned function from dotnet.js bundled with Uno).

Neither blazor.webassembly.js nor Microsoft.JSInterop.js can be used directly with Uno, because this breaks everything. So what should we do?

Additional notes

https://github.com/mmarinchenko/UnoWasmApp repository contains empty Uno application with Wasm head. Last commit adds the Microsoft.AspNetCore.Components.WebAssembly package and the Microsoft.AspNetCore.Components.WebAssembly.Hosting.WebAssemblyHostBuilder.CreateDefault() call to reproduce the issue. No other changes were made, except for some minor format and package version fixes.

P.S. This could be a success story in the future if we solve this issue!

@jeromelaban
Copy link
Member

If I'm not mistaken, this particular set of API is now discouraged as it is not performant, and it is best to use JSImport/JSExport attributes, which Uno supports properly. Are you able to use this approach instead?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants