Skip to content

Commit d46d569

Browse files
authored
Simplify JSRuntime method signature (dotnet/extensions#2188)
\n\nCommit migrated from dotnet/extensions@9c392a9
1 parent ef83e33 commit d46d569

12 files changed

+249
-122
lines changed

src/JSInterop/Microsoft.JSInterop/ref/Microsoft.JSInterop.netcoreapp3.0.cs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ protected JSRuntime() { }
5050
protected System.TimeSpan? DefaultAsyncTimeout { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
5151
protected internal System.Text.Json.JsonSerializerOptions JsonSerializerOptions { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
5252
protected abstract void BeginInvokeJS(long taskId, string identifier, string argsJson);
53-
protected internal abstract void EndInvokeDotNet(string callId, bool success, object resultOrError, string assemblyName, string methodIdentifier, long dotNetObjectId);
53+
protected internal abstract void EndInvokeDotNet(Microsoft.JSInterop.Infrastructure.DotNetInvocationInfo invocationInfo, in Microsoft.JSInterop.Infrastructure.DotNetInvocationResult invocationResult);
5454
public System.Threading.Tasks.ValueTask<TValue> InvokeAsync<TValue>(string identifier, object[] args) { throw null; }
5555
public System.Threading.Tasks.ValueTask<TValue> InvokeAsync<TValue>(string identifier, System.Threading.CancellationToken cancellationToken, object[] args) { throw null; }
5656
}
@@ -72,8 +72,31 @@ namespace Microsoft.JSInterop.Infrastructure
7272
{
7373
public static partial class DotNetDispatcher
7474
{
75-
public static void BeginInvokeDotNet(Microsoft.JSInterop.JSRuntime jsRuntime, string callId, string assemblyName, string methodIdentifier, long dotNetObjectId, string argsJson) { }
75+
public static void BeginInvokeDotNet(Microsoft.JSInterop.JSRuntime jsRuntime, Microsoft.JSInterop.Infrastructure.DotNetInvocationInfo invocationInfo, string argsJson) { }
7676
public static void EndInvokeJS(Microsoft.JSInterop.JSRuntime jsRuntime, string arguments) { }
77-
public static string Invoke(Microsoft.JSInterop.JSRuntime jsRuntime, string assemblyName, string methodIdentifier, long dotNetObjectId, string argsJson) { throw null; }
77+
public static string Invoke(Microsoft.JSInterop.JSRuntime jsRuntime, in Microsoft.JSInterop.Infrastructure.DotNetInvocationInfo invocationInfo, string argsJson) { throw null; }
78+
}
79+
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
80+
public readonly partial struct DotNetInvocationInfo
81+
{
82+
private readonly object _dummy;
83+
private readonly int _dummyPrimitive;
84+
public DotNetInvocationInfo(string assemblyName, string methodIdentifier, long dotNetObjectId, string callId) { throw null; }
85+
public string AssemblyName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
86+
public string CallId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
87+
public long DotNetObjectId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
88+
public string MethodIdentifier { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
89+
}
90+
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
91+
public readonly partial struct DotNetInvocationResult
92+
{
93+
private readonly object _dummy;
94+
private readonly int _dummyPrimitive;
95+
public DotNetInvocationResult(System.Exception exception, string errorKind) { throw null; }
96+
public DotNetInvocationResult(object result) { throw null; }
97+
public string ErrorKind { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
98+
public System.Exception Exception { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
99+
public object Result { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
100+
public bool Success { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
78101
}
79102
}

src/JSInterop/Microsoft.JSInterop/ref/Microsoft.JSInterop.netstandard2.0.cs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ protected JSRuntime() { }
5050
protected System.TimeSpan? DefaultAsyncTimeout { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
5151
protected internal System.Text.Json.JsonSerializerOptions JsonSerializerOptions { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
5252
protected abstract void BeginInvokeJS(long taskId, string identifier, string argsJson);
53-
protected internal abstract void EndInvokeDotNet(string callId, bool success, object resultOrError, string assemblyName, string methodIdentifier, long dotNetObjectId);
53+
protected internal abstract void EndInvokeDotNet(Microsoft.JSInterop.Infrastructure.DotNetInvocationInfo invocationInfo, in Microsoft.JSInterop.Infrastructure.DotNetInvocationResult invocationResult);
5454
public System.Threading.Tasks.ValueTask<TValue> InvokeAsync<TValue>(string identifier, object[] args) { throw null; }
5555
public System.Threading.Tasks.ValueTask<TValue> InvokeAsync<TValue>(string identifier, System.Threading.CancellationToken cancellationToken, object[] args) { throw null; }
5656
}
@@ -72,8 +72,31 @@ namespace Microsoft.JSInterop.Infrastructure
7272
{
7373
public static partial class DotNetDispatcher
7474
{
75-
public static void BeginInvokeDotNet(Microsoft.JSInterop.JSRuntime jsRuntime, string callId, string assemblyName, string methodIdentifier, long dotNetObjectId, string argsJson) { }
75+
public static void BeginInvokeDotNet(Microsoft.JSInterop.JSRuntime jsRuntime, Microsoft.JSInterop.Infrastructure.DotNetInvocationInfo invocationInfo, string argsJson) { }
7676
public static void EndInvokeJS(Microsoft.JSInterop.JSRuntime jsRuntime, string arguments) { }
77-
public static string Invoke(Microsoft.JSInterop.JSRuntime jsRuntime, string assemblyName, string methodIdentifier, long dotNetObjectId, string argsJson) { throw null; }
77+
public static string Invoke(Microsoft.JSInterop.JSRuntime jsRuntime, in Microsoft.JSInterop.Infrastructure.DotNetInvocationInfo invocationInfo, string argsJson) { throw null; }
78+
}
79+
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
80+
public readonly partial struct DotNetInvocationInfo
81+
{
82+
private readonly object _dummy;
83+
private readonly int _dummyPrimitive;
84+
public DotNetInvocationInfo(string assemblyName, string methodIdentifier, long dotNetObjectId, string callId) { throw null; }
85+
public string AssemblyName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
86+
public string CallId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
87+
public long DotNetObjectId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
88+
public string MethodIdentifier { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
89+
}
90+
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
91+
public readonly partial struct DotNetInvocationResult
92+
{
93+
private readonly object _dummy;
94+
private readonly int _dummyPrimitive;
95+
public DotNetInvocationResult(System.Exception exception, string errorKind) { throw null; }
96+
public DotNetInvocationResult(object result) { throw null; }
97+
public string ErrorKind { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
98+
public System.Exception Exception { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
99+
public object Result { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
100+
public bool Success { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
78101
}
79102
}

src/JSInterop/Microsoft.JSInterop/src/Infrastructure/DotNetDispatcher.cs

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,25 +28,23 @@ public static class DotNetDispatcher
2828
/// Receives a call from JS to .NET, locating and invoking the specified method.
2929
/// </summary>
3030
/// <param name="jsRuntime">The <see cref="JSRuntime"/>.</param>
31-
/// <param name="assemblyName">The assembly containing the method to be invoked.</param>
32-
/// <param name="methodIdentifier">The identifier of the method to be invoked. The method must be annotated with a <see cref="JSInvokableAttribute"/> matching this identifier string.</param>
33-
/// <param name="dotNetObjectId">For instance method calls, identifies the target object.</param>
31+
/// <param name="invocationInfo">The <see cref="DotNetInvocationInfo"/>.</param>
3432
/// <param name="argsJson">A JSON representation of the parameters.</param>
3533
/// <returns>A JSON representation of the return value, or null.</returns>
36-
public static string Invoke(JSRuntime jsRuntime, string assemblyName, string methodIdentifier, long dotNetObjectId, string argsJson)
34+
public static string Invoke(JSRuntime jsRuntime, in DotNetInvocationInfo invocationInfo, string argsJson)
3735
{
3836
// This method doesn't need [JSInvokable] because the platform is responsible for having
3937
// some way to dispatch calls here. The logic inside here is the thing that checks whether
4038
// the targeted method has [JSInvokable]. It is not itself subject to that restriction,
4139
// because there would be nobody to police that. This method *is* the police.
4240

4341
IDotNetObjectReference targetInstance = default;
44-
if (dotNetObjectId != default)
42+
if (invocationInfo.DotNetObjectId != default)
4543
{
46-
targetInstance = jsRuntime.GetObjectReference(dotNetObjectId);
44+
targetInstance = jsRuntime.GetObjectReference(invocationInfo.DotNetObjectId);
4745
}
4846

49-
var syncResult = InvokeSynchronously(jsRuntime, assemblyName, methodIdentifier, targetInstance, argsJson);
47+
var syncResult = InvokeSynchronously(jsRuntime, invocationInfo, targetInstance, argsJson);
5048
if (syncResult == null)
5149
{
5250
return null;
@@ -59,13 +57,10 @@ public static string Invoke(JSRuntime jsRuntime, string assemblyName, string met
5957
/// Receives a call from JS to .NET, locating and invoking the specified method asynchronously.
6058
/// </summary>
6159
/// <param name="jsRuntime">The <see cref="JSRuntime"/>.</param>
62-
/// <param name="callId">A value identifying the asynchronous call that should be passed back with the result, or null if no result notification is required.</param>
63-
/// <param name="assemblyName">The assembly containing the method to be invoked.</param>
64-
/// <param name="methodIdentifier">The identifier of the method to be invoked. The method must be annotated with a <see cref="JSInvokableAttribute"/> matching this identifier string.</param>
65-
/// <param name="dotNetObjectId">For instance method calls, identifies the target object.</param>
60+
/// <param name="invocationInfo">The <see cref="DotNetInvocationInfo"/>.</param>
6661
/// <param name="argsJson">A JSON representation of the parameters.</param>
6762
/// <returns>A JSON representation of the return value, or null.</returns>
68-
public static void BeginInvokeDotNet(JSRuntime jsRuntime, string callId, string assemblyName, string methodIdentifier, long dotNetObjectId, string argsJson)
63+
public static void BeginInvokeDotNet(JSRuntime jsRuntime, DotNetInvocationInfo invocationInfo, string argsJson)
6964
{
7065
// This method doesn't need [JSInvokable] because the platform is responsible for having
7166
// some way to dispatch calls here. The logic inside here is the thing that checks whether
@@ -75,18 +70,19 @@ public static void BeginInvokeDotNet(JSRuntime jsRuntime, string callId, string
7570
// Using ExceptionDispatchInfo here throughout because we want to always preserve
7671
// original stack traces.
7772

73+
var callId = invocationInfo.CallId;
74+
7875
object syncResult = null;
7976
ExceptionDispatchInfo syncException = null;
8077
IDotNetObjectReference targetInstance = null;
81-
8278
try
8379
{
84-
if (dotNetObjectId != default)
80+
if (invocationInfo.DotNetObjectId != default)
8581
{
86-
targetInstance = jsRuntime.GetObjectReference(dotNetObjectId);
82+
targetInstance = jsRuntime.GetObjectReference(invocationInfo.DotNetObjectId);
8783
}
8884

89-
syncResult = InvokeSynchronously(jsRuntime, assemblyName, methodIdentifier, targetInstance, argsJson);
85+
syncResult = InvokeSynchronously(jsRuntime, invocationInfo, targetInstance, argsJson);
9086
}
9187
catch (Exception ex)
9288
{
@@ -101,7 +97,7 @@ public static void BeginInvokeDotNet(JSRuntime jsRuntime, string callId, string
10197
else if (syncException != null)
10298
{
10399
// Threw synchronously, let's respond.
104-
jsRuntime.EndInvokeDotNet(callId, false, syncException, assemblyName, methodIdentifier, dotNetObjectId);
100+
jsRuntime.EndInvokeDotNet(invocationInfo, new DotNetInvocationResult(syncException.SourceException, "InvocationFailure"));
105101
}
106102
else if (syncResult is Task task)
107103
{
@@ -111,23 +107,27 @@ public static void BeginInvokeDotNet(JSRuntime jsRuntime, string callId, string
111107
{
112108
if (t.Exception != null)
113109
{
114-
var exception = t.Exception.GetBaseException();
115-
116-
jsRuntime.EndInvokeDotNet(callId, false, ExceptionDispatchInfo.Capture(exception), assemblyName, methodIdentifier, dotNetObjectId);
110+
var exceptionDispatchInfo = ExceptionDispatchInfo.Capture(t.Exception.GetBaseException());
111+
var dispatchResult = new DotNetInvocationResult(exceptionDispatchInfo.SourceException, "InvocationFailure");
112+
jsRuntime.EndInvokeDotNet(invocationInfo, dispatchResult);
117113
}
118114

119115
var result = TaskGenericsUtil.GetTaskResult(task);
120-
jsRuntime.EndInvokeDotNet(callId, true, result, assemblyName, methodIdentifier, dotNetObjectId);
116+
jsRuntime.EndInvokeDotNet(invocationInfo, new DotNetInvocationResult(result));
121117
}, TaskScheduler.Current);
122118
}
123119
else
124120
{
125-
jsRuntime.EndInvokeDotNet(callId, true, syncResult, assemblyName, methodIdentifier, dotNetObjectId);
121+
var dispatchResult = new DotNetInvocationResult(syncResult);
122+
jsRuntime.EndInvokeDotNet(invocationInfo, dispatchResult);
126123
}
127124
}
128125

129-
private static object InvokeSynchronously(JSRuntime jsRuntime, string assemblyName, string methodIdentifier, IDotNetObjectReference objectReference, string argsJson)
126+
private static object InvokeSynchronously(JSRuntime jsRuntime, in DotNetInvocationInfo callInfo, IDotNetObjectReference objectReference, string argsJson)
130127
{
128+
var assemblyName = callInfo.AssemblyName;
129+
var methodIdentifier = callInfo.MethodIdentifier;
130+
131131
AssemblyKey assemblyKey;
132132
if (objectReference is null)
133133
{
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
namespace Microsoft.JSInterop.Infrastructure
5+
{
6+
/// <summary>
7+
/// Information about a JSInterop call from JavaScript to .NET.
8+
/// </summary>
9+
public readonly struct DotNetInvocationInfo
10+
{
11+
/// <summary>
12+
/// Initializes a new instance of <see cref="DotNetInvocationInfo"/>.
13+
/// </summary>
14+
/// <param name="assemblyName">The name of the assembly containing the method.</param>
15+
/// <param name="methodIdentifier">The identifier of the method to be invoked.</param>
16+
/// <param name="dotNetObjectId">The object identifier for instance method calls.</param>
17+
/// <param name="callId">The call identifier.</param>
18+
public DotNetInvocationInfo(string assemblyName, string methodIdentifier, long dotNetObjectId, string callId)
19+
{
20+
CallId = callId;
21+
AssemblyName = assemblyName;
22+
MethodIdentifier = methodIdentifier;
23+
DotNetObjectId = dotNetObjectId;
24+
}
25+
26+
/// <summary>
27+
/// Gets the name of the assembly containing the method.
28+
/// Only one of <see cref="DotNetObjectId"/> or <see cref="AssemblyName"/> may be specified.
29+
/// </summary>
30+
public string AssemblyName { get; }
31+
32+
/// <summary>
33+
/// Gets the identifier of the method to be invoked. This is the value specified in the <see cref="JSInvokableAttribute"/>.
34+
/// </summary>
35+
public string MethodIdentifier { get; }
36+
37+
/// <summary>
38+
/// Gets the object identifier for instance method calls.
39+
/// Only one of <see cref="DotNetObjectId"/> or <see cref="AssemblyName"/> may be specified.
40+
/// </summary>
41+
public long DotNetObjectId { get; }
42+
43+
/// <summary>
44+
/// Gets the call identifier. This value is <see langword="null"/> when the client does not expect a value to be returned.
45+
/// </summary>
46+
public string CallId { get; }
47+
}
48+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using System;
2+
3+
namespace Microsoft.JSInterop.Infrastructure
4+
{
5+
/// <summary>
6+
/// Result of a .NET invocation that is returned to JavaScript.
7+
/// </summary>
8+
public readonly struct DotNetInvocationResult
9+
{
10+
/// <summary>
11+
/// Constructor for a failed invocation.
12+
/// </summary>
13+
/// <param name="exception">The <see cref="System.Exception"/> that caused the failure.</param>
14+
/// <param name="errorKind">The error kind.</param>
15+
public DotNetInvocationResult(Exception exception, string errorKind)
16+
{
17+
Result = default;
18+
Exception = exception ?? throw new ArgumentNullException(nameof(exception));
19+
ErrorKind = errorKind;
20+
Success = false;
21+
}
22+
23+
/// <summary>
24+
/// Constructor for a successful invocation.
25+
/// </summary>
26+
/// <param name="result">The result.</param>
27+
public DotNetInvocationResult(object result)
28+
{
29+
Result = result;
30+
Exception = default;
31+
ErrorKind = default;
32+
Success = true;
33+
}
34+
35+
/// <summary>
36+
/// Gets the <see cref="System.Exception"/> that caused the failure.
37+
/// </summary>
38+
public Exception Exception { get; }
39+
40+
/// <summary>
41+
/// Gets the error kind.
42+
/// </summary>
43+
public string ErrorKind { get; }
44+
45+
/// <summary>
46+
/// Gets the result of a successful invocation.
47+
/// </summary>
48+
public object Result { get; }
49+
50+
/// <summary>
51+
/// <see langword="true"/> if the invocation succeeded, otherwise <see langword="false"/>.
52+
/// </summary>
53+
public bool Success { get; }
54+
}
55+
}

0 commit comments

Comments
 (0)