dotnet / AspNetCore.Docs

Documentation for ASP.NET Core
https://docs.microsoft.com/aspnet/core
Creative Commons Attribution 4.0 International
12.56k stars 25.31k forks source link

JSImport/Export in Maui Blazor Hybrid #31331

Closed hawkerm closed 8 months ago

hawkerm commented 8 months ago

Description

I find this article's examples a bit hard to process, it's not clear exactly what goes where. But following it and trying to run it in my Blazor Maui Hybrid app, I get a "System.Runtime.InteropServices.JavaScript is not supported on this platform." error on the JSHost.ImportAsync line... which I don't understand...

How do I interop with JavaScript in a Blazor Maui Hybrid app? With all the different flavors of Blazor/ASP/MAUI Hybrid configurations out there, it's very difficult to find the right proper documentation or know if the documentation applies to the specific setup of my project.

Page URL

https://learn.microsoft.com/en-us/aspnet/core/blazor/javascript-interoperability/import-export-interop?view=aspnetcore-8.0

Content source URL

https://github.com/dotnet/AspNetCore.Docs/blob/main/aspnetcore/blazor/javascript-interoperability/import-export-interop.md

Document ID

8aab92a0-c05f-ef01-fb74-a0bf525aae69

Article author

@guardrex

github-actions[bot] commented 8 months ago

πŸ‚πŸŽ Happy Holidays! ❄️⛄

This issue has been marked for triage on the Blazor Docs GitHub project, and I'll respond as soon as I return from the holiday vacation the second week of January.

We only work on documentation on this repo. If you need product support, close this issue and seek assistance through one or more of the following support channels:

If you think that you found a potential bug in the framework or have product feedback, close this issue and open a new issue for the ASP.NET Core product unit at dotnet/aspnetcore issues. Bug reports require a clear explanation of the problem, usually including a minimal repro project placed on GitHub for the product unit engineers to download and run. If you determine with the product unit that it isn't a bug but merely requires documentation, please re-open this docs issue and place a cross-link to your engineering issue discussion.

For problems or feedback on Visual Studio, close this issue and use the Report a Problem or Suggest a Feature processes from within VS, which open internal issues for the VS product unit. For more information, see Visual Studio Feedback.

For problems with Visual Studio Code, close this issue and ask for support on community support forums. For bug reports and product feedback, open an issue on the microsoft/vscode GitHub repo.

πŸ’ƒπŸ•ΊπŸ₯³ Happy New Year! πŸŽˆπŸŽ†πŸΎπŸ₯‚πŸŽ‰ See you in 2024!

hawkerm commented 8 months ago

Ugh, looks like this isn't a supported scenario? https://github.com/dotnet/maui/issues/13551 - though then I don't understand what the equivalent is...

guardrex commented 8 months ago

Hello @hawkerm ... Yes, I was just typing that .........

As the article states ...

This article describes an alternative JS interop approach specific to client-side components executed on WebAssembly.

... so this article's scenarios aren't appropriate for MAUI+Blazor apps. You should use the guidance in the other two articles mentioned ...

I'll make an additional adjustment to explicitly direct Blazor Hybrid readers to those two articles. Leave this issue open. It will close automatically when the PR merges.

hawkerm commented 8 months ago

Thanks @guardrex, I've found those articles as well, but haven't had luck applying any of the examples to my code for Maui Blazor Hybrid as well. Especially the module one that uses IJSObjectReference, as it throws an error that deserialization of interfaces isn't supported. Is there a dedicated example/sample repo somewhere that shows how to do this with Maui Blazor Hybrid?

Related: https://github.com/dotnet/maui/discussions/8041

guardrex commented 8 months ago

No, we don't ... and I've only assumed that the guidance works in Blazor Hybrid apps because the PU ("product unit") engineers never told me that it wouldn't work.

I think it best if I find some time to try a simple JS call and a simple .NET call in a MAUI-Blazor app to see if I can repro a problem. I have some time this morning, so I'll try a test within the hour and get back to you. Stand-by .....................

guardrex commented 8 months ago

I don't see a problem in a basic test. I used the first one, the CallJs1 component example, which is in a nutshell ....

The script added in index.html under the Blazor script ...

<script>
    window.convertArray = (win1251Array) => {
        var win1251decoder = new TextDecoder('windows-1251');
        var bytes = new Uint8Array(win1251Array);
        var decodedArray = win1251decoder.decode(bytes);
        console.log(decodedArray);
        return decodedArray;
    };
</script>

... with the code to call it in the Home component ...

@page "/"
@inject IJSRuntime JS

<h1>Hello, world!</h1>

Welcome to your new app.

<p>
    <button @onclick="ConvertArray">Convert Array</button>
</p>

<p>
    @text
</p>

@code {
    private MarkupString text;

    private uint[] quoteArray =
        new uint[]
        {
            60, 101, 109, 62, 67, 97, 110, 39, 116, 32, 115, 116, 111, 112, 32,
            116, 104, 101, 32, 115, 105, 103, 110, 97, 108, 44, 32, 77, 97,
            108, 46, 60, 47, 101, 109, 62, 32, 45, 32, 77, 114, 46, 32, 85, 110,
            105, 118, 101, 114, 115, 101, 10, 10,
        };

    private async Task ConvertArray()
    {
        text = new(await JS.InvokeAsync<string>("convertArray", quoteArray));
    }
}

I get ...

image

Next, I try a collocated module example JsCollocation2 component at https://learn.microsoft.com/en-us/aspnet/core/blazor/javascript-interoperability/?view=aspnetcore-8.0#load-a-script-from-an-external-javascript-file-js-collocated-with-a-component. That one goes ...

Components/Pages/JsCollocation2.razor:

@page "/js-collocation-2"
@implements IAsyncDisposable
@inject IJSRuntime JS

<PageTitle>JS Collocation 2</PageTitle>

<h1>JS Collocation Example 2</h1>

<button @onclick="ShowPrompt">Call showPrompt2</button>

@if (!string.IsNullOrEmpty(result))
{
    <p>
        Hello @result!
    </p>
}

@code {
    private IJSObjectReference? module;
    private string? result;

    protected async override Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            module = await JS.InvokeAsync<IJSObjectReference>("import",
                "./Components/Pages/JsCollocation2.razor.js");
        }
    }

    public async void ShowPrompt()
    {
        if (module is not null)
        {
            result = await module.InvokeAsync<string>(
                "showPrompt2", "What's your name?");
            StateHasChanged();
        }
    }

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (module is not null)
        {
            await module.DisposeAsync();
        }
    }
}

... added to the NavMenu to get to it ...

<div class="nav-item px-3">
    <NavLink class="nav-link" href="js-collocation-2">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> JS Col 2
    </NavLink>
</div>

... with ...

Components/Pages/JsCollocation2.razor.js:

export function showPrompt2(message) {
  return prompt(message, 'Type your name here');
}

I have the prompt ...

image

... and the value is returned to the component ...

image

I can't repro a problem here. I'm not going to try the .NET call because I think I'll get the same result. I'm slammed with work, so I think at this point it's more of a support request than a docs problem ... at least a docs problem that I understand.

I recommend that you open an issue for the product unit ... and you should place a minimal repro on GH for them to look at and/or show your exact code ...

https://github.com/dotnet/aspnetcore/issues

Please add ...

cc: @guardrex https://github.com/dotnet/AspNetCore.Docs/issues/31331

... to the bottom of your opening comment so that I can follow along. I might re-open this for doc work depending on what they say.