JSObjectReference API review follow-up (#25476)
* API review changes. * Fixed JSObjectReferenceJsonConverter * CR feedback * Update JSObjectReferenceExtensions.cs
This commit is contained in:
parent
6ec1b48118
commit
2a0b7dc43e
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
|
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
|
||||||
|
|
@ -12,4 +12,8 @@
|
||||||
<Reference Include="Microsoft.JSInterop" />
|
<Reference Include="Microsoft.JSInterop" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="$(SharedSourceRoot)JSInterop\*.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ namespace Microsoft.JSInterop.WebAssembly
|
||||||
var callInfo = new JSCallInfo
|
var callInfo = new JSCallInfo
|
||||||
{
|
{
|
||||||
FunctionIdentifier = identifier,
|
FunctionIdentifier = identifier,
|
||||||
ResultType = ResultTypeFromGeneric<TResult>()
|
ResultType = JSCallResultTypeHelper.FromGeneric<TResult>()
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = InternalCalls.InvokeJS<T0, T1, T2, TResult>(out var exception, ref callInfo, arg0, arg1, arg2);
|
var result = InternalCalls.InvokeJS<T0, T1, T2, TResult>(out var exception, ref callInfo, arg0, arg1, arg2);
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@
|
||||||
ReturnValues["returnArray"] = string.Join(",", ((IJSInProcessRuntime)JSRuntime).Invoke<Segment[]>("returnArray").Select(x => x.Source).ToArray());
|
ReturnValues["returnArray"] = string.Join(",", ((IJSInProcessRuntime)JSRuntime).Invoke<Segment[]>("returnArray").Select(x => x.Source).ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
var jsObjectReference = await JSRuntime.InvokeAsync<JSObjectReference>("returnJSObjectReference");
|
var jsObjectReference = await JSRuntime.InvokeAsync<IJSObjectReference>("returnJSObjectReference");
|
||||||
ReturnValues["jsObjectReference.identity"] = await jsObjectReference.InvokeAsync<string>("identity", "Invoked from JSObjectReference");
|
ReturnValues["jsObjectReference.identity"] = await jsObjectReference.InvokeAsync<string>("identity", "Invoked from JSObjectReference");
|
||||||
ReturnValues["jsObjectReference.nested.add"] = (await jsObjectReference.InvokeAsync<int>("nested.add", 2, 3)).ToString();
|
ReturnValues["jsObjectReference.nested.add"] = (await jsObjectReference.InvokeAsync<int>("nested.add", 2, 3)).ToString();
|
||||||
ReturnValues["addViaJSObjectReference"] = (await JSRuntime.InvokeAsync<int>("addViaJSObjectReference", jsObjectReference, 2, 3)).ToString();
|
ReturnValues["addViaJSObjectReference"] = (await JSRuntime.InvokeAsync<int>("addViaJSObjectReference", jsObjectReference, 2, 3)).ToString();
|
||||||
|
|
@ -151,7 +151,7 @@
|
||||||
JSObjectReferenceInvokeNonFunctionException = e;
|
JSObjectReferenceInvokeNonFunctionException = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
var module = await JSRuntime.InvokeAsync<JSObjectReference>("import", "./js/testmodule.js");
|
var module = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./js/testmodule.js");
|
||||||
ReturnValues["jsObjectReferenceModule"] = await module.InvokeAsync<string>("identity", "Returned from module!");
|
ReturnValues["jsObjectReferenceModule"] = await module.InvokeAsync<string>("identity", "Returned from module!");
|
||||||
|
|
||||||
if (shouldSupportSyncInterop)
|
if (shouldSupportSyncInterop)
|
||||||
|
|
@ -192,7 +192,7 @@
|
||||||
{
|
{
|
||||||
var inProcRuntime = ((IJSInProcessRuntime)JSRuntime);
|
var inProcRuntime = ((IJSInProcessRuntime)JSRuntime);
|
||||||
|
|
||||||
var jsInProcObjectReference = inProcRuntime.Invoke<JSInProcessObjectReference>("returnJSObjectReference");
|
var jsInProcObjectReference = inProcRuntime.Invoke<IJSInProcessObjectReference>("returnJSObjectReference");
|
||||||
ReturnValues["jsInProcessObjectReference.identity"] = jsInProcObjectReference.Invoke<string>("identity", "Invoked from JSInProcessObjectReference");
|
ReturnValues["jsInProcessObjectReference.identity"] = jsInProcObjectReference.Invoke<string>("identity", "Invoked from JSInProcessObjectReference");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -415,20 +415,20 @@ namespace BasicTestApp.InteropTest
|
||||||
}
|
}
|
||||||
|
|
||||||
[JSInvokable]
|
[JSInvokable]
|
||||||
public static JSObjectReference RoundTripJSObjectReference(JSObjectReference jsObjectReference)
|
public static IJSObjectReference RoundTripJSObjectReference(IJSObjectReference jsObjectReference)
|
||||||
{
|
{
|
||||||
return jsObjectReference;
|
return jsObjectReference;
|
||||||
}
|
}
|
||||||
|
|
||||||
[JSInvokable]
|
[JSInvokable]
|
||||||
public static async Task<JSObjectReference> RoundTripJSObjectReferenceAsync(JSObjectReference jSObjectReference)
|
public static async Task<IJSObjectReference> RoundTripJSObjectReferenceAsync(IJSObjectReference jSObjectReference)
|
||||||
{
|
{
|
||||||
await Task.Yield();
|
await Task.Yield();
|
||||||
return jSObjectReference;
|
return jSObjectReference;
|
||||||
}
|
}
|
||||||
|
|
||||||
[JSInvokable]
|
[JSInvokable]
|
||||||
public static string InvokeDisposedJSObjectReferenceException(JSInProcessObjectReference jsObjectReference)
|
public static string InvokeDisposedJSObjectReferenceException(IJSInProcessObjectReference jsObjectReference)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -442,7 +442,7 @@ namespace BasicTestApp.InteropTest
|
||||||
}
|
}
|
||||||
|
|
||||||
[JSInvokable]
|
[JSInvokable]
|
||||||
public static async Task<string> InvokeDisposedJSObjectReferenceExceptionAsync(JSObjectReference jsObjectReference)
|
public static async Task<string> InvokeDisposedJSObjectReferenceExceptionAsync(IJSObjectReference jsObjectReference)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
// 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.
|
||||||
|
/// </summary>
|
||||||
|
public interface IJSInProcessObjectReference : IJSObjectReference
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the specified JavaScript function synchronously.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TValue">The JSON-serializable return type.</typeparam>
|
||||||
|
/// <param name="identifier">An identifier for the function to invoke. For example, the value <c>"someScope.someFunction"</c> will invoke the function <c>someScope.someFunction</c> on the target instance.</param>
|
||||||
|
/// <param name="args">JSON-serializable arguments.</param>
|
||||||
|
/// <returns>An instance of <typeparamref name="TValue"/> obtained by JSON-deserializing the return value.</returns>
|
||||||
|
TValue Invoke<TValue>(string identifier, params object?[]? args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
// 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.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.JSInterop
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a reference to a JavaScript object.
|
||||||
|
/// </summary>
|
||||||
|
public interface IJSObjectReference : IAsyncDisposable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the specified JavaScript function asynchronously.
|
||||||
|
/// <para>
|
||||||
|
/// <see cref="JSRuntime"/> will apply timeouts to this operation based on the value configured in <see cref="JSRuntime.DefaultAsyncTimeout"/>. To dispatch a call with a different, or no timeout,
|
||||||
|
/// consider using <see cref="InvokeAsync{TValue}(string, CancellationToken, object[])" />.
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TValue">The JSON-serializable return type.</typeparam>
|
||||||
|
/// <param name="identifier">An identifier for the function to invoke. For example, the value <c>"someScope.someFunction"</c> will invoke the function <c>someScope.someFunction</c> on the target instance.</param>
|
||||||
|
/// <param name="args">JSON-serializable arguments.</param>
|
||||||
|
/// <returns>An instance of <typeparamref name="TValue"/> obtained by JSON-deserializing the return value.</returns>
|
||||||
|
ValueTask<TValue> InvokeAsync<TValue>(string identifier, object?[]? args);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the specified JavaScript function asynchronously.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TValue">The JSON-serializable return type.</typeparam>
|
||||||
|
/// <param name="identifier">An identifier for the function to invoke. For example, the value <c>"someScope.someFunction"</c> will invoke the function <c>someScope.someFunction</c> on the target instance.</param>
|
||||||
|
/// <param name="cancellationToken">
|
||||||
|
/// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts
|
||||||
|
/// (<see cref="JSRuntime.DefaultAsyncTimeout"/>) from being applied.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="args">JSON-serializable arguments.</param>
|
||||||
|
/// <returns>An instance of <typeparamref name="TValue"/> obtained by JSON-deserializing the return value.</returns>
|
||||||
|
ValueTask<TValue> InvokeAsync<TValue>(string identifier, CancellationToken cancellationToken, object?[]? args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,17 +7,21 @@ using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace Microsoft.JSInterop.Infrastructure
|
namespace Microsoft.JSInterop.Infrastructure
|
||||||
{
|
{
|
||||||
internal sealed class JSObjectReferenceJsonConverter<TJSObjectReference>
|
internal sealed class JSObjectReferenceJsonConverter<TInterface, TImplementation> : JsonConverter<TInterface>
|
||||||
: JsonConverter<TJSObjectReference> where TJSObjectReference : JSObjectReference
|
where TInterface : class, IJSObjectReference
|
||||||
|
where TImplementation : JSObjectReference, TInterface
|
||||||
{
|
{
|
||||||
private readonly Func<long, TJSObjectReference> _jsObjectReferenceFactory;
|
private readonly Func<long, TImplementation> _jsObjectReferenceFactory;
|
||||||
|
|
||||||
public JSObjectReferenceJsonConverter(Func<long, TJSObjectReference> jsObjectReferenceFactory)
|
public JSObjectReferenceJsonConverter(Func<long, TImplementation> jsObjectReferenceFactory)
|
||||||
{
|
{
|
||||||
_jsObjectReferenceFactory = jsObjectReferenceFactory;
|
_jsObjectReferenceFactory = jsObjectReferenceFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override TJSObjectReference? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
public override bool CanConvert(Type typeToConvert)
|
||||||
|
=> typeToConvert == typeof(TInterface) || typeToConvert == typeof(TImplementation);
|
||||||
|
|
||||||
|
public override TInterface? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
long id = -1;
|
long id = -1;
|
||||||
|
|
||||||
|
|
@ -49,10 +53,10 @@ namespace Microsoft.JSInterop.Infrastructure
|
||||||
return _jsObjectReferenceFactory(id);
|
return _jsObjectReferenceFactory(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Write(Utf8JsonWriter writer, TJSObjectReference value, JsonSerializerOptions options)
|
public override void Write(Utf8JsonWriter writer, TInterface value, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
writer.WriteStartObject();
|
writer.WriteStartObject();
|
||||||
writer.WriteNumber(JSObjectReference.IdKey, value.Id);
|
writer.WriteNumber(JSObjectReference.IdKey, ((TImplementation)value).Id);
|
||||||
writer.WriteEndObject();
|
writer.WriteEndObject();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,7 @@ using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace Microsoft.JSInterop
|
namespace Microsoft.JSInterop
|
||||||
{
|
{
|
||||||
/// <summary>
|
internal class JSInProcessObjectReference : JSObjectReference, IJSInProcessObjectReference
|
||||||
/// Represents a reference to a JavaScript object whose functions can be invoked synchronously.
|
|
||||||
/// </summary>
|
|
||||||
public class JSInProcessObjectReference : JSObjectReference
|
|
||||||
{
|
{
|
||||||
private readonly JSInProcessRuntime _jsRuntime;
|
private readonly JSInProcessRuntime _jsRuntime;
|
||||||
|
|
||||||
|
|
@ -17,15 +14,8 @@ namespace Microsoft.JSInterop
|
||||||
_jsRuntime = jsRuntime;
|
_jsRuntime = jsRuntime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invokes the specified JavaScript function synchronously.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TValue">The JSON-serializable return type.</typeparam>
|
|
||||||
/// <param name="identifier">An identifier for the function to invoke. For example, the value <c>"someScope.someFunction"</c> will invoke the function <c>someScope.someFunction</c> on the target instance.</param>
|
|
||||||
/// <param name="args">JSON-serializable arguments.</param>
|
|
||||||
/// <returns>An instance of <typeparamref name="TValue"/> obtained by JSON-deserializing the return value.</returns>
|
|
||||||
[return: MaybeNull]
|
[return: MaybeNull]
|
||||||
public TValue Invoke<TValue>(string identifier, params object[] args)
|
public TValue Invoke<TValue>(string identifier, params object?[]? args)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ThrowIfDisposed();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
public static class JSInProcessObjectReferenceExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the specified JavaScript function synchronously.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="jsObjectReference">The <see cref="IJSInProcessObjectReference"/>.</param>
|
||||||
|
/// <param name="identifier">An identifier for the function to invoke. For example, the value <c>"someScope.someFunction"</c> will invoke the function <c>someScope.someFunction</c> on the target instance.</param>
|
||||||
|
/// <param name="args">JSON-serializable arguments.</param>
|
||||||
|
public static void InvokeVoid(this IJSInProcessObjectReference jsObjectReference, string identifier, params object?[] args)
|
||||||
|
{
|
||||||
|
if (jsObjectReference == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(jsObjectReference));
|
||||||
|
}
|
||||||
|
|
||||||
|
jsObjectReference.Invoke<object>(identifier, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,7 +17,7 @@ namespace Microsoft.JSInterop
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected JSInProcessRuntime()
|
protected JSInProcessRuntime()
|
||||||
{
|
{
|
||||||
JsonSerializerOptions.Converters.Add(new JSObjectReferenceJsonConverter<JSInProcessObjectReference>(
|
JsonSerializerOptions.Converters.Add(new JSObjectReferenceJsonConverter<IJSInProcessObjectReference, JSInProcessObjectReference>(
|
||||||
id => new JSInProcessObjectReference(this, id)));
|
id => new JSInProcessObjectReference(this, id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -27,7 +27,7 @@ namespace Microsoft.JSInterop
|
||||||
var resultJson = InvokeJS(
|
var resultJson = InvokeJS(
|
||||||
identifier,
|
identifier,
|
||||||
JsonSerializer.Serialize(args, JsonSerializerOptions),
|
JsonSerializer.Serialize(args, JsonSerializerOptions),
|
||||||
ResultTypeFromGeneric<TValue>(),
|
JSCallResultTypeHelper.FromGeneric<TValue>(),
|
||||||
targetInstanceId);
|
targetInstanceId);
|
||||||
|
|
||||||
if (resultJson is null)
|
if (resultJson is null)
|
||||||
|
|
|
||||||
|
|
@ -8,77 +8,37 @@ using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Microsoft.JSInterop
|
namespace Microsoft.JSInterop
|
||||||
{
|
{
|
||||||
/// <summary>
|
internal class JSObjectReference : IJSObjectReference
|
||||||
/// Represents a reference to a JavaScript object.
|
|
||||||
/// </summary>
|
|
||||||
public class JSObjectReference : IAsyncDisposable
|
|
||||||
{
|
{
|
||||||
internal static readonly JsonEncodedText IdKey = JsonEncodedText.Encode("__jsObjectId");
|
public static readonly JsonEncodedText IdKey = JsonEncodedText.Encode("__jsObjectId");
|
||||||
|
|
||||||
private readonly JSRuntime _jsRuntime;
|
private readonly JSRuntime _jsRuntime;
|
||||||
|
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
internal long Id { get; }
|
public long Id { get; }
|
||||||
|
|
||||||
internal JSObjectReference(JSRuntime jsRuntime, long id)
|
public JSObjectReference(JSRuntime jsRuntime, long id)
|
||||||
{
|
{
|
||||||
_jsRuntime = jsRuntime;
|
_jsRuntime = jsRuntime;
|
||||||
|
|
||||||
Id = id;
|
Id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public ValueTask<TValue> InvokeAsync<TValue>(string identifier, object?[]? args)
|
||||||
/// Invokes the specified JavaScript function asynchronously.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="identifier">An identifier for the function to invoke. For example, the value <c>"someScope.someFunction"</c> will invoke the function <c>someScope.someFunction</c> on the target instance.</param>
|
|
||||||
/// <param name="args">JSON-serializable arguments.</param>
|
|
||||||
/// <returns>A <see cref="ValueTask"/> that represents the asynchronous invocation operation.</returns>
|
|
||||||
public async ValueTask InvokeVoidAsync(string identifier, params object[] args)
|
|
||||||
{
|
|
||||||
await InvokeAsync<object>(identifier, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invokes the specified JavaScript function asynchronously.
|
|
||||||
/// <para>
|
|
||||||
/// <see cref="JSRuntime"/> will apply timeouts to this operation based on the value configured in <see cref="JSRuntime.DefaultAsyncTimeout"/>. To dispatch a call with a different, or no timeout,
|
|
||||||
/// consider using <see cref="InvokeAsync{TValue}(string, CancellationToken, object[])" />.
|
|
||||||
/// </para>
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TValue">The JSON-serializable return type.</typeparam>
|
|
||||||
/// <param name="identifier">An identifier for the function to invoke. For example, the value <c>"someScope.someFunction"</c> will invoke the function <c>someScope.someFunction</c> on the target instance.</param>
|
|
||||||
/// <param name="args">JSON-serializable arguments.</param>
|
|
||||||
/// <returns>An instance of <typeparamref name="TValue"/> obtained by JSON-deserializing the return value.</returns>
|
|
||||||
public ValueTask<TValue> InvokeAsync<TValue>(string identifier, params object[] args)
|
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ThrowIfDisposed();
|
||||||
|
|
||||||
return _jsRuntime.InvokeAsync<TValue>(Id, identifier, args);
|
return _jsRuntime.InvokeAsync<TValue>(Id, identifier, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public ValueTask<TValue> InvokeAsync<TValue>(string identifier, CancellationToken cancellationToken, object?[]? args)
|
||||||
/// Invokes the specified JavaScript function asynchronously.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TValue">The JSON-serializable return type.</typeparam>
|
|
||||||
/// <param name="identifier">An identifier for the function to invoke. For example, the value <c>"someScope.someFunction"</c> will invoke the function <c>someScope.someFunction</c> on the target instance.</param>
|
|
||||||
/// <param name="cancellationToken">
|
|
||||||
/// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts
|
|
||||||
/// (<see cref="JSRuntime.DefaultAsyncTimeout"/>) from being applied.
|
|
||||||
/// </param>
|
|
||||||
/// <param name="args">JSON-serializable arguments.</param>
|
|
||||||
/// <returns>An instance of <typeparamref name="TValue"/> obtained by JSON-deserializing the return value.</returns>
|
|
||||||
public ValueTask<TValue> InvokeAsync<TValue>(string identifier, CancellationToken cancellationToken, params object[] args)
|
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ThrowIfDisposed();
|
||||||
|
|
||||||
return _jsRuntime.InvokeAsync<TValue>(Id, identifier, cancellationToken, args);
|
return _jsRuntime.InvokeAsync<TValue>(Id, identifier, cancellationToken, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Disposes the <see cref="JSObjectReference"/>, freeing its resources and disabling it from further use.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A <see cref="ValueTask"/> representing the completion of the operation.</returns>
|
|
||||||
public async ValueTask DisposeAsync()
|
public async ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
if (!_disposed)
|
if (!_disposed)
|
||||||
|
|
@ -89,9 +49,6 @@ namespace Microsoft.JSInterop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Throws an exception if this instance has been disposed.
|
|
||||||
/// </summary>
|
|
||||||
protected void ThrowIfDisposed()
|
protected void ThrowIfDisposed()
|
||||||
{
|
{
|
||||||
if (_disposed)
|
if (_disposed)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,139 @@
|
||||||
|
// 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.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.JSInterop
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Extensions for <see cref="IJSObjectReference"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static class JSObjectReferenceExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the specified JavaScript function asynchronously.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="jsObjectReference">The <see cref="IJSObjectReference"/>.</param>
|
||||||
|
/// <param name="identifier">An identifier for the function to invoke. For example, the value <c>"someScope.someFunction"</c> will invoke the function <c>someScope.someFunction</c> on the target instance.</param>
|
||||||
|
/// <param name="args">JSON-serializable arguments.</param>
|
||||||
|
/// <returns>A <see cref="ValueTask"/> that represents the asynchronous invocation operation.</returns>
|
||||||
|
public static async ValueTask InvokeVoidAsync(this IJSObjectReference jsObjectReference, string identifier, params object?[] args)
|
||||||
|
{
|
||||||
|
if (jsObjectReference is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(jsObjectReference));
|
||||||
|
}
|
||||||
|
|
||||||
|
await jsObjectReference.InvokeAsync<object>(identifier, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the specified JavaScript function asynchronously.
|
||||||
|
/// <para>
|
||||||
|
/// <see cref="JSRuntime"/> will apply timeouts to this operation based on the value configured in <see cref="JSRuntime.DefaultAsyncTimeout"/>. To dispatch a call with a different timeout, or no timeout,
|
||||||
|
/// consider using <see cref="IJSObjectReference.InvokeAsync{TValue}(string, CancellationToken, object[])" />.
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="jsObjectReference">The <see cref="IJSObjectReference"/>.</param>
|
||||||
|
/// <typeparam name="TValue">The JSON-serializable return type.</typeparam>
|
||||||
|
/// <param name="identifier">An identifier for the function to invoke. For example, the value <c>"someScope.someFunction"</c> will invoke the function <c>someScope.someFunction</c> on the target instance.</param>
|
||||||
|
/// <param name="args">JSON-serializable arguments.</param>
|
||||||
|
/// <returns>An instance of <typeparamref name="TValue"/> obtained by JSON-deserializing the return value.</returns>
|
||||||
|
public static ValueTask<TValue> InvokeAsync<TValue>(this IJSObjectReference jsObjectReference, string identifier, params object?[] args)
|
||||||
|
{
|
||||||
|
if (jsObjectReference is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(jsObjectReference));
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsObjectReference.InvokeAsync<TValue>(identifier, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the specified JavaScript function asynchronously.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TValue">The JSON-serializable return type.</typeparam>
|
||||||
|
/// <param name="jsObjectReference">The <see cref="IJSObjectReference"/>.</param>
|
||||||
|
/// <param name="identifier">An identifier for the function to invoke. For example, the value <c>"someScope.someFunction"</c> will invoke the function <c>someScope.someFunction</c> on the target instance.</param>
|
||||||
|
/// <param name="cancellationToken">
|
||||||
|
/// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts
|
||||||
|
/// (<see cref="JSRuntime.DefaultAsyncTimeout"/>) from being applied.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="args">JSON-serializable arguments.</param>
|
||||||
|
/// <returns>An instance of <typeparamref name="TValue"/> obtained by JSON-deserializing the return value.</returns>
|
||||||
|
public static ValueTask<TValue> InvokeAsync<TValue>(this IJSObjectReference jsObjectReference, string identifier, CancellationToken cancellationToken, params object?[] args)
|
||||||
|
{
|
||||||
|
if (jsObjectReference is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(jsObjectReference));
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsObjectReference.InvokeAsync<TValue>(identifier, cancellationToken, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the specified JavaScript function asynchronously.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="jsObjectReference">The <see cref="IJSObjectReference"/>.</param>
|
||||||
|
/// <param name="identifier">An identifier for the function to invoke. For example, the value <c>"someScope.someFunction"</c> will invoke the function <c>someScope.someFunction</c> on the target instance.</param>
|
||||||
|
/// <param name="cancellationToken">
|
||||||
|
/// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts
|
||||||
|
/// (<see cref="JSRuntime.DefaultAsyncTimeout"/>) from being applied.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="args">JSON-serializable arguments.</param>
|
||||||
|
/// <returns>A <see cref="ValueTask"/> that represents the asynchronous invocation operation.</returns>
|
||||||
|
public static async ValueTask InvokeVoidAsync(this IJSObjectReference jsObjectReference, string identifier, CancellationToken cancellationToken, params object?[] args)
|
||||||
|
{
|
||||||
|
if (jsObjectReference is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(jsObjectReference));
|
||||||
|
}
|
||||||
|
|
||||||
|
await jsObjectReference.InvokeAsync<object>(identifier, cancellationToken, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the specified JavaScript function asynchronously.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="jsObjectReference">The <see cref="IJSObjectReference"/>.</param>
|
||||||
|
/// <param name="identifier">An identifier for the function to invoke. For example, the value <c>"someScope.someFunction"</c> will invoke the function <c>someScope.someFunction</c> on the target instance.</param>
|
||||||
|
/// <param name="timeout">The duration after which to cancel the async operation. Overrides default timeouts (<see cref="JSRuntime.DefaultAsyncTimeout"/>).</param>
|
||||||
|
/// <param name="args">JSON-serializable arguments.</param>
|
||||||
|
/// <returns>A <see cref="ValueTask"/> that represents the asynchronous invocation operation.</returns>
|
||||||
|
public static async ValueTask<TValue> InvokeAsync<TValue>(this IJSObjectReference jsObjectReference, string identifier, TimeSpan timeout, params object?[] args)
|
||||||
|
{
|
||||||
|
if (jsObjectReference is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(jsObjectReference));
|
||||||
|
}
|
||||||
|
|
||||||
|
using var cancellationTokenSource = timeout == Timeout.InfiniteTimeSpan ? null : new CancellationTokenSource(timeout);
|
||||||
|
var cancellationToken = cancellationTokenSource?.Token ?? CancellationToken.None;
|
||||||
|
|
||||||
|
return await jsObjectReference.InvokeAsync<TValue>(identifier, cancellationToken, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the specified JavaScript function asynchronously.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="jsObjectReference">The <see cref="IJSObjectReference"/>.</param>
|
||||||
|
/// <param name="identifier">An identifier for the function to invoke. For example, the value <c>"someScope.someFunction"</c> will invoke the function <c>someScope.someFunction</c> on the target instance.</param>
|
||||||
|
/// <param name="timeout">The duration after which to cancel the async operation. Overrides default timeouts (<see cref="JSRuntime.DefaultAsyncTimeout"/>).</param>
|
||||||
|
/// <param name="args">JSON-serializable arguments.</param>
|
||||||
|
/// <returns>A <see cref="ValueTask"/> that represents the asynchronous invocation operation.</returns>
|
||||||
|
public static async ValueTask InvokeVoidAsync(this IJSObjectReference jsObjectReference, string identifier, TimeSpan timeout, params object?[] args)
|
||||||
|
{
|
||||||
|
if (jsObjectReference is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(jsObjectReference));
|
||||||
|
}
|
||||||
|
|
||||||
|
using var cancellationTokenSource = timeout == Timeout.InfiniteTimeSpan ? null : new CancellationTokenSource(timeout);
|
||||||
|
var cancellationToken = cancellationTokenSource?.Token ?? CancellationToken.None;
|
||||||
|
|
||||||
|
await jsObjectReference.InvokeAsync<object>(identifier, cancellationToken, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -37,7 +37,7 @@ namespace Microsoft.JSInterop
|
||||||
Converters =
|
Converters =
|
||||||
{
|
{
|
||||||
new DotNetObjectReferenceJsonConverterFactory(this),
|
new DotNetObjectReferenceJsonConverterFactory(this),
|
||||||
new JSObjectReferenceJsonConverter<JSObjectReference>(id => new JSObjectReference(this, id)),
|
new JSObjectReferenceJsonConverter<IJSObjectReference, JSObjectReference>(id => new JSObjectReference(this, id)),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -52,17 +52,6 @@ namespace Microsoft.JSInterop
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected TimeSpan? DefaultAsyncTimeout { get; set; }
|
protected TimeSpan? DefaultAsyncTimeout { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a <see cref="JSCallResultType"/> from the given generic type.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TResult">
|
|
||||||
/// The type of the result of the relevant JS interop call.
|
|
||||||
/// </typeparam>
|
|
||||||
protected static JSCallResultType ResultTypeFromGeneric<TResult>()
|
|
||||||
=> typeof(TResult) == typeof(JSObjectReference) || typeof(TResult) == typeof(JSInProcessObjectReference) ?
|
|
||||||
JSCallResultType.JSObjectReference :
|
|
||||||
JSCallResultType.Default;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invokes the specified JavaScript function asynchronously.
|
/// Invokes the specified JavaScript function asynchronously.
|
||||||
/// <para>
|
/// <para>
|
||||||
|
|
@ -134,7 +123,7 @@ namespace Microsoft.JSInterop
|
||||||
var argsJson = args?.Any() == true ?
|
var argsJson = args?.Any() == true ?
|
||||||
JsonSerializer.Serialize(args, JsonSerializerOptions) :
|
JsonSerializer.Serialize(args, JsonSerializerOptions) :
|
||||||
null;
|
null;
|
||||||
var resultType = ResultTypeFromGeneric<TValue>();
|
var resultType = JSCallResultTypeHelper.FromGeneric<TValue>();
|
||||||
|
|
||||||
BeginInvokeJS(taskId, identifier, argsJson, resultType, targetInstanceId);
|
BeginInvokeJS(taskId, identifier, argsJson, resultType, targetInstanceId);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
|
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
|
||||||
|
|
@ -13,6 +13,10 @@
|
||||||
<Reference Include="System.Text.Json" />
|
<Reference Include="System.Text.Json" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="$(SharedSourceRoot)JSInterop\*.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<InternalsVisibleTo Include="Microsoft.JSInterop.Tests" />
|
<InternalsVisibleTo Include="Microsoft.JSInterop.Tests" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.JSInterop.Infrastructure
|
||||||
var json = "{}";
|
var json = "{}";
|
||||||
|
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
var ex = Assert.Throws<JsonException>(() => JsonSerializer.Deserialize<JSObjectReference>(json, JsonSerializerOptions));
|
var ex = Assert.Throws<JsonException>(() => JsonSerializer.Deserialize<IJSObjectReference>(json, JsonSerializerOptions));
|
||||||
Assert.Equal("Required property __jsObjectId not found.", ex.Message);
|
Assert.Equal("Required property __jsObjectId not found.", ex.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -29,7 +29,7 @@ namespace Microsoft.JSInterop.Infrastructure
|
||||||
var json = "{\"foo\":2}";
|
var json = "{\"foo\":2}";
|
||||||
|
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
var ex = Assert.Throws<JsonException>(() => JsonSerializer.Deserialize<JSObjectReference>(json, JsonSerializerOptions));
|
var ex = Assert.Throws<JsonException>(() => JsonSerializer.Deserialize<IJSObjectReference>(json, JsonSerializerOptions));
|
||||||
Assert.Equal("Unexcepted JSON property foo.", ex.Message);
|
Assert.Equal("Unexcepted JSON property foo.", ex.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,7 +40,7 @@ namespace Microsoft.JSInterop.Infrastructure
|
||||||
var json = $"{{\"__jsObjectId\":5";
|
var json = $"{{\"__jsObjectId\":5";
|
||||||
|
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
var ex = Record.Exception(() => JsonSerializer.Deserialize<JSObjectReference>(json, JsonSerializerOptions));
|
var ex = Record.Exception(() => JsonSerializer.Deserialize<IJSObjectReference>(json, JsonSerializerOptions));
|
||||||
Assert.IsAssignableFrom<JsonException>(ex);
|
Assert.IsAssignableFrom<JsonException>(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,7 +51,7 @@ namespace Microsoft.JSInterop.Infrastructure
|
||||||
var json = $"{{\"__jsObjectId\":3,\"__jsObjectId\":7}}";
|
var json = $"{{\"__jsObjectId\":3,\"__jsObjectId\":7}}";
|
||||||
|
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
var ex = Record.Exception(() => JsonSerializer.Deserialize<JSObjectReference>(json, JsonSerializerOptions));
|
var ex = Record.Exception(() => JsonSerializer.Deserialize<IJSObjectReference>(json, JsonSerializerOptions));
|
||||||
Assert.IsAssignableFrom<JsonException>(ex);
|
Assert.IsAssignableFrom<JsonException>(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,7 +63,7 @@ namespace Microsoft.JSInterop.Infrastructure
|
||||||
var json = $"{{\"__jsObjectId\":{expectedId}}}";
|
var json = $"{{\"__jsObjectId\":{expectedId}}}";
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var deserialized = JsonSerializer.Deserialize<JSObjectReference>(json, JsonSerializerOptions)!;
|
var deserialized = (JSObjectReference)JsonSerializer.Deserialize<IJSObjectReference>(json, JsonSerializerOptions)!;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedId, deserialized?.Id);
|
Assert.Equal(expectedId, deserialized?.Id);
|
||||||
|
|
@ -76,7 +76,7 @@ namespace Microsoft.JSInterop.Infrastructure
|
||||||
var jsObjectRef = new JSObjectReference(JSRuntime, 7);
|
var jsObjectRef = new JSObjectReference(JSRuntime, 7);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var json = JsonSerializer.Serialize(jsObjectRef, JsonSerializerOptions);
|
var json = JsonSerializer.Serialize((IJSObjectReference)jsObjectRef, JsonSerializerOptions);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal($"{{\"__jsObjectId\":{jsObjectRef.Id}}}", json);
|
Assert.Equal($"{{\"__jsObjectId\":{jsObjectRef.Id}}}", json);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
internal static class JSCallResultTypeHelper
|
||||||
|
{
|
||||||
|
public static JSCallResultType FromGeneric<TResult>()
|
||||||
|
=> typeof(TResult) == typeof(IJSObjectReference) || typeof(TResult) == typeof(IJSInProcessObjectReference) ?
|
||||||
|
JSCallResultType.JSObjectReference :
|
||||||
|
JSCallResultType.Default;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue