Skip to content

Commit 8a2f29b

Browse files
JSObjectReference (#25028)
1 parent 0050ece commit 8a2f29b

28 files changed

+919
-90
lines changed

AspNetCore.sln

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1507,6 +1507,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Diagno
15071507
EndProject
15081508
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Diagnostics.HealthChecks.Tests", "src\HealthChecks\HealthChecks\test\Microsoft.Extensions.Diagnostics.HealthChecks.Tests.csproj", "{7509AA1E-3093-4BEE-984F-E11579E98A11}"
15091509
EndProject
1510+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.JSInterop.Tests", "src\JSInterop\Microsoft.JSInterop\test\Microsoft.JSInterop.Tests.csproj", "{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}"
1511+
EndProject
15101512
Global
15111513
GlobalSection(SolutionConfigurationPlatforms) = preSolution
15121514
Debug|Any CPU = Debug|Any CPU
@@ -7179,6 +7181,18 @@ Global
71797181
{7509AA1E-3093-4BEE-984F-E11579E98A11}.Release|x64.Build.0 = Release|Any CPU
71807182
{7509AA1E-3093-4BEE-984F-E11579E98A11}.Release|x86.ActiveCfg = Release|Any CPU
71817183
{7509AA1E-3093-4BEE-984F-E11579E98A11}.Release|x86.Build.0 = Release|Any CPU
7184+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
7185+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Debug|Any CPU.Build.0 = Debug|Any CPU
7186+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Debug|x64.ActiveCfg = Debug|Any CPU
7187+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Debug|x64.Build.0 = Debug|Any CPU
7188+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Debug|x86.ActiveCfg = Debug|Any CPU
7189+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Debug|x86.Build.0 = Debug|Any CPU
7190+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Release|Any CPU.ActiveCfg = Release|Any CPU
7191+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Release|Any CPU.Build.0 = Release|Any CPU
7192+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Release|x64.ActiveCfg = Release|Any CPU
7193+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Release|x64.Build.0 = Release|Any CPU
7194+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Release|x86.ActiveCfg = Release|Any CPU
7195+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Release|x86.Build.0 = Release|Any CPU
71827196
EndGlobalSection
71837197
GlobalSection(SolutionProperties) = preSolution
71847198
HideSolutionNode = FALSE
@@ -7934,6 +7948,7 @@ Global
79347948
{B06040BC-DA28-4923-8CAC-20EB517D471B} = {22D7D74B-565D-4047-97B4-F149B1A13350}
79357949
{55CACC1F-FE96-47C8-8073-91F4CAA55C75} = {2A91479A-4ABE-4BB7-9A5E-CA3B9CCFC69E}
79367950
{7509AA1E-3093-4BEE-984F-E11579E98A11} = {7CB09412-C9B0-47E8-A8C3-311AA4CFDE04}
7951+
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E} = {16898702-3E33-41C1-B8D8-4CE3F1D46BD9}
79377952
EndGlobalSection
79387953
GlobalSection(ExtensibilityGlobals) = postSolution
79397954
SolutionGuid = {3E8720B3-DBDD-498C-B383-2CC32A054E8F}

src/Components/Server/src/Circuits/RemoteJSRuntime.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ private void EndInvokeDotNetCore(string callId, bool success, object resultOrErr
7171
JsonSerializer.Serialize(new[] { callId, success, resultOrError }, JsonSerializerOptions));
7272
}
7373

74-
protected override void BeginInvokeJS(long asyncHandle, string identifier, string argsJson)
74+
protected override void BeginInvokeJS(long asyncHandle, string identifier, string argsJson, JSCallResultType resultType, long targetInstanceId)
7575
{
7676
if (_clientProxy is null)
7777
{
@@ -83,7 +83,7 @@ protected override void BeginInvokeJS(long asyncHandle, string identifier, strin
8383

8484
Log.BeginInvokeJS(_logger, asyncHandle, identifier);
8585

86-
_clientProxy.SendAsync("JS.BeginInvokeJS", asyncHandle, identifier, argsJson);
86+
_clientProxy.SendAsync("JS.BeginInvokeJS", asyncHandle, identifier, argsJson, (int)resultType, targetInstanceId);
8787
}
8888

8989
public static class Log

src/Components/Web.JS/dist/Release/blazor.server.js

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Components/Web.JS/dist/Release/blazor.webassembly.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Components/Web.JS/src/Boot.Server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ async function initializeConnection(options: CircuitStartOptions, logger: Logger
9797

9898
connection.on('JS.AttachComponent', (componentId, selector) => attachRootComponentToLogicalElement(0, circuit.resolveElement(selector), componentId));
9999
connection.on('JS.BeginInvokeJS', DotNet.jsCallDispatcher.beginInvokeJSFromDotNet);
100-
connection.on('JS.EndInvokeDotNet', (args: string) => DotNet.jsCallDispatcher.endInvokeDotNetFromJS(...(JSON.parse(args) as [string, boolean, unknown])));
100+
connection.on('JS.EndInvokeDotNet', (args: string) => DotNet.jsCallDispatcher.endInvokeDotNetFromJS(...(DotNet.parseJsonWithRevivers(args) as [string, boolean, unknown])));
101101

102102
const renderQueue = RenderQueue.getOrCreate(logger);
103103
connection.on('JS.RenderBatch', (batchId: number, batchData: Uint8Array) => {

src/Components/Web.JS/src/Boot.WebAssembly.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ async function boot(options?: Partial<WebAssemblyStartOptions>): Promise<void> {
3232
}
3333
});
3434

35+
// Configure JS interop
36+
window['Blazor']._internal.invokeJSFromDotNet = invokeJSFromDotNet;
37+
3538
// Configure environment for execution under Mono WebAssembly with shared-memory rendering
3639
const platform = Environment.setPlatform(monoPlatform);
3740
window['Blazor'].platform = platform;
@@ -84,6 +87,28 @@ async function boot(options?: Partial<WebAssemblyStartOptions>): Promise<void> {
8487
platform.callEntryPoint(resourceLoader.bootConfig.entryAssembly);
8588
}
8689

90+
function invokeJSFromDotNet(callInfo: Pointer, arg0: any, arg1: any, arg2: any): any {
91+
const functionIdentifier = monoPlatform.readStringField(callInfo, 0)!;
92+
const resultType = monoPlatform.readInt32Field(callInfo, 4);
93+
const marshalledCallArgsJson = monoPlatform.readStringField(callInfo, 8);
94+
const targetInstanceId = monoPlatform.readUint64Field(callInfo, 20);
95+
96+
if (marshalledCallArgsJson !== null) {
97+
const marshalledCallAsyncHandle = monoPlatform.readUint64Field(callInfo, 12);
98+
99+
if (marshalledCallAsyncHandle !== 0) {
100+
DotNet.jsCallDispatcher.beginInvokeJSFromDotNet(marshalledCallAsyncHandle, functionIdentifier, marshalledCallArgsJson, resultType, targetInstanceId);
101+
return 0;
102+
} else {
103+
const resultJson = DotNet.jsCallDispatcher.invokeJSFromDotNet(functionIdentifier, marshalledCallArgsJson, resultType, targetInstanceId)!;
104+
return resultJson === null ? 0 : BINDING.js_string_to_mono_string(resultJson);
105+
}
106+
} else {
107+
const func = DotNet.jsCallDispatcher.findJSFunction(functionIdentifier, targetInstanceId);
108+
return func.call(null, arg0, arg1, arg2);
109+
}
110+
}
111+
87112
window['Blazor'].start = boot;
88113
if (shouldAutoStart()) {
89114
boot().catch(error => {

src/Components/WebAssembly/JSInterop/src/InternalCalls.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,7 @@ internal static class InternalCalls
1616
// in driver.c in the Mono distribution
1717
/// See: https://github.com/mono/mono/blob/90574987940959fe386008a850982ea18236a533/sdks/wasm/src/driver.c#L318-L319
1818

19-
// We're passing asyncHandle by ref not because we want it to be writable, but so it gets
20-
// passed as a pointer (4 bytes). We can pass 4-byte values, but not 8-byte ones.
2119
[MethodImpl(MethodImplOptions.InternalCall)]
22-
public static extern string InvokeJSMarshalled(out string exception, ref long asyncHandle, string functionIdentifier, string argsJson);
23-
24-
[MethodImpl(MethodImplOptions.InternalCall)]
25-
public static extern TRes InvokeJSUnmarshalled<T0, T1, T2, TRes>(out string exception, string functionIdentifier, [AllowNull] T0 arg0, [AllowNull] T1 arg1, [AllowNull] T2 arg2);
20+
public static extern TRes InvokeJS<T0, T1, T2, TRes>(out string exception, ref JSCallInfo callInfo, [AllowNull] T0 arg0, [AllowNull] T1 arg1, [AllowNull] T2 arg2);
2621
}
2722
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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+
using System.Runtime.InteropServices;
5+
using Microsoft.JSInterop;
6+
7+
namespace WebAssembly.JSInterop
8+
{
9+
[StructLayout(LayoutKind.Explicit, Pack = 4)]
10+
internal struct JSCallInfo
11+
{
12+
[FieldOffset(0)]
13+
public string FunctionIdentifier;
14+
15+
[FieldOffset(4)]
16+
public JSCallResultType ResultType;
17+
18+
[FieldOffset(8)]
19+
public string MarshalledCallArgsJson;
20+
21+
[FieldOffset(12)]
22+
public long MarshalledCallAsyncHandle;
23+
24+
[FieldOffset(20)]
25+
public long TargetInstanceId;
26+
}
27+
}

src/Components/WebAssembly/JSInterop/src/WebAssemblyJSRuntime.cs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,37 @@ namespace Microsoft.JSInterop.WebAssembly
1414
public abstract class WebAssemblyJSRuntime : JSInProcessRuntime, IJSUnmarshalledRuntime
1515
{
1616
/// <inheritdoc />
17-
protected override string InvokeJS(string identifier, string argsJson)
17+
protected override string InvokeJS(string identifier, string argsJson, JSCallResultType resultType, long targetInstanceId)
1818
{
19-
var noAsyncHandle = default(long);
20-
var result = InternalCalls.InvokeJSMarshalled(out var exception, ref noAsyncHandle, identifier, argsJson);
19+
var callInfo = new JSCallInfo
20+
{
21+
FunctionIdentifier = identifier,
22+
TargetInstanceId = targetInstanceId,
23+
ResultType = resultType,
24+
MarshalledCallArgsJson = argsJson ?? "[]",
25+
MarshalledCallAsyncHandle = default
26+
};
27+
28+
var result = InternalCalls.InvokeJS<object, object, object, string>(out var exception, ref callInfo, null, null, null);
29+
2130
return exception != null
2231
? throw new JSException(exception)
2332
: result;
2433
}
2534

2635
/// <inheritdoc />
27-
protected override void BeginInvokeJS(long asyncHandle, string identifier, string argsJson)
36+
protected override void BeginInvokeJS(long asyncHandle, string identifier, string argsJson, JSCallResultType resultType, long targetInstanceId)
2837
{
29-
InternalCalls.InvokeJSMarshalled(out _, ref asyncHandle, identifier, argsJson);
38+
var callInfo = new JSCallInfo
39+
{
40+
FunctionIdentifier = identifier,
41+
TargetInstanceId = targetInstanceId,
42+
ResultType = resultType,
43+
MarshalledCallArgsJson = argsJson ?? "[]",
44+
MarshalledCallAsyncHandle = asyncHandle
45+
};
46+
47+
InternalCalls.InvokeJS<object, object, object, string>(out _, ref callInfo, null, null, null);
3048
}
3149

3250
protected override void EndInvokeDotNet(DotNetInvocationInfo callInfo, in DotNetInvocationResult dispatchResult)
@@ -39,7 +57,7 @@ protected override void EndInvokeDotNet(DotNetInvocationInfo callInfo, in DotNet
3957
// We pass 0 as the async handle because we don't want the JS-side code to
4058
// send back any notification (we're just providing a result for an existing async call)
4159
var args = JsonSerializer.Serialize(new[] { callInfo.CallId, dispatchResult.Success, resultOrError }, JsonSerializerOptions);
42-
BeginInvokeJS(0, "DotNet.jsCallDispatcher.endInvokeDotNetFromJS", args);
60+
BeginInvokeJS(0, "DotNet.jsCallDispatcher.endInvokeDotNetFromJS", args, JSCallResultType.Default, 0);
4361
}
4462

4563
/// <inheritdoc />
@@ -57,7 +75,14 @@ TResult IJSUnmarshalledRuntime.InvokeUnmarshalled<T0, T1, TResult>(string identi
5775
/// <inheritdoc />
5876
TResult IJSUnmarshalledRuntime.InvokeUnmarshalled<T0, T1, T2, TResult>(string identifier, T0 arg0, T1 arg1, T2 arg2)
5977
{
60-
var result = InternalCalls.InvokeJSUnmarshalled<T0, T1, T2, TResult>(out var exception, identifier, arg0, arg1, arg2);
78+
var callInfo = new JSCallInfo
79+
{
80+
FunctionIdentifier = identifier,
81+
ResultType = ResultTypeFromGeneric<TResult>()
82+
};
83+
84+
var result = InternalCalls.InvokeJS<T0, T1, T2, TResult>(out var exception, ref callInfo, arg0, arg1, arg2);
85+
6186
return exception != null
6287
? throw new JSException(exception)
6388
: result;

src/Components/test/E2ETest/Tests/InteropTest.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,13 @@ public void CanInvokeDotNetMethods()
5555
["result7Async"] = @"[{""id"":6,""isValid"":true,""data"":{""source"":""Some random text with at least 6 characters"",""start"":6,""length"":6}},6,123,24,48,6.25]",
5656
["result8Async"] = @"[{""id"":7,""isValid"":false,""data"":{""source"":""Some random text with at least 7 characters"",""start"":7,""length"":7}},7,123,28,56,7.25,[0.5,1.5,2.5,3.5,4.5,5.5,6.5]]",
5757
["result9Async"] = @"[{""id"":8,""isValid"":true,""data"":{""source"":""Some random text with at least 8 characters"",""start"":8,""length"":8}},8,123,32,64,8.25,[0.5,1.5,2.5,3.5,4.5,5.5,6.5,7.5],{""source"":""Some random text with at least 7 characters"",""start"":9,""length"":9}]",
58+
["roundTripJSObjectReferenceAsync"] = @"""successful""",
59+
["invokeDisposedJSObjectReferenceExceptionAsync"] = @"""JS object instance with ID",
5860
["AsyncThrowSyncException"] = @"""System.InvalidOperationException: Threw a sync exception!",
5961
["AsyncThrowAsyncException"] = @"""System.InvalidOperationException: Threw an async exception!",
6062
["SyncExceptionFromAsyncMethod"] = "Function threw a sync exception!",
6163
["AsyncExceptionFromAsyncMethod"] = "Function threw an async exception!",
64+
["JSObjectReferenceInvokeNonFunctionException"] = "The value 'nonFunction' is not a function.",
6265
["resultReturnDotNetObjectByRefAsync"] = "1001",
6366
["instanceMethodThisTypeNameAsync"] = @"""JavaScriptInterop""",
6467
["instanceMethodStringValueUpperAsync"] = @"""MY STRING""",
@@ -69,6 +72,10 @@ public void CanInvokeDotNetMethods()
6972
["testDtoAsync"] = "Same",
7073
["returnPrimitiveAsync"] = "123",
7174
["returnArrayAsync"] = "first,second",
75+
["jsObjectReference.identity"] = "Invoked from JSObjectReference",
76+
["jsObjectReference.nested.add"] = "5",
77+
["addViaJSObjectReference"] = "5",
78+
["jsObjectReferenceModule"] = "Returned from module!",
7279
["syncGenericInstanceMethod"] = @"""Initial value""",
7380
["asyncGenericInstanceMethod"] = @"""Updated value 1""",
7481
};
@@ -93,13 +100,16 @@ public void CanInvokeDotNetMethods()
93100
["result7"] = @"[{""id"":6,""isValid"":true,""data"":{""source"":""Some random text with at least 6 characters"",""start"":6,""length"":6}},6,123,24,48,6.25]",
94101
["result8"] = @"[{""id"":7,""isValid"":false,""data"":{""source"":""Some random text with at least 7 characters"",""start"":7,""length"":7}},7,123,28,56,7.25,[0.5,1.5,2.5,3.5,4.5,5.5,6.5]]",
95102
["result9"] = @"[{""id"":8,""isValid"":true,""data"":{""source"":""Some random text with at least 8 characters"",""start"":8,""length"":8}},8,123,32,64,8.25,[0.5,1.5,2.5,3.5,4.5,5.5,6.5,7.5],{""source"":""Some random text with at least 7 characters"",""start"":9,""length"":9}]",
103+
["roundTripJSObjectReference"] = @"""successful""",
104+
["invokeDisposedJSObjectReferenceException"] = @"""JS object instance with ID",
96105
["ThrowException"] = @"""System.InvalidOperationException: Threw an exception!",
97106
["ExceptionFromSyncMethod"] = "Function threw an exception!",
98107
["resultReturnDotNetObjectByRefSync"] = "1000",
99108
["instanceMethodThisTypeName"] = @"""JavaScriptInterop""",
100109
["instanceMethodStringValueUpper"] = @"""MY STRING""",
101110
["instanceMethodIncomingByRef"] = "123",
102111
["instanceMethodOutgoingByRef"] = "1234",
112+
["jsInProcessObjectReference.identity"] = "Invoked from JSInProcessObjectReference",
103113
["stringValueUpperSync"] = "MY STRING",
104114
["testDtoNonSerializedValueSync"] = "99999",
105115
["testDtoSync"] = "Same",

src/Components/test/testassets/BasicTestApp/InteropComponent.razor

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
<p id="@nameof(SyncExceptionFromAsyncMethod)">@SyncExceptionFromAsyncMethod?.Message</p>
4747
<h2>@nameof(AsyncExceptionFromAsyncMethod)</h2>
4848
<p id="@nameof(AsyncExceptionFromAsyncMethod)">@AsyncExceptionFromAsyncMethod?.Message</p>
49+
<h2>@nameof(JSObjectReferenceInvokeNonFunctionException)</h2>
50+
<p id="@nameof(JSObjectReferenceInvokeNonFunctionException)">@JSObjectReferenceInvokeNonFunctionException?.Message</p>
4951
</div>
5052
@if (DoneWithInterop)
5153
{
@@ -59,6 +61,7 @@
5961
public JSException ExceptionFromSyncMethod { get; set; }
6062
public JSException SyncExceptionFromAsyncMethod { get; set; }
6163
public JSException AsyncExceptionFromAsyncMethod { get; set; }
64+
public JSException JSObjectReferenceInvokeNonFunctionException { get; set; }
6265

6366
public IDictionary<string, object> ReceiveDotNetObjectByRefResult { get; set; } = new Dictionary<string, object>();
6467
public IDictionary<string, object> ReceiveDotNetObjectByRefAsyncResult { get; set; } = new Dictionary<string, object>();
@@ -134,6 +137,28 @@
134137
ReturnValues["returnArray"] = string.Join(",", ((IJSInProcessRuntime)JSRuntime).Invoke<Segment[]>("returnArray").Select(x => x.Source).ToArray());
135138
}
136139

140+
var jsObjectReference = await JSRuntime.InvokeAsync<JSObjectReference>("returnJSObjectReference");
141+
ReturnValues["jsObjectReference.identity"] = await jsObjectReference.InvokeAsync<string>("identity", "Invoked from JSObjectReference");
142+
ReturnValues["jsObjectReference.nested.add"] = (await jsObjectReference.InvokeAsync<int>("nested.add", 2, 3)).ToString();
143+
ReturnValues["addViaJSObjectReference"] = (await JSRuntime.InvokeAsync<int>("addViaJSObjectReference", jsObjectReference, 2, 3)).ToString();
144+
145+
try
146+
{
147+
await jsObjectReference.InvokeAsync<object>("nonFunction");
148+
}
149+
catch (JSException e)
150+
{
151+
JSObjectReferenceInvokeNonFunctionException = e;
152+
}
153+
154+
var module = await JSRuntime.InvokeAsync<JSObjectReference>("import", "./js/testmodule.js");
155+
ReturnValues["jsObjectReferenceModule"] = await module.InvokeAsync<string>("identity", "Returned from module!");
156+
157+
if (shouldSupportSyncInterop)
158+
{
159+
InvokeInProcessJSInterop();
160+
}
161+
137162
Invocations = invocations;
138163
DoneWithInterop = true;
139164
}
@@ -163,6 +188,14 @@
163188
ReceiveDotNetObjectByRefResult["testDto"] = result.TestDto.Value == passDotNetObjectByRef ? "Same" : "Different";
164189
}
165190

191+
public void InvokeInProcessJSInterop()
192+
{
193+
var inProcRuntime = ((IJSInProcessRuntime)JSRuntime);
194+
195+
var jsInProcObjectReference = inProcRuntime.Invoke<JSInProcessObjectReference>("returnJSObjectReference");
196+
ReturnValues["jsInProcessObjectReference.identity"] = jsInProcObjectReference.Invoke<string>("identity", "Invoked from JSInProcessObjectReference");
197+
}
198+
166199
public class PassDotNetObjectByRefArgs
167200
{
168201
public string StringValue { get; set; }

src/Components/test/testassets/BasicTestApp/InteropTest/JavaScriptInterop.cs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,47 @@ public static int ExtractNonSerializedValue(DotNetObjectReference<TestDTO> objec
414414
return objectByRef.Value.GetNonSerializedValue();
415415
}
416416

417+
[JSInvokable]
418+
public static JSObjectReference RoundTripJSObjectReference(JSObjectReference jsObjectReference)
419+
{
420+
return jsObjectReference;
421+
}
422+
423+
[JSInvokable]
424+
public static async Task<JSObjectReference> RoundTripJSObjectReferenceAsync(JSObjectReference jSObjectReference)
425+
{
426+
await Task.Yield();
427+
return jSObjectReference;
428+
}
429+
430+
[JSInvokable]
431+
public static string InvokeDisposedJSObjectReferenceException(JSInProcessObjectReference jsObjectReference)
432+
{
433+
try
434+
{
435+
jsObjectReference.Invoke<object>("noop");
436+
return "No exception thrown";
437+
}
438+
catch (JSException e)
439+
{
440+
return e.Message;
441+
}
442+
}
443+
444+
[JSInvokable]
445+
public static async Task<string> InvokeDisposedJSObjectReferenceExceptionAsync(JSObjectReference jsObjectReference)
446+
{
447+
try
448+
{
449+
await jsObjectReference.InvokeVoidAsync("noop");
450+
return "No exception thrown";
451+
}
452+
catch (JSException e)
453+
{
454+
return e.Message;
455+
}
456+
}
457+
417458
[JSInvokable]
418459
public InstanceMethodOutput InstanceMethod(InstanceMethodInput input)
419460
{

0 commit comments

Comments
 (0)