Skip to content

API proposal for new JS interop infrastructure #62455

Open
@oroztocil

Description

@oroztocil

The API change proposal in the JS interop area is split into two issues. This issue deals with "infrastructural" types and methods used internally by Blazor, or by users with custom JSRuntime implementations. The "user-facing" methods are described in #62454.

Background and Motivation

Application developers can perform JS interop calls using methods from the IJSRuntime and IJSObjectReference interfaces (or their synchronous InProcess variants). These calls are internally realized by BeginInvokeJS (or InvokeJS) method which has different implementation based on the communication channel (e.g. SignalR channel for RemoteJSRuntime).

Previously, all the data required to specify the interop call was passed in individual method arguments. Any modification or addition of a parameter would require a (potentially breaking) public API change. We propose adding new BeginInvokeJS and InvokeJS overloads that instead take a JSInvocationInfo instance. This structure would encapsulate all interop call parameters and would simplify further API changes.

Furthermore, we propose adding JSCallType enum that will be passed as one of the JSInvocationInfo parameters in order to disambiguate between different JS interop operations supported by the new JS interop methods (see #62454).

Proposed API

namespace Microsoft.JSInterop.Infrastructure
{
    public readonly struct JSInvocationInfo
    {
        public JSInvocationInfo();

        public required long AsyncHandle { get; init; }
        public required long TargetInstanceId { get; init; }
        public required string Identifier { get; init; }
        public required JSCallType CallType { get; init; }
        public required JSCallResultType ResultType { get; init; }
        public required string ArgsJson { get; init; }
    }

public enum JSCallType : int
{
    /// <summary>
    /// Represents a regular function invocation.
    /// </summary>
    FunctionCall = 1,

    /// <summary>
    /// Represents a constructor function invocation with the <c>new</c> operator.
    /// </summary>
    NewCall = 2,

    /// <summary>
    /// Represents reading a property value.
    /// </summary>
    GetValue = 3,

    /// <summary>
    /// Represents updating or defining a property value.
    /// </summary>
    SetValue = 4,
}

}
namespace Microsoft.JSInterop
{
    public abstract class JSRuntime
    {
        protected virtual void BeginInvokeJS(in JSInvocationInfo invocationInfo);
    }

    public abstract class JSInProcessRuntime
    {
        protected virtual string? InvokeJS(in JSInvocationInfo invocationInfo);
    }
}

namespace Microsoft.JSInterop.WebAssembly
{
    public class WebAssemblyJSRuntime
    {
        protected override void BeginInvokeJS(in JSInvocationInfo invocationInfo);
        protected override string InvokeJS(in JSInvocationInfo invocationInfo);
    }
}

namespace Microsoft.AspNetCore.Components.Web.Internal
{
    public interface IInternalWebJSInProcessRuntime
    {
        string InvokeJS(in JSInvocationInfo invocationInfo);
    }
}

Alternative Designs

JSInvocationInfo could be removed and the JSCallType value could be simply added as an another parameter in the existing BeginInvokeJS/InvokeJS overloads.

Risks

The API does not introduce a breaking change. The IInternalWebJSInProcessRuntime.InvokeJS method has a default implementation.

Adding the JSInvocationInfo DTO might introduce a minor performance cost. We try to minimize the cost by make it a readonly struct passed with the in modifier.

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-ready-for-reviewAPI is ready for formal API review - https://github.com/dotnet/apireviewsarea-blazorIncludes: Blazor, Razor Components

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions