Description
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.