IJSUnmarshalledObjectReference for unmarshalled JS interop calls on JavaScript objects. (#25548)
* Added IJSUnmarshalledObjectReference
* Working support for IJSUnmarshalledObjectReference
* CR feedback
* Removed IVT and made JSObjectReference public
* Updated JSON converter.
* Update JSObjectReferenceJsonConverterTest.cs
* Removed whitespace 😓
This commit is contained in:
parent
c61bdfdd25
commit
bbc7fd8192
File diff suppressed because one or more lines are too long
|
|
@ -130,7 +130,16 @@ function invokeJSFromDotNet(callInfo: Pointer, arg0: any, arg1: any, arg2: any):
|
|||
}
|
||||
} else {
|
||||
const func = DotNet.jsCallDispatcher.findJSFunction(functionIdentifier, targetInstanceId);
|
||||
return func.call(null, arg0, arg1, arg2);
|
||||
const result = func.call(null, arg0, arg1, arg2);
|
||||
|
||||
switch (resultType) {
|
||||
case DotNet.JSCallResultType.Default:
|
||||
return result;
|
||||
case DotNet.JSCallResultType.JSObjectReference:
|
||||
return DotNet.createJSObjectReference(result).__jsObjectId;
|
||||
default:
|
||||
throw new Error(`Invalid JS call result type '${resultType}'.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.JSInterop.Implementation;
|
||||
|
||||
namespace Microsoft.JSInterop.WebAssembly
|
||||
{
|
||||
internal class WebAssemblyJSObjectReference : JSInProcessObjectReference, IJSUnmarshalledObjectReference
|
||||
{
|
||||
private readonly WebAssemblyJSRuntime _jsRuntime;
|
||||
|
||||
public WebAssemblyJSObjectReference(WebAssemblyJSRuntime jsRuntime, long id) : base(jsRuntime, id)
|
||||
{
|
||||
_jsRuntime = jsRuntime;
|
||||
}
|
||||
|
||||
public TResult InvokeUnmarshalled<TResult>(string identifier)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
return _jsRuntime.InvokeUnmarshalled<object, object, object, TResult>(identifier, null, null, null, Id);
|
||||
}
|
||||
|
||||
public TResult InvokeUnmarshalled<T0, TResult>(string identifier, T0 arg0)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
return _jsRuntime.InvokeUnmarshalled<T0, object, object, TResult>(identifier, arg0, null, null, Id);
|
||||
}
|
||||
|
||||
public TResult InvokeUnmarshalled<T0, T1, TResult>(string identifier, T0 arg0, T1 arg1)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
return _jsRuntime.InvokeUnmarshalled<T0, T1, object, TResult>(identifier, arg0, arg1, null, Id);
|
||||
}
|
||||
|
||||
public TResult InvokeUnmarshalled<T0, T1, T2, TResult>(string identifier, T0 arg0, T1 arg1, T2 arg2)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
return _jsRuntime.InvokeUnmarshalled<T0, T1, T2, TResult>(identifier, arg0, arg1, arg2, Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using Microsoft.JSInterop.Infrastructure;
|
||||
using WebAssembly.JSInterop;
|
||||
|
|
@ -60,32 +61,50 @@ namespace Microsoft.JSInterop.WebAssembly
|
|||
BeginInvokeJS(0, "DotNet.jsCallDispatcher.endInvokeDotNetFromJS", args, JSCallResultType.Default, 0);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
TResult IJSUnmarshalledRuntime.InvokeUnmarshalled<TResult>(string identifier)
|
||||
=> ((IJSUnmarshalledRuntime)this).InvokeUnmarshalled<object, object, object, TResult>(identifier, null, null, null);
|
||||
|
||||
/// <inheritdoc />
|
||||
TResult IJSUnmarshalledRuntime.InvokeUnmarshalled<T0, TResult>(string identifier, T0 arg0)
|
||||
=> ((IJSUnmarshalledRuntime)this).InvokeUnmarshalled<T0, object, object, TResult>(identifier, arg0, null, null);
|
||||
|
||||
/// <inheritdoc />
|
||||
TResult IJSUnmarshalledRuntime.InvokeUnmarshalled<T0, T1, TResult>(string identifier, T0 arg0, T1 arg1)
|
||||
=> ((IJSUnmarshalledRuntime)this).InvokeUnmarshalled<T0, T1, object, TResult>(identifier, arg0, arg1, null);
|
||||
|
||||
/// <inheritdoc />
|
||||
TResult IJSUnmarshalledRuntime.InvokeUnmarshalled<T0, T1, T2, TResult>(string identifier, T0 arg0, T1 arg1, T2 arg2)
|
||||
internal TResult InvokeUnmarshalled<T0, T1, T2, TResult>(string identifier, T0 arg0, T1 arg1, T2 arg2, long targetInstanceId)
|
||||
{
|
||||
var resultType = JSCallResultTypeHelper.FromGeneric<TResult>();
|
||||
|
||||
var callInfo = new JSCallInfo
|
||||
{
|
||||
FunctionIdentifier = identifier,
|
||||
ResultType = JSCallResultTypeHelper.FromGeneric<TResult>()
|
||||
TargetInstanceId = targetInstanceId,
|
||||
ResultType = resultType,
|
||||
};
|
||||
|
||||
var result = InternalCalls.InvokeJS<T0, T1, T2, TResult>(out var exception, ref callInfo, arg0, arg1, arg2);
|
||||
string exception;
|
||||
|
||||
return exception != null
|
||||
? throw new JSException(exception)
|
||||
: result;
|
||||
switch (resultType)
|
||||
{
|
||||
case JSCallResultType.Default:
|
||||
var result = InternalCalls.InvokeJS<T0, T1, T2, TResult>(out exception, ref callInfo, arg0, arg1, arg2);
|
||||
return exception != null
|
||||
? throw new JSException(exception)
|
||||
: result;
|
||||
case JSCallResultType.JSObjectReference:
|
||||
var id = InternalCalls.InvokeJS<T0, T1, T2, int>(out exception, ref callInfo, arg0, arg1, arg2);
|
||||
return exception != null
|
||||
? throw new JSException(exception)
|
||||
: (TResult)(object)new WebAssemblyJSObjectReference(this, id);
|
||||
default:
|
||||
throw new InvalidOperationException($"Invalid result type '{resultType}'.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public TResult InvokeUnmarshalled<TResult>(string identifier)
|
||||
=> InvokeUnmarshalled<object, object, object, TResult>(identifier, null, null, null, 0);
|
||||
|
||||
/// <inheritdoc />
|
||||
public TResult InvokeUnmarshalled<T0, TResult>(string identifier, T0 arg0)
|
||||
=> InvokeUnmarshalled<T0, object, object, TResult>(identifier, arg0, null, null, 0);
|
||||
|
||||
/// <inheritdoc />
|
||||
public TResult InvokeUnmarshalled<T0, T1, TResult>(string identifier, T0 arg0, T1 arg1)
|
||||
=> InvokeUnmarshalled<T0, T1, object, TResult>(identifier, arg0, arg1, null, 0);
|
||||
|
||||
/// <inheritdoc />
|
||||
public TResult InvokeUnmarshalled<T0, T1, T2, TResult>(string identifier, T0 arg0, T1 arg1, T2 arg2)
|
||||
=> InvokeUnmarshalled<T0, T1, T2, TResult>(identifier, arg0, arg1, arg2, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Rendering
|
|||
/// <inheritdoc />
|
||||
protected override Task UpdateDisplayAsync(in RenderBatch batch)
|
||||
{
|
||||
((IJSUnmarshalledRuntime)DefaultWebAssemblyJSRuntime.Instance).InvokeUnmarshalled<int, RenderBatch, object>(
|
||||
DefaultWebAssemblyJSRuntime.Instance.InvokeUnmarshalled<int, RenderBatch, object>(
|
||||
"Blazor._internal.renderBatch",
|
||||
_webAssemblyRendererId,
|
||||
batch);
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Services
|
|||
_jsRuntime.InvokeVoid("console.error", formattedMessage);
|
||||
break;
|
||||
case LogLevel.Critical:
|
||||
((IJSUnmarshalledRuntime)_jsRuntime).InvokeUnmarshalled<string, object>("Blazor._internal.dotNetCriticalError", formattedMessage);
|
||||
_jsRuntime.InvokeUnmarshalled<string, object>("Blazor._internal.dotNetCriticalError", formattedMessage);
|
||||
break;
|
||||
default: // LogLevel.None or invalid enum values
|
||||
Console.WriteLine(formattedMessage);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,6 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Services
|
|||
public static WebAssemblyJSRuntimeInvoker Instance = new WebAssemblyJSRuntimeInvoker();
|
||||
|
||||
public virtual TResult InvokeUnmarshalled<T0, T1, T2, TResult>(string identifier, T0 arg0, T1 arg1, T2 arg2)
|
||||
=> ((IJSUnmarshalledRuntime)DefaultWebAssemblyJSRuntime.Instance).InvokeUnmarshalled<T0, T1, T2, TResult>(identifier, arg0, arg1, arg2);
|
||||
=> DefaultWebAssemblyJSRuntime.Instance.InvokeUnmarshalled<T0, T1, T2, TResult>(identifier, arg0, arg1, arg2);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
|||
["instanceMethodIncomingByRef"] = "123",
|
||||
["instanceMethodOutgoingByRef"] = "1234",
|
||||
["jsInProcessObjectReference.identity"] = "Invoked from JSInProcessObjectReference",
|
||||
["jsUnmarshalledObjectReference.unmarshalledFunction"] = "True",
|
||||
["stringValueUpperSync"] = "MY STRING",
|
||||
["testDtoNonSerializedValueSync"] = "99999",
|
||||
["testDtoSync"] = "Same",
|
||||
|
|
|
|||
|
|
@ -194,6 +194,14 @@
|
|||
|
||||
var jsInProcObjectReference = inProcRuntime.Invoke<IJSInProcessObjectReference>("returnJSObjectReference");
|
||||
ReturnValues["jsInProcessObjectReference.identity"] = jsInProcObjectReference.Invoke<string>("identity", "Invoked from JSInProcessObjectReference");
|
||||
|
||||
var unmarshalledRuntime = (IJSUnmarshalledRuntime)JSRuntime;
|
||||
var jsUnmarshalledReference = unmarshalledRuntime.InvokeUnmarshalled<IJSUnmarshalledObjectReference>("returnJSObjectReference");
|
||||
ReturnValues["jsUnmarshalledObjectReference.unmarshalledFunction"] = jsUnmarshalledReference.InvokeUnmarshalled<InteropStruct, bool>("unmarshalledFunction", new InteropStruct
|
||||
{
|
||||
Message = "Sent from .NET",
|
||||
NumberField = 42,
|
||||
}).ToString();
|
||||
}
|
||||
|
||||
public class PassDotNetObjectByRefArgs
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BasicTestApp.InteropTest
|
||||
{
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct InteropStruct
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public string Message;
|
||||
|
||||
[FieldOffset(8)]
|
||||
public int NumberField;
|
||||
}
|
||||
}
|
||||
|
|
@ -233,6 +233,11 @@ function returnJSObjectReference() {
|
|||
dispose: function () {
|
||||
DotNet.disposeJSObjectReference(this);
|
||||
},
|
||||
unmarshalledFunction: function (fields) {
|
||||
const message = Blazor.platform.readStringField(fields, 0);
|
||||
const numberField = Blazor.platform.readInt32Field(fields, 8);
|
||||
return message === "Sent from .NET" && numberField === 42;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.JSInterop
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a reference to a JavaScript object whose functions can be invoked synchronously.
|
||||
/// </summary>
|
||||
public interface IJSInProcessObjectReference : IJSObjectReference
|
||||
public interface IJSInProcessObjectReference : IJSObjectReference, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Invokes the specified JavaScript function synchronously.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.JSInterop
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a reference to a JavaScript object whose functions can be invoked synchronously without JSON marshalling.
|
||||
/// </summary>
|
||||
public interface IJSUnmarshalledObjectReference : IJSInProcessObjectReference
|
||||
{
|
||||
/// <summary>
|
||||
/// Invokes the JavaScript function registered with the specified identifier.
|
||||
/// </summary>
|
||||
/// <typeparam name="TResult">The .NET type corresponding to the function's return value type.</typeparam>
|
||||
/// <param name="identifier">The identifier used when registering the target function.</param>
|
||||
/// <returns>The result of the function invocation.</returns>
|
||||
TResult InvokeUnmarshalled<TResult>(string identifier);
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the JavaScript function registered with the specified identifier.
|
||||
/// </summary>
|
||||
/// <typeparam name="T0">The type of the first argument.</typeparam>
|
||||
/// <typeparam name="TResult">The .NET type corresponding to the function's return value type.</typeparam>
|
||||
/// <param name="identifier">The identifier used when registering the target function.</param>
|
||||
/// <param name="arg0">The first argument.</param>
|
||||
/// <returns>The result of the function invocation.</returns>
|
||||
TResult InvokeUnmarshalled<T0, TResult>(string identifier, T0 arg0);
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the JavaScript function registered with the specified identifier.
|
||||
/// </summary>
|
||||
/// <typeparam name="T0">The type of the first argument.</typeparam>
|
||||
/// <typeparam name="T1">The type of the second argument.</typeparam>
|
||||
/// <typeparam name="TResult">The .NET type corresponding to the function's return value type.</typeparam>
|
||||
/// <param name="identifier">The identifier used when registering the target function.</param>
|
||||
/// <param name="arg0">The first argument.</param>
|
||||
/// <param name="arg1">The second argument.</param>
|
||||
/// <returns>The result of the function invocation.</returns>
|
||||
TResult InvokeUnmarshalled<T0, T1, TResult>(string identifier, T0 arg0, T1 arg1);
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the JavaScript function registered with the specified identifier.
|
||||
/// </summary>
|
||||
/// <typeparam name="T0">The type of the first argument.</typeparam>
|
||||
/// <typeparam name="T1">The type of the second argument.</typeparam>
|
||||
/// <typeparam name="T2">The type of the third argument.</typeparam>
|
||||
/// <typeparam name="TResult">The .NET type corresponding to the function's return value type.</typeparam>
|
||||
/// <param name="identifier">The identifier used when registering the target function.</param>
|
||||
/// <param name="arg0">The first argument.</param>
|
||||
/// <param name="arg1">The second argument.</param>
|
||||
/// <param name="arg2">The third argument.</param>
|
||||
/// <returns>The result of the function invocation.</returns>
|
||||
TResult InvokeUnmarshalled<T0, T1, T2, TResult>(string identifier, T0 arg0, T1 arg1, T2 arg2);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Microsoft.JSInterop.Implementation
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements functionality for <see cref="IJSInProcessObjectReference"/>.
|
||||
/// </summary>
|
||||
public class JSInProcessObjectReference : JSObjectReference, IJSInProcessObjectReference
|
||||
{
|
||||
private readonly JSInProcessRuntime _jsRuntime;
|
||||
|
||||
/// <summary>
|
||||
/// Inititializes a new <see cref="JSInProcessObjectReference"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="jsRuntime">The <see cref="JSInProcessRuntime"/> used for invoking JS interop calls.</param>
|
||||
/// <param name="id">The unique identifier.</param>
|
||||
protected internal JSInProcessObjectReference(JSInProcessRuntime jsRuntime, long id) : base(jsRuntime, id)
|
||||
{
|
||||
_jsRuntime = jsRuntime;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[return: MaybeNull]
|
||||
public TValue Invoke<TValue>(string identifier, params object?[]? args)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
return _jsRuntime.Invoke<TValue>(identifier, Id, args);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
if (!Disposed)
|
||||
{
|
||||
Disposed = true;
|
||||
|
||||
_jsRuntime.InvokeVoid("DotNet.jsCallDispatcher.disposeJSObjectReferenceById", Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,29 +2,38 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.JSInterop
|
||||
namespace Microsoft.JSInterop.Implementation
|
||||
{
|
||||
internal class JSObjectReference : IJSObjectReference
|
||||
/// <summary>
|
||||
/// Implements functionality for <see cref="IJSObjectReference"/>.
|
||||
/// </summary>
|
||||
public class JSObjectReference : IJSObjectReference
|
||||
{
|
||||
public static readonly JsonEncodedText IdKey = JsonEncodedText.Encode("__jsObjectId");
|
||||
|
||||
private readonly JSRuntime _jsRuntime;
|
||||
|
||||
private bool _disposed;
|
||||
internal bool Disposed { get; set; }
|
||||
|
||||
public long Id { get; }
|
||||
/// <summary>
|
||||
/// The unique identifier assigned to this instance.
|
||||
/// </summary>
|
||||
protected internal long Id { get; }
|
||||
|
||||
public JSObjectReference(JSRuntime jsRuntime, long id)
|
||||
/// <summary>
|
||||
/// Inititializes a new <see cref="JSObjectReference"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="jsRuntime">The <see cref="JSRuntime"/> used for invoking JS interop calls.</param>
|
||||
/// <param name="id">The unique identifier.</param>
|
||||
protected internal JSObjectReference(JSRuntime jsRuntime, long id)
|
||||
{
|
||||
_jsRuntime = jsRuntime;
|
||||
|
||||
Id = id;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask<TValue> InvokeAsync<TValue>(string identifier, object?[]? args)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
|
@ -32,6 +41,7 @@ namespace Microsoft.JSInterop
|
|||
return _jsRuntime.InvokeAsync<TValue>(Id, identifier, args);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask<TValue> InvokeAsync<TValue>(string identifier, CancellationToken cancellationToken, object?[]? args)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
|
@ -39,19 +49,21 @@ namespace Microsoft.JSInterop
|
|||
return _jsRuntime.InvokeAsync<TValue>(Id, identifier, cancellationToken, args);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
if (!_disposed)
|
||||
if (!Disposed)
|
||||
{
|
||||
_disposed = true;
|
||||
Disposed = true;
|
||||
|
||||
await _jsRuntime.InvokeVoidAsync("DotNet.jsCallDispatcher.disposeJSObjectReferenceById", Id);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected void ThrowIfDisposed()
|
||||
{
|
||||
if (_disposed)
|
||||
if (Disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(GetType().Name);
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.JSInterop.Implementation;
|
||||
|
||||
namespace Microsoft.JSInterop.Infrastructure
|
||||
{
|
||||
|
|
@ -11,6 +12,8 @@ namespace Microsoft.JSInterop.Infrastructure
|
|||
where TInterface : class, IJSObjectReference
|
||||
where TImplementation : JSObjectReference, TInterface
|
||||
{
|
||||
private static readonly JsonEncodedText _idKey = JsonEncodedText.Encode("__jsObjectId");
|
||||
|
||||
private readonly Func<long, TImplementation> _jsObjectReferenceFactory;
|
||||
|
||||
public JSObjectReferenceJsonConverter(Func<long, TImplementation> jsObjectReferenceFactory)
|
||||
|
|
@ -29,7 +32,7 @@ namespace Microsoft.JSInterop.Infrastructure
|
|||
{
|
||||
if (reader.TokenType == JsonTokenType.PropertyName)
|
||||
{
|
||||
if (id == -1 && reader.ValueTextEquals(JSObjectReference.IdKey.EncodedUtf8Bytes))
|
||||
if (id == -1 && reader.ValueTextEquals(_idKey.EncodedUtf8Bytes))
|
||||
{
|
||||
reader.Read();
|
||||
id = reader.GetInt64();
|
||||
|
|
@ -47,7 +50,7 @@ namespace Microsoft.JSInterop.Infrastructure
|
|||
|
||||
if (id == -1)
|
||||
{
|
||||
throw new JsonException($"Required property {JSObjectReference.IdKey} not found.");
|
||||
throw new JsonException($"Required property {_idKey} not found.");
|
||||
}
|
||||
|
||||
return _jsObjectReferenceFactory(id);
|
||||
|
|
@ -56,7 +59,7 @@ namespace Microsoft.JSInterop.Infrastructure
|
|||
public override void Write(Utf8JsonWriter writer, TInterface value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
writer.WriteNumber(JSObjectReference.IdKey, ((TImplementation)value).Id);
|
||||
writer.WriteNumber(_idKey, ((TImplementation)value).Id);
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Microsoft.JSInterop
|
||||
{
|
||||
internal class JSInProcessObjectReference : JSObjectReference, IJSInProcessObjectReference
|
||||
{
|
||||
private readonly JSInProcessRuntime _jsRuntime;
|
||||
|
||||
internal JSInProcessObjectReference(JSInProcessRuntime jsRuntime, long id) : base(jsRuntime, id)
|
||||
{
|
||||
_jsRuntime = jsRuntime;
|
||||
}
|
||||
|
||||
[return: MaybeNull]
|
||||
public TValue Invoke<TValue>(string identifier, params object?[]? args)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
return _jsRuntime.Invoke<TValue>(identifier, Id, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json;
|
||||
using Microsoft.JSInterop.Implementation;
|
||||
using Microsoft.JSInterop.Infrastructure;
|
||||
|
||||
namespace Microsoft.JSInterop
|
||||
|
|
@ -17,8 +18,9 @@ namespace Microsoft.JSInterop
|
|||
/// </summary>
|
||||
protected JSInProcessRuntime()
|
||||
{
|
||||
JsonSerializerOptions.Converters.Add(new JSObjectReferenceJsonConverter<IJSInProcessObjectReference, JSInProcessObjectReference>(
|
||||
id => new JSInProcessObjectReference(this, id)));
|
||||
JsonSerializerOptions.Converters.Add(
|
||||
new JSObjectReferenceJsonConverter<IJSInProcessObjectReference, JSInProcessObjectReference>(
|
||||
id => new JSInProcessObjectReference(this, id)));
|
||||
}
|
||||
|
||||
[return: MaybeNull]
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using System.Linq;
|
|||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.JSInterop.Implementation;
|
||||
using Microsoft.JSInterop.Infrastructure;
|
||||
|
||||
namespace Microsoft.JSInterop
|
||||
|
|
@ -37,7 +38,8 @@ namespace Microsoft.JSInterop
|
|||
Converters =
|
||||
{
|
||||
new DotNetObjectReferenceJsonConverterFactory(this),
|
||||
new JSObjectReferenceJsonConverter<IJSObjectReference, JSObjectReference>(id => new JSObjectReference(this, id)),
|
||||
new JSObjectReferenceJsonConverter<IJSObjectReference, JSObjectReference>(
|
||||
id => new JSObjectReference(this, id)),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using Microsoft.JSInterop.Implementation;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.JSInterop.Infrastructure
|
||||
|
|
@ -9,7 +11,16 @@ namespace Microsoft.JSInterop.Infrastructure
|
|||
public class JSObjectReferenceJsonConverterTest
|
||||
{
|
||||
private readonly JSRuntime JSRuntime = new TestJSRuntime();
|
||||
private JsonSerializerOptions JsonSerializerOptions => JSRuntime.JsonSerializerOptions;
|
||||
private readonly JsonSerializerOptions JsonSerializerOptions;
|
||||
|
||||
public JSObjectReferenceJsonConverterTest()
|
||||
{
|
||||
JsonSerializerOptions = JSRuntime.JsonSerializerOptions;
|
||||
JsonSerializerOptions.Converters.Add(new JSObjectReferenceJsonConverter<IJSInProcessObjectReference, JSInProcessObjectReference>(
|
||||
id => new JSInProcessObjectReference(default!, id)));
|
||||
JsonSerializerOptions.Converters.Add(new JSObjectReferenceJsonConverter<IJSUnmarshalledObjectReference, TestJSUnmarshalledObjectReference>(
|
||||
id => new TestJSUnmarshalledObjectReference(id)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Read_Throws_IfJsonIsMissingJSObjectIdProperty()
|
||||
|
|
@ -56,7 +67,7 @@ namespace Microsoft.JSInterop.Infrastructure
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void Read_ReadsJson()
|
||||
public void Read_ReadsJson_IJSObjectReference()
|
||||
{
|
||||
// Arrange
|
||||
var expectedId = 3;
|
||||
|
|
@ -69,6 +80,34 @@ namespace Microsoft.JSInterop.Infrastructure
|
|||
Assert.Equal(expectedId, deserialized?.Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Read_ReadsJson_IJSInProcessObjectReference()
|
||||
{
|
||||
// Arrange
|
||||
var expectedId = 3;
|
||||
var json = $"{{\"__jsObjectId\":{expectedId}}}";
|
||||
|
||||
// Act
|
||||
var deserialized = (JSInProcessObjectReference)JsonSerializer.Deserialize<IJSInProcessObjectReference>(json, JsonSerializerOptions)!;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedId, deserialized?.Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Read_ReadsJson_IJSUnmarshalledObjectReference()
|
||||
{
|
||||
// Arrange
|
||||
var expectedId = 3;
|
||||
var json = $"{{\"__jsObjectId\":{expectedId}}}";
|
||||
|
||||
// Act
|
||||
var deserialized = (TestJSUnmarshalledObjectReference)JsonSerializer.Deserialize<IJSUnmarshalledObjectReference>(json, JsonSerializerOptions)!;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedId, deserialized?.Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Write_WritesValidJson()
|
||||
{
|
||||
|
|
@ -81,5 +120,32 @@ namespace Microsoft.JSInterop.Infrastructure
|
|||
// Assert
|
||||
Assert.Equal($"{{\"__jsObjectId\":{jsObjectRef.Id}}}", json);
|
||||
}
|
||||
|
||||
private class TestJSUnmarshalledObjectReference : JSInProcessObjectReference, IJSUnmarshalledObjectReference
|
||||
{
|
||||
public TestJSUnmarshalledObjectReference(long id) : base(default!, id)
|
||||
{
|
||||
}
|
||||
|
||||
public TResult InvokeUnmarshalled<TResult>(string identifier)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public TResult InvokeUnmarshalled<T0, TResult>(string identifier, T0 arg0)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public TResult InvokeUnmarshalled<T0, T1, TResult>(string identifier, T0 arg0, T1 arg1)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public TResult InvokeUnmarshalled<T0, T1, T2, TResult>(string identifier, T0 arg0, T1 arg1, T2 arg2)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.JSInterop.Implementation;
|
||||
using Microsoft.JSInterop.Infrastructure;
|
||||
using Xunit;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ namespace Microsoft.JSInterop
|
|||
internal static class JSCallResultTypeHelper
|
||||
{
|
||||
public static JSCallResultType FromGeneric<TResult>()
|
||||
=> typeof(TResult) == typeof(IJSObjectReference) || typeof(TResult) == typeof(IJSInProcessObjectReference) ?
|
||||
=> typeof(TResult) == typeof(IJSObjectReference)
|
||||
|| typeof(TResult) == typeof(IJSInProcessObjectReference)
|
||||
|| typeof(TResult) == typeof(IJSUnmarshalledObjectReference) ?
|
||||
JSCallResultType.JSObjectReference :
|
||||
JSCallResultType.Default;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue