From d758ef83bf4abb505ea5e4b9b87febf89d1c78be Mon Sep 17 00:00:00 2001 From: Mackinnon Buck Date: Tue, 16 Apr 2024 16:28:18 -0700 Subject: [PATCH] Improvements --- .../Microsoft.AspNetCore.Components.csproj | 1 - .../src/PersistentComponentState.cs | 29 ------- .../Components/src/PublicAPI.Unshipped.txt | 1 - .../src/DefaultAntiforgeryStateProvider.cs | 16 ++-- .../JsonConverterFactoryTypeInfoResolver.cs | 45 +++++++++++ .../Shared/src/JsonSerializerOptionsCache.cs | 75 ------------------- ...Microsoft.AspNetCore.Components.Web.csproj | 1 + src/Components/Web/src/WebRenderer.cs | 9 ++- .../RazorComponents/App.razor | 5 ++ .../Components.WasmMinimal.csproj | 3 + .../Microsoft.JSInterop/src/IJSRuntime.cs | 21 ++++-- .../Microsoft.JSInterop/src/JSRuntime.cs | 32 ++++---- .../src/JSRuntimeExtensions.cs | 37 ++++----- .../src/Microsoft.JSInterop.csproj | 1 - .../src/PublicAPI.Unshipped.txt | 22 +++--- 15 files changed, 132 insertions(+), 166 deletions(-) create mode 100644 src/Components/Shared/src/JsonSerialization/JsonConverterFactoryTypeInfoResolver.cs delete mode 100644 src/Components/Shared/src/JsonSerializerOptionsCache.cs diff --git a/src/Components/Components/src/Microsoft.AspNetCore.Components.csproj b/src/Components/Components/src/Microsoft.AspNetCore.Components.csproj index ba20808b6a79..9ebdbfc3778f 100644 --- a/src/Components/Components/src/Microsoft.AspNetCore.Components.csproj +++ b/src/Components/Components/src/Microsoft.AspNetCore.Components.csproj @@ -16,7 +16,6 @@ - diff --git a/src/Components/Components/src/PersistentComponentState.cs b/src/Components/Components/src/PersistentComponentState.cs index ff6de37b09ec..bc193dd77e5f 100644 --- a/src/Components/Components/src/PersistentComponentState.cs +++ b/src/Components/Components/src/PersistentComponentState.cs @@ -3,7 +3,6 @@ using System.Diagnostics.CodeAnalysis; using System.Text.Json; -using System.Text.Json.Serialization.Metadata; using static Microsoft.AspNetCore.Internal.LinkerFlags; namespace Microsoft.AspNetCore.Components; @@ -17,7 +16,6 @@ public class PersistentComponentState private readonly IDictionary _currentState; private readonly List _registeredCallbacks; - private readonly JsonSerializerOptionsCache _jsonSerializerOptionsCache = new(JsonSerializerOptionsProvider.Options); internal PersistentComponentState( IDictionary currentState, @@ -116,33 +114,6 @@ public PersistingComponentStateSubscription RegisterOnPersisting(Func call } } - /// - /// Tries to retrieve the persisted state as JSON with the given and deserializes it into an - /// instance of type . - /// - /// The key used to persist the instance. - /// The to use when deserializing from JSON. - /// The persisted instance. - /// true if the state was found; false otherwise. - [RequiresUnreferencedCode("JSON serialization and deserialization might require types that cannot be statically analyzed.")] - public bool TryTakeFromJson(string key, IJsonTypeInfoResolver resolver, [MaybeNullWhen(false)] out TValue? instance) - { - ArgumentNullException.ThrowIfNull(key); - - if (TryTake(key, out var data)) - { - var reader = new Utf8JsonReader(data); - var options = _jsonSerializerOptionsCache.GetOrAdd(resolver); - instance = JsonSerializer.Deserialize(ref reader, options)!; - return true; - } - else - { - instance = default; - return false; - } - } - private bool TryTake(string key, out byte[]? value) { ArgumentNullException.ThrowIfNull(key); diff --git a/src/Components/Components/src/PublicAPI.Unshipped.txt b/src/Components/Components/src/PublicAPI.Unshipped.txt index e111812b4a50..7dc5c58110bf 100644 --- a/src/Components/Components/src/PublicAPI.Unshipped.txt +++ b/src/Components/Components/src/PublicAPI.Unshipped.txt @@ -1,2 +1 @@ #nullable enable -Microsoft.AspNetCore.Components.PersistentComponentState.TryTakeFromJson(string! key, System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver! resolver, out TValue? instance) -> bool diff --git a/src/Components/Shared/src/DefaultAntiforgeryStateProvider.cs b/src/Components/Shared/src/DefaultAntiforgeryStateProvider.cs index 9c12d3b42458..a40137fc0e57 100644 --- a/src/Components/Shared/src/DefaultAntiforgeryStateProvider.cs +++ b/src/Components/Shared/src/DefaultAntiforgeryStateProvider.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.CodeAnalysis; +using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.AspNetCore.Components.Web; @@ -25,14 +26,19 @@ public DefaultAntiforgeryStateProvider(PersistentComponentState state) // don't have access to the request. _subscription = state.RegisterOnPersisting(() => { - state.PersistAsJson(PersistenceKey, GetAntiforgeryToken()); + var bytes = JsonSerializer.SerializeToUtf8Bytes( + GetAntiforgeryToken(), + DefaultAntiforgeryStateProviderSerializerContext.Default.AntiforgeryRequestToken); + state.PersistAsJson(PersistenceKey, bytes); return Task.CompletedTask; }, RenderMode.InteractiveAuto); - state.TryTakeFromJson( - PersistenceKey, - DefaultAntiforgeryStateProviderSerializerContext.Default, - out _currentToken); + if (state.TryTakeFromJson(PersistenceKey, out var bytes)) + { + _currentToken = JsonSerializer.Deserialize( + bytes, + DefaultAntiforgeryStateProviderSerializerContext.Default.AntiforgeryRequestToken); + } } /// diff --git a/src/Components/Shared/src/JsonSerialization/JsonConverterFactoryTypeInfoResolver.cs b/src/Components/Shared/src/JsonSerialization/JsonConverterFactoryTypeInfoResolver.cs new file mode 100644 index 000000000000..32d9973a0fd8 --- /dev/null +++ b/src/Components/Shared/src/JsonSerialization/JsonConverterFactoryTypeInfoResolver.cs @@ -0,0 +1,45 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; + +namespace Microsoft.AspNetCore.Components; + +// For custom converters that don't rely on serializing an object graph, +// we can resolve the incoming type's JsonTypeInfo directly from the converter. +// This skips extra work to collect metadata for the type that won't be used. +internal sealed class JsonConverterFactoryTypeInfoResolver : IJsonTypeInfoResolver +{ + public static readonly JsonConverterFactoryTypeInfoResolver Instance = new(); + + private JsonConverterFactoryTypeInfoResolver() + { + } + + public JsonTypeInfo? GetTypeInfo(Type type, JsonSerializerOptions options) + { + if (type != typeof(T)) + { + return null; + } + + foreach (var converter in options.Converters) + { + if (converter is not JsonConverterFactory factory || !factory.CanConvert(type)) + { + continue; + } + + if (factory.CreateConverter(type, options) is not { } converterToUse) + { + continue; + } + + return JsonMetadataServices.CreateValueInfo(options, converterToUse); + } + + return null; + } +} diff --git a/src/Components/Shared/src/JsonSerializerOptionsCache.cs b/src/Components/Shared/src/JsonSerializerOptionsCache.cs deleted file mode 100644 index b3a8f6b3eddd..000000000000 --- a/src/Components/Shared/src/JsonSerializerOptionsCache.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Concurrent; -using System.Reflection.Metadata; -using System.Runtime.CompilerServices; -using System.Text.Json; -using System.Text.Json.Serialization.Metadata; - -[assembly: MetadataUpdateHandler(typeof(JsonSerializerOptionsCache.MetadataUpdateHandler))] - -internal sealed class JsonSerializerOptionsCache -{ - private readonly JsonSerializerOptions _baseOptions; - - // We expect JSON type info resolvers to be long-lived objects in most cases. This is because they'll - // typically be generated by the JSON source generator and referenced via generated static properties. - // Therefore, we shouldn't need to worry about type info resolvers not getting GC'd due to referencing - // them here. - private readonly ConcurrentDictionary _cachedSerializerOptions = []; - - public JsonSerializerOptionsCache(JsonSerializerOptions baseOptions) - { - _baseOptions = baseOptions; - - if (MetadataUpdater.IsSupported) - { - TrackInstance(this); - } - } - - public JsonSerializerOptions GetOrAdd( - IJsonTypeInfoResolver? resolver, - Func? valueFactory = null) - { - if (resolver is null) - { - return _baseOptions; - } - - return _cachedSerializerOptions.GetOrAdd(resolver, static (resolver, args) => - { - if (args.valueFactory is not null) - { - resolver = args.valueFactory(resolver); - } - - return new JsonSerializerOptions(args.cache._baseOptions) - { - TypeInfoResolver = resolver, - }; - }, (cache: this, valueFactory)); - } - - private static void TrackInstance(JsonSerializerOptionsCache instance) - => TrackedJsonSerializerOptionsCaches.All.Add(instance, null); - - internal static class TrackedJsonSerializerOptionsCaches - { - // Tracks all live JSRuntime instances. All instances add themselves to this table in their - // constructor when hot reload is enabled. - public static readonly ConditionalWeakTable All = []; - } - - internal static class MetadataUpdateHandler - { - public static void ClearCache(Type[]? _) - { - foreach (var (cache, _) in TrackedJsonSerializerOptionsCaches.All) - { - cache._cachedSerializerOptions.Clear(); - } - } - } -} diff --git a/src/Components/Web/src/Microsoft.AspNetCore.Components.Web.csproj b/src/Components/Web/src/Microsoft.AspNetCore.Components.Web.csproj index 2b337152af34..9362dc20a8dc 100644 --- a/src/Components/Web/src/Microsoft.AspNetCore.Components.Web.csproj +++ b/src/Components/Web/src/Microsoft.AspNetCore.Components.Web.csproj @@ -18,6 +18,7 @@ + diff --git a/src/Components/Web/src/WebRenderer.cs b/src/Components/Web/src/WebRenderer.cs index 52c162752825..463143d91d64 100644 --- a/src/Components/Web/src/WebRenderer.cs +++ b/src/Components/Web/src/WebRenderer.cs @@ -41,10 +41,15 @@ public WebRenderer( // Supply a DotNetObjectReference to JS that it can use to call us back for events etc. jsComponentInterop.AttachToRenderer(this); + var jsRuntime = serviceProvider.GetRequiredService(); + var jsRuntimeJsonSerializerOptions = jsRuntime.CloneJsonSerializerOptions(); + jsRuntimeJsonSerializerOptions.TypeInfoResolverChain.Insert(0, JsonConverterFactoryTypeInfoResolver>.Instance); + jsRuntimeJsonSerializerOptions.TypeInfoResolverChain.Insert(0, WebRendererSerializerContext.Default); + jsRuntime.InvokeVoidAsync( "Blazor._internal.attachWebRendererInterop", - WebRendererSerializerContext.Default, + jsRuntimeJsonSerializerOptions, _rendererId, _interopMethodsReference, jsComponentInterop.Configuration.JSComponentParametersByIdentifier, @@ -148,6 +153,8 @@ public void RemoveRootComponent(int componentId) } } +[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Serialization)] +[JsonSerializable(typeof(object[]))] [JsonSerializable(typeof(int))] [JsonSerializable(typeof(Dictionary))] [JsonSerializable(typeof(Dictionary>))] diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/App.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/App.razor index befd36e52a53..08b02cad20ee 100644 --- a/src/Components/test/testassets/Components.TestServer/RazorComponents/App.razor +++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/App.razor @@ -70,6 +70,11 @@ }); } }, + configureRuntime: (builder) => { + builder.withConfig({ + browserProfilerOptions: {}, + }); + }, }, }).then(() => { const startedParagraph = document.createElement('p'); diff --git a/src/Components/test/testassets/Components.WasmMinimal/Components.WasmMinimal.csproj b/src/Components/test/testassets/Components.WasmMinimal/Components.WasmMinimal.csproj index 3b5fd66e8188..188f62b80e6b 100644 --- a/src/Components/test/testassets/Components.WasmMinimal/Components.WasmMinimal.csproj +++ b/src/Components/test/testassets/Components.WasmMinimal/Components.WasmMinimal.csproj @@ -5,6 +5,9 @@ enable enable WasmMinimal + + browser; + true diff --git a/src/JSInterop/Microsoft.JSInterop/src/IJSRuntime.cs b/src/JSInterop/Microsoft.JSInterop/src/IJSRuntime.cs index 1484c983d79b..ed4f91a72296 100644 --- a/src/JSInterop/Microsoft.JSInterop/src/IJSRuntime.cs +++ b/src/JSInterop/Microsoft.JSInterop/src/IJSRuntime.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.CodeAnalysis; -using System.Text.Json.Serialization.Metadata; +using System.Text.Json; using static Microsoft.AspNetCore.Internal.LinkerFlags; namespace Microsoft.JSInterop; @@ -34,11 +34,11 @@ public interface IJSRuntime /// /// The JSON-serializable return type. /// An identifier for the function to invoke. For example, the value "someScope.someFunction" will invoke the function window.someScope.someFunction. - /// The to use for JSON serialization and deserialization. + /// The to use for JSON serialization and deserialization. /// JSON-serializable arguments. /// An instance of obtained by JSON-deserializing the return value. - ValueTask InvokeAsync<[DynamicallyAccessedMembers(JsonSerialized)] TValue>(string identifier, IJsonTypeInfoResolver resolver, object?[]? args) - => throw new InvalidOperationException($"Supplying a custom {nameof(IJsonTypeInfoResolver)} is not supported by the current JS runtime"); + ValueTask InvokeAsync<[DynamicallyAccessedMembers(JsonSerialized)] TValue>(string identifier, JsonSerializerOptions options, object?[]? args) + => throw new InvalidOperationException($"Supplying a custom {nameof(JsonSerializerOptions)} is not supported by the current JS runtime"); /// /// Invokes the specified JavaScript function asynchronously. @@ -58,13 +58,20 @@ public interface IJSRuntime /// /// The JSON-serializable return type. /// An identifier for the function to invoke. For example, the value "someScope.someFunction" will invoke the function window.someScope.someFunction. - /// The to use for JSON serialization and deserialization. + /// The to use for JSON serialization and deserialization. /// /// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts /// () from being applied. /// /// JSON-serializable arguments. /// An instance of obtained by JSON-deserializing the return value. - ValueTask InvokeAsync<[DynamicallyAccessedMembers(JsonSerialized)] TValue>(string identifier, IJsonTypeInfoResolver resolver, CancellationToken cancellationToken, object?[]? args) - => throw new InvalidOperationException($"Supplying a custom {nameof(IJsonTypeInfoResolver)} is not supported by the current JS runtime"); + ValueTask InvokeAsync<[DynamicallyAccessedMembers(JsonSerialized)] TValue>(string identifier, JsonSerializerOptions options, CancellationToken cancellationToken, object?[]? args) + => throw new InvalidOperationException($"Supplying a custom {nameof(JsonSerializerOptions)} is not supported by the current JS runtime"); + + /// + /// Returns a copy of the current used for JSON serialization and deserialization. + /// + /// A copy of the . + JsonSerializerOptions CloneJsonSerializerOptions() + => throw new InvalidOperationException($"The current JS runtime does not support cloning {nameof(JsonSerializerOptions)}"); } diff --git a/src/JSInterop/Microsoft.JSInterop/src/JSRuntime.cs b/src/JSInterop/Microsoft.JSInterop/src/JSRuntime.cs index eb3ac1359b26..28d2d78de61d 100644 --- a/src/JSInterop/Microsoft.JSInterop/src/JSRuntime.cs +++ b/src/JSInterop/Microsoft.JSInterop/src/JSRuntime.cs @@ -22,7 +22,6 @@ public abstract partial class JSRuntime : IJSRuntime, IDisposable private long _nextPendingTaskId = 1; // Start at 1 because zero signals "no response needed" private readonly ConcurrentDictionary _pendingTasks = new(); private readonly ConcurrentDictionary _trackedRefsById = new(); - private readonly JsonSerializerOptionsCache _jsonSerializerOptionsCache; internal readonly ArrayBuilder ByteArraysToBeRevived = new(); @@ -45,8 +44,6 @@ protected JSRuntime() new ByteArrayJsonConverter(this), }, }; - - _jsonSerializerOptionsCache = new(JsonSerializerOptions); } /// @@ -59,42 +56,45 @@ protected JSRuntime() /// protected TimeSpan? DefaultAsyncTimeout { get; set; } + /// + public JsonSerializerOptions CloneJsonSerializerOptions() => new(JsonSerializerOptions); + /// public ValueTask InvokeAsync<[DynamicallyAccessedMembers(JsonSerialized)] TValue>(string identifier, object?[]? args) => InvokeAsync(0, identifier, args); /// - public ValueTask InvokeAsync<[DynamicallyAccessedMembers(JsonSerialized)] TValue>(string identifier, IJsonTypeInfoResolver resolver, object?[]? args) - => InvokeAsync(0, identifier, resolver, args); + public ValueTask InvokeAsync<[DynamicallyAccessedMembers(JsonSerialized)] TValue>(string identifier, JsonSerializerOptions options, object?[]? args) + => InvokeAsync(0, identifier, options, args); /// public ValueTask InvokeAsync<[DynamicallyAccessedMembers(JsonSerialized)] TValue>(string identifier, CancellationToken cancellationToken, object?[]? args) => InvokeAsync(0, identifier, cancellationToken, args); /// - public ValueTask InvokeAsync<[DynamicallyAccessedMembers(JsonSerialized)] TValue>(string identifier, IJsonTypeInfoResolver resolver, CancellationToken cancellationToken, object?[]? args) - => InvokeAsync(0, identifier, resolver, cancellationToken, args); + public ValueTask InvokeAsync<[DynamicallyAccessedMembers(JsonSerialized)] TValue>(string identifier, JsonSerializerOptions options, CancellationToken cancellationToken, object?[]? args) + => InvokeAsync(0, identifier, options, cancellationToken, args); - internal async ValueTask InvokeAsync<[DynamicallyAccessedMembers(JsonSerialized)] TValue>(long targetInstanceId, string identifier, IJsonTypeInfoResolver? resolver, object?[]? args) + internal async ValueTask InvokeAsync<[DynamicallyAccessedMembers(JsonSerialized)] TValue>(long targetInstanceId, string identifier, JsonSerializerOptions? options, object?[]? args) { if (DefaultAsyncTimeout.HasValue) { using var cts = new CancellationTokenSource(DefaultAsyncTimeout.Value); // We need to await here due to the using - return await InvokeAsync(targetInstanceId, identifier, resolver, cts.Token, args); + return await InvokeAsync(targetInstanceId, identifier, options, cts.Token, args); } - return await InvokeAsync(targetInstanceId, identifier, resolver, CancellationToken.None, args); + return await InvokeAsync(targetInstanceId, identifier, options, CancellationToken.None, args); } internal ValueTask InvokeAsync<[DynamicallyAccessedMembers(JsonSerialized)] TValue>(long targetInstanceId, string identifier, object?[]? args) - => InvokeAsync(targetInstanceId, identifier, resolver: null, args); + => InvokeAsync(targetInstanceId, identifier, options: null, args); [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "We expect application code is configured to ensure JS interop arguments are linker friendly.")] internal ValueTask InvokeAsync<[DynamicallyAccessedMembers(JsonSerialized)] TValue>( long targetInstanceId, string identifier, - IJsonTypeInfoResolver? resolver, + JsonSerializerOptions? jsonSerializerOptions, CancellationToken cancellationToken, object?[]? args) { @@ -114,11 +114,7 @@ protected JSRuntime() try { var resultType = JSCallResultTypeHelper.FromGeneric(); - var jsonSerializerOptions = _jsonSerializerOptionsCache.GetOrAdd(resolver, static resolver => - JsonTypeInfoResolver.Combine( - resolver, - JSRuntimeSerializerContext.Default, - FallbackTypeInfoResolver.Instance)); + jsonSerializerOptions ??= JsonSerializerOptions; var argsJson = args switch { @@ -145,7 +141,7 @@ protected JSRuntime() string identifier, CancellationToken cancellationToken, object?[]? args) - => InvokeAsync(targetInstanceId, identifier, resolver: null, cancellationToken, args); + => InvokeAsync(targetInstanceId, identifier, jsonSerializerOptions: null, cancellationToken, args); /// /// Begins an asynchronous function invocation. diff --git a/src/JSInterop/Microsoft.JSInterop/src/JSRuntimeExtensions.cs b/src/JSInterop/Microsoft.JSInterop/src/JSRuntimeExtensions.cs index 71b7d2f7ea52..315bb8118277 100644 --- a/src/JSInterop/Microsoft.JSInterop/src/JSRuntimeExtensions.cs +++ b/src/JSInterop/Microsoft.JSInterop/src/JSRuntimeExtensions.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.CodeAnalysis; +using System.Text.Json; using System.Text.Json.Serialization.Metadata; using Microsoft.JSInterop.Infrastructure; using static Microsoft.AspNetCore.Internal.LinkerFlags; @@ -32,14 +33,14 @@ public static async ValueTask InvokeVoidAsync(this IJSRuntime jsRuntime, string /// /// The . /// An identifier for the function to invoke. For example, the value "someScope.someFunction" will invoke the function window.someScope.someFunction. - /// The to use for JSON serialization. + /// The to use for JSON serialization. /// JSON-serializable arguments. /// A that represents the asynchronous invocation operation. - public static async ValueTask InvokeVoidAsync(this IJSRuntime jsRuntime, string identifier, IJsonTypeInfoResolver resolver, params object?[]? args) + public static async ValueTask InvokeVoidAsync(this IJSRuntime jsRuntime, string identifier, JsonSerializerOptions options, params object?[]? args) { ArgumentNullException.ThrowIfNull(jsRuntime); - await jsRuntime.InvokeAsync(identifier, resolver, args); + await jsRuntime.InvokeAsync(identifier, options, args); } /// @@ -65,18 +66,18 @@ public static async ValueTask InvokeVoidAsync(this IJSRuntime jsRuntime, string /// /// The . /// An identifier for the function to invoke. For example, the value "someScope.someFunction" will invoke the function window.someScope.someFunction. - /// The to use for JSON serialization. + /// The to use for JSON serialization. /// /// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts /// () from being applied. /// /// JSON-serializable arguments. /// A that represents the asynchronous invocation operation. - public static async ValueTask InvokeVoidAsync(this IJSRuntime jsRuntime, string identifier, IJsonTypeInfoResolver resolver, CancellationToken cancellationToken, params object?[]? args) + public static async ValueTask InvokeVoidAsync(this IJSRuntime jsRuntime, string identifier, JsonSerializerOptions options, CancellationToken cancellationToken, params object?[]? args) { ArgumentNullException.ThrowIfNull(jsRuntime); - await jsRuntime.InvokeAsync(identifier, resolver, cancellationToken, args); + await jsRuntime.InvokeAsync(identifier, options, cancellationToken, args); } /// @@ -102,18 +103,18 @@ public static async ValueTask InvokeVoidAsync(this IJSRuntime jsRuntime, string /// /// The . /// An identifier for the function to invoke. For example, the value "someScope.someFunction" will invoke the function window.someScope.someFunction. - /// The to use for JSON serialization. + /// The to use for JSON serialization. /// The duration after which to cancel the async operation. Overrides default timeouts (). /// JSON-serializable arguments. /// A that represents the asynchronous invocation operation. - public static async ValueTask InvokeVoidAsync(this IJSRuntime jsRuntime, string identifier, IJsonTypeInfoResolver resolver, TimeSpan timeout, params object?[]? args) + public static async ValueTask InvokeVoidAsync(this IJSRuntime jsRuntime, string identifier, JsonSerializerOptions options, TimeSpan timeout, params object?[]? args) { ArgumentNullException.ThrowIfNull(jsRuntime); using var cancellationTokenSource = timeout == Timeout.InfiniteTimeSpan ? null : new CancellationTokenSource(timeout); var cancellationToken = cancellationTokenSource?.Token ?? CancellationToken.None; - await jsRuntime.InvokeAsync(identifier, resolver, cancellationToken, args); + await jsRuntime.InvokeAsync(identifier, options, cancellationToken, args); } /// @@ -145,14 +146,14 @@ public static async ValueTask InvokeVoidAsync(this IJSRuntime jsRuntime, string /// The . /// The JSON-serializable return type. /// An identifier for the function to invoke. For example, the value "someScope.someFunction" will invoke the function window.someScope.someFunction. - /// The to use for JSON serialization and deserialization. + /// The to use for JSON serialization and deserialization. /// JSON-serializable arguments. /// An instance of obtained by JSON-deserializing the return value. - public static ValueTask InvokeAsync<[DynamicallyAccessedMembers(JsonSerialized)] TValue>(this IJSRuntime jsRuntime, string identifier, IJsonTypeInfoResolver resolver, params object?[]? args) + public static ValueTask InvokeAsync<[DynamicallyAccessedMembers(JsonSerialized)] TValue>(this IJSRuntime jsRuntime, string identifier, JsonSerializerOptions options, params object?[]? args) { ArgumentNullException.ThrowIfNull(jsRuntime); - return jsRuntime.InvokeAsync(identifier, resolver, args); + return jsRuntime.InvokeAsync(identifier, options, args); } /// @@ -180,18 +181,18 @@ public static async ValueTask InvokeVoidAsync(this IJSRuntime jsRuntime, string /// The JSON-serializable return type. /// The . /// An identifier for the function to invoke. For example, the value "someScope.someFunction" will invoke the function window.someScope.someFunction. - /// The to use for JSON serialization and deserialization. + /// The to use for JSON serialization and deserialization. /// /// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts /// () from being applied. /// /// JSON-serializable arguments. /// An instance of obtained by JSON-deserializing the return value. - public static ValueTask InvokeAsync<[DynamicallyAccessedMembers(JsonSerialized)] TValue>(this IJSRuntime jsRuntime, string identifier, IJsonTypeInfoResolver resolver, CancellationToken cancellationToken, params object?[]? args) + public static ValueTask InvokeAsync<[DynamicallyAccessedMembers(JsonSerialized)] TValue>(this IJSRuntime jsRuntime, string identifier, JsonSerializerOptions options, CancellationToken cancellationToken, params object?[]? args) { ArgumentNullException.ThrowIfNull(jsRuntime); - return jsRuntime.InvokeAsync(identifier, resolver, cancellationToken, args); + return jsRuntime.InvokeAsync(identifier, options, cancellationToken, args); } /// @@ -217,17 +218,17 @@ public static async ValueTask InvokeVoidAsync(this IJSRuntime jsRuntime, string /// /// The . /// An identifier for the function to invoke. For example, the value "someScope.someFunction" will invoke the function window.someScope.someFunction. - /// The to use for JSON serialization and deserialization. + /// The to use for JSON serialization and deserialization. /// The duration after which to cancel the async operation. Overrides default timeouts (). /// JSON-serializable arguments. /// A that represents the asynchronous invocation operation. - public static async ValueTask InvokeAsync<[DynamicallyAccessedMembers(JsonSerialized)] TValue>(this IJSRuntime jsRuntime, string identifier, IJsonTypeInfoResolver resolver, TimeSpan timeout, params object?[]? args) + public static async ValueTask InvokeAsync<[DynamicallyAccessedMembers(JsonSerialized)] TValue>(this IJSRuntime jsRuntime, string identifier, JsonSerializerOptions options, TimeSpan timeout, params object?[]? args) { ArgumentNullException.ThrowIfNull(jsRuntime); using var cancellationTokenSource = timeout == Timeout.InfiniteTimeSpan ? null : new CancellationTokenSource(timeout); var cancellationToken = cancellationTokenSource?.Token ?? CancellationToken.None; - return await jsRuntime.InvokeAsync(identifier, resolver, cancellationToken, args); + return await jsRuntime.InvokeAsync(identifier, options, cancellationToken, args); } } diff --git a/src/JSInterop/Microsoft.JSInterop/src/Microsoft.JSInterop.csproj b/src/JSInterop/Microsoft.JSInterop/src/Microsoft.JSInterop.csproj index 8092928fcb03..baebaf34e3c8 100644 --- a/src/JSInterop/Microsoft.JSInterop/src/Microsoft.JSInterop.csproj +++ b/src/JSInterop/Microsoft.JSInterop/src/Microsoft.JSInterop.csproj @@ -18,7 +18,6 @@ - diff --git a/src/JSInterop/Microsoft.JSInterop/src/PublicAPI.Unshipped.txt b/src/JSInterop/Microsoft.JSInterop/src/PublicAPI.Unshipped.txt index 1a79f6cd0b27..152241b61ae5 100644 --- a/src/JSInterop/Microsoft.JSInterop/src/PublicAPI.Unshipped.txt +++ b/src/JSInterop/Microsoft.JSInterop/src/PublicAPI.Unshipped.txt @@ -9,13 +9,15 @@ *REMOVED*Microsoft.JSInterop.IJSUnmarshalledRuntime.InvokeUnmarshalled(string! identifier, T0 arg0, T1 arg1) -> TResult *REMOVED*Microsoft.JSInterop.IJSUnmarshalledRuntime.InvokeUnmarshalled(string! identifier, T0 arg0) -> TResult *REMOVED*Microsoft.JSInterop.IJSUnmarshalledRuntime.InvokeUnmarshalled(string! identifier) -> TResult -Microsoft.JSInterop.IJSRuntime.InvokeAsync(string! identifier, System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver! resolver, object?[]? args) -> System.Threading.Tasks.ValueTask -Microsoft.JSInterop.IJSRuntime.InvokeAsync(string! identifier, System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver! resolver, System.Threading.CancellationToken cancellationToken, object?[]? args) -> System.Threading.Tasks.ValueTask -Microsoft.JSInterop.JSRuntime.InvokeAsync(string! identifier, System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver! resolver, object?[]? args) -> System.Threading.Tasks.ValueTask -Microsoft.JSInterop.JSRuntime.InvokeAsync(string! identifier, System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver! resolver, System.Threading.CancellationToken cancellationToken, object?[]? args) -> System.Threading.Tasks.ValueTask -static Microsoft.JSInterop.JSRuntimeExtensions.InvokeAsync(this Microsoft.JSInterop.IJSRuntime! jsRuntime, string! identifier, System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver! resolver, params object?[]? args) -> System.Threading.Tasks.ValueTask -static Microsoft.JSInterop.JSRuntimeExtensions.InvokeAsync(this Microsoft.JSInterop.IJSRuntime! jsRuntime, string! identifier, System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver! resolver, System.Threading.CancellationToken cancellationToken, params object?[]? args) -> System.Threading.Tasks.ValueTask -static Microsoft.JSInterop.JSRuntimeExtensions.InvokeAsync(this Microsoft.JSInterop.IJSRuntime! jsRuntime, string! identifier, System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver! resolver, System.TimeSpan timeout, params object?[]? args) -> System.Threading.Tasks.ValueTask -static Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync(this Microsoft.JSInterop.IJSRuntime! jsRuntime, string! identifier, System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver! resolver, params object?[]? args) -> System.Threading.Tasks.ValueTask -static Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync(this Microsoft.JSInterop.IJSRuntime! jsRuntime, string! identifier, System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver! resolver, System.Threading.CancellationToken cancellationToken, params object?[]? args) -> System.Threading.Tasks.ValueTask -static Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync(this Microsoft.JSInterop.IJSRuntime! jsRuntime, string! identifier, System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver! resolver, System.TimeSpan timeout, params object?[]? args) -> System.Threading.Tasks.ValueTask \ No newline at end of file +Microsoft.JSInterop.IJSRuntime.CloneJsonSerializerOptions() -> System.Text.Json.JsonSerializerOptions! +Microsoft.JSInterop.IJSRuntime.InvokeAsync(string! identifier, System.Text.Json.JsonSerializerOptions! options, object?[]? args) -> System.Threading.Tasks.ValueTask +Microsoft.JSInterop.IJSRuntime.InvokeAsync(string! identifier, System.Text.Json.JsonSerializerOptions! options, System.Threading.CancellationToken cancellationToken, object?[]? args) -> System.Threading.Tasks.ValueTask +Microsoft.JSInterop.JSRuntime.CloneJsonSerializerOptions() -> System.Text.Json.JsonSerializerOptions! +Microsoft.JSInterop.JSRuntime.InvokeAsync(string! identifier, System.Text.Json.JsonSerializerOptions! options, object?[]? args) -> System.Threading.Tasks.ValueTask +Microsoft.JSInterop.JSRuntime.InvokeAsync(string! identifier, System.Text.Json.JsonSerializerOptions! options, System.Threading.CancellationToken cancellationToken, object?[]? args) -> System.Threading.Tasks.ValueTask +static Microsoft.JSInterop.JSRuntimeExtensions.InvokeAsync(this Microsoft.JSInterop.IJSRuntime! jsRuntime, string! identifier, System.Text.Json.JsonSerializerOptions! options, params object?[]? args) -> System.Threading.Tasks.ValueTask +static Microsoft.JSInterop.JSRuntimeExtensions.InvokeAsync(this Microsoft.JSInterop.IJSRuntime! jsRuntime, string! identifier, System.Text.Json.JsonSerializerOptions! options, System.Threading.CancellationToken cancellationToken, params object?[]? args) -> System.Threading.Tasks.ValueTask +static Microsoft.JSInterop.JSRuntimeExtensions.InvokeAsync(this Microsoft.JSInterop.IJSRuntime! jsRuntime, string! identifier, System.Text.Json.JsonSerializerOptions! options, System.TimeSpan timeout, params object?[]? args) -> System.Threading.Tasks.ValueTask +static Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync(this Microsoft.JSInterop.IJSRuntime! jsRuntime, string! identifier, System.Text.Json.JsonSerializerOptions! options, params object?[]? args) -> System.Threading.Tasks.ValueTask +static Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync(this Microsoft.JSInterop.IJSRuntime! jsRuntime, string! identifier, System.Text.Json.JsonSerializerOptions! options, System.Threading.CancellationToken cancellationToken, params object?[]? args) -> System.Threading.Tasks.ValueTask +static Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync(this Microsoft.JSInterop.IJSRuntime! jsRuntime, string! identifier, System.Text.Json.JsonSerializerOptions! options, System.TimeSpan timeout, params object?[]? args) -> System.Threading.Tasks.ValueTask \ No newline at end of file