dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.16k stars 9.92k forks source link

Allow JS.InvokeAsync<IJSObjectReference> calls to return null/undefined #52070

Open SteveSandersonMS opened 9 months ago

SteveSandersonMS commented 9 months ago

Discovered by @tlmii as an issue Aspire Dashboard, or in fact in the underlying Fluent UI library

Currently, if you do either of these:

... you get an error: Cannot create a JSObjectReference from the value 'null' (or undefined)

This makes it inconvenient to call a JS function that may return null or undefined.

Workaround

On the .NET side, you can define a struct like:

    private struct MyResult
    {
        public IJSObjectReference? Value { get; set; }
    }

... and then call js.InvokeAsync<MyResult>(...), and then on the JS side you'd do:

    return {
        value: something ? DotNet.createJSObjectReference(something) : null
    };

... so that createJSObjectReference is only called conditionally on there being a value for it. On the .NET side, you can then check whether result.Value is null.

However this is all very inconvenient.

Proposal

At minimum, we should change DotNet.createJSObjectReference so that if the supplied value is null/undefined, that's not an error, and we just track the null/undefined value in the same way we track nonempty values. This would not be a breaking change, since it gave an exception before.

If we wanted to go further, we could extend IJSObjectReference to have a bool HasValue { get; } so the .NET side could distinguish null/undefined from other values. That is a bit more involved since (1) it's extending an interface which is breaking unless we add a default behavior, and it's unclear what the default behavior would be, and (2) of course we have to send more info across the wire. It would have the benefit that we wouldn't have to track the null/undefined value on the JS side, because the .NET side could be extended to no-op if you dispose when HasValue is false, and the outbound serializer on the .NET side could automatically supply null if HasValue is false (assuming we're OK with losing the distinction between null and undefined). Altogether I'm not sure all of this "going further" design is worth it, given what a niche case it is, and how it introduces nonobvious design pivots.

SteveSandersonMS commented 9 months ago

Related issue: https://github.com/dotnet/aspnetcore/issues/40272. We fixed this in https://github.com/dotnet/aspnetcore/pull/41916, however the fix was to give a better error rather than to make it work.

ghost commented 9 months ago

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

yueyinqiu commented 8 months ago

Also found this one year before: https://stackoverflow.com/questions/74264029/

Are there any alternative solutions now for my case, without an unnecessary performance overhead?