Add nullable to JSInterop (#22326)

This commit is contained in:
Pranav K 2020-06-09 22:39:01 -07:00 committed by GitHub
parent e1fab3098b
commit c58ab9247c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 88 additions and 86 deletions

View File

@ -3,6 +3,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks> <TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks> <TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<Nullable>annotations</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'"> <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<Compile Include="Microsoft.JSInterop.netstandard2.0.cs" /> <Compile Include="Microsoft.JSInterop.netstandard2.0.cs" />

View File

@ -30,7 +30,8 @@ namespace Microsoft.JSInterop
public abstract partial class JSInProcessRuntime : Microsoft.JSInterop.JSRuntime, Microsoft.JSInterop.IJSInProcessRuntime, Microsoft.JSInterop.IJSRuntime public abstract partial class JSInProcessRuntime : Microsoft.JSInterop.JSRuntime, Microsoft.JSInterop.IJSInProcessRuntime, Microsoft.JSInterop.IJSRuntime
{ {
protected JSInProcessRuntime() { } protected JSInProcessRuntime() { }
protected abstract string InvokeJS(string identifier, string argsJson); protected abstract string? InvokeJS(string identifier, string? argsJson);
[return: System.Diagnostics.CodeAnalysis.MaybeNullAttribute]
public TValue Invoke<TValue>(string identifier, params object[] args) { throw null; } public TValue Invoke<TValue>(string identifier, params object[] args) { throw null; }
} }
public static partial class JSInProcessRuntimeExtensions public static partial class JSInProcessRuntimeExtensions
@ -42,15 +43,16 @@ namespace Microsoft.JSInterop
{ {
public JSInvokableAttribute() { } public JSInvokableAttribute() { }
public JSInvokableAttribute(string identifier) { } public JSInvokableAttribute(string identifier) { }
public string Identifier { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } public string? Identifier { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
} }
public abstract partial class JSRuntime : Microsoft.JSInterop.IJSRuntime public abstract partial class JSRuntime : Microsoft.JSInterop.IJSRuntime
{ {
protected JSRuntime() { } protected JSRuntime() { }
protected System.TimeSpan? DefaultAsyncTimeout { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } protected System.TimeSpan? DefaultAsyncTimeout { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
protected internal System.Text.Json.JsonSerializerOptions JsonSerializerOptions { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } protected internal System.Text.Json.JsonSerializerOptions JsonSerializerOptions { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
protected abstract void BeginInvokeJS(long taskId, string identifier, string argsJson); protected abstract void BeginInvokeJS(long taskId, string identifier, string? argsJson);
protected internal abstract void EndInvokeDotNet(Microsoft.JSInterop.Infrastructure.DotNetInvocationInfo invocationInfo, in Microsoft.JSInterop.Infrastructure.DotNetInvocationResult invocationResult); protected internal abstract void EndInvokeDotNet(Microsoft.JSInterop.Infrastructure.DotNetInvocationInfo invocationInfo, in Microsoft.JSInterop.Infrastructure.DotNetInvocationResult invocationResult);
[System.Diagnostics.DebuggerStepThroughAttribute]
public System.Threading.Tasks.ValueTask<TValue> InvokeAsync<TValue>(string identifier, object[] args) { throw null; } public System.Threading.Tasks.ValueTask<TValue> InvokeAsync<TValue>(string identifier, object[] args) { throw null; }
public System.Threading.Tasks.ValueTask<TValue> InvokeAsync<TValue>(string identifier, System.Threading.CancellationToken cancellationToken, object[] args) { throw null; } public System.Threading.Tasks.ValueTask<TValue> InvokeAsync<TValue>(string identifier, System.Threading.CancellationToken cancellationToken, object[] args) { throw null; }
} }
@ -74,7 +76,7 @@ namespace Microsoft.JSInterop.Infrastructure
{ {
public static void BeginInvokeDotNet(Microsoft.JSInterop.JSRuntime jsRuntime, Microsoft.JSInterop.Infrastructure.DotNetInvocationInfo invocationInfo, string argsJson) { } public static void BeginInvokeDotNet(Microsoft.JSInterop.JSRuntime jsRuntime, Microsoft.JSInterop.Infrastructure.DotNetInvocationInfo invocationInfo, string argsJson) { }
public static void EndInvokeJS(Microsoft.JSInterop.JSRuntime jsRuntime, string arguments) { } public static void EndInvokeJS(Microsoft.JSInterop.JSRuntime jsRuntime, string arguments) { }
public static string Invoke(Microsoft.JSInterop.JSRuntime jsRuntime, in Microsoft.JSInterop.Infrastructure.DotNetInvocationInfo invocationInfo, string argsJson) { throw null; } public static string? Invoke(Microsoft.JSInterop.JSRuntime jsRuntime, in Microsoft.JSInterop.Infrastructure.DotNetInvocationInfo invocationInfo, string argsJson) { throw null; }
} }
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public readonly partial struct DotNetInvocationInfo public readonly partial struct DotNetInvocationInfo
@ -92,11 +94,11 @@ namespace Microsoft.JSInterop.Infrastructure
{ {
private readonly object _dummy; private readonly object _dummy;
private readonly int _dummyPrimitive; private readonly int _dummyPrimitive;
public DotNetInvocationResult(System.Exception exception, string errorKind) { throw null; } public DotNetInvocationResult(System.Exception exception, string? errorKind) { throw null; }
public DotNetInvocationResult(object result) { throw null; } public DotNetInvocationResult(object? result) { throw null; }
public string ErrorKind { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } public string? ErrorKind { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
public System.Exception Exception { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } public System.Exception? Exception { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
public object Result { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } public object? Result { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
public bool Success { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } public bool Success { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
} }
} }

View File

@ -30,7 +30,7 @@ namespace Microsoft.JSInterop
public abstract partial class JSInProcessRuntime : Microsoft.JSInterop.JSRuntime, Microsoft.JSInterop.IJSInProcessRuntime, Microsoft.JSInterop.IJSRuntime public abstract partial class JSInProcessRuntime : Microsoft.JSInterop.JSRuntime, Microsoft.JSInterop.IJSInProcessRuntime, Microsoft.JSInterop.IJSRuntime
{ {
protected JSInProcessRuntime() { } protected JSInProcessRuntime() { }
protected abstract string InvokeJS(string identifier, string argsJson); protected abstract string? InvokeJS(string identifier, string? argsJson);
public TValue Invoke<TValue>(string identifier, params object[] args) { throw null; } public TValue Invoke<TValue>(string identifier, params object[] args) { throw null; }
} }
public static partial class JSInProcessRuntimeExtensions public static partial class JSInProcessRuntimeExtensions
@ -42,15 +42,16 @@ namespace Microsoft.JSInterop
{ {
public JSInvokableAttribute() { } public JSInvokableAttribute() { }
public JSInvokableAttribute(string identifier) { } public JSInvokableAttribute(string identifier) { }
public string Identifier { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } public string? Identifier { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
} }
public abstract partial class JSRuntime : Microsoft.JSInterop.IJSRuntime public abstract partial class JSRuntime : Microsoft.JSInterop.IJSRuntime
{ {
protected JSRuntime() { } protected JSRuntime() { }
protected System.TimeSpan? DefaultAsyncTimeout { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } protected System.TimeSpan? DefaultAsyncTimeout { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
protected internal System.Text.Json.JsonSerializerOptions JsonSerializerOptions { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } protected internal System.Text.Json.JsonSerializerOptions JsonSerializerOptions { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
protected abstract void BeginInvokeJS(long taskId, string identifier, string argsJson); protected abstract void BeginInvokeJS(long taskId, string identifier, string? argsJson);
protected internal abstract void EndInvokeDotNet(Microsoft.JSInterop.Infrastructure.DotNetInvocationInfo invocationInfo, in Microsoft.JSInterop.Infrastructure.DotNetInvocationResult invocationResult); protected internal abstract void EndInvokeDotNet(Microsoft.JSInterop.Infrastructure.DotNetInvocationInfo invocationInfo, in Microsoft.JSInterop.Infrastructure.DotNetInvocationResult invocationResult);
[System.Diagnostics.DebuggerStepThroughAttribute]
public System.Threading.Tasks.ValueTask<TValue> InvokeAsync<TValue>(string identifier, object[] args) { throw null; } public System.Threading.Tasks.ValueTask<TValue> InvokeAsync<TValue>(string identifier, object[] args) { throw null; }
public System.Threading.Tasks.ValueTask<TValue> InvokeAsync<TValue>(string identifier, System.Threading.CancellationToken cancellationToken, object[] args) { throw null; } public System.Threading.Tasks.ValueTask<TValue> InvokeAsync<TValue>(string identifier, System.Threading.CancellationToken cancellationToken, object[] args) { throw null; }
} }
@ -74,7 +75,7 @@ namespace Microsoft.JSInterop.Infrastructure
{ {
public static void BeginInvokeDotNet(Microsoft.JSInterop.JSRuntime jsRuntime, Microsoft.JSInterop.Infrastructure.DotNetInvocationInfo invocationInfo, string argsJson) { } public static void BeginInvokeDotNet(Microsoft.JSInterop.JSRuntime jsRuntime, Microsoft.JSInterop.Infrastructure.DotNetInvocationInfo invocationInfo, string argsJson) { }
public static void EndInvokeJS(Microsoft.JSInterop.JSRuntime jsRuntime, string arguments) { } public static void EndInvokeJS(Microsoft.JSInterop.JSRuntime jsRuntime, string arguments) { }
public static string Invoke(Microsoft.JSInterop.JSRuntime jsRuntime, in Microsoft.JSInterop.Infrastructure.DotNetInvocationInfo invocationInfo, string argsJson) { throw null; } public static string? Invoke(Microsoft.JSInterop.JSRuntime jsRuntime, in Microsoft.JSInterop.Infrastructure.DotNetInvocationInfo invocationInfo, string argsJson) { throw null; }
} }
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public readonly partial struct DotNetInvocationInfo public readonly partial struct DotNetInvocationInfo
@ -92,11 +93,11 @@ namespace Microsoft.JSInterop.Infrastructure
{ {
private readonly object _dummy; private readonly object _dummy;
private readonly int _dummyPrimitive; private readonly int _dummyPrimitive;
public DotNetInvocationResult(System.Exception exception, string errorKind) { throw null; } public DotNetInvocationResult(System.Exception exception, string? errorKind) { throw null; }
public DotNetInvocationResult(object result) { throw null; } public DotNetInvocationResult(object? result) { throw null; }
public string ErrorKind { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } public string? ErrorKind { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
public System.Exception Exception { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } public System.Exception? Exception { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
public object Result { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } public object? Result { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
public bool Success { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } public bool Success { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
} }
} }

View File

@ -18,7 +18,7 @@ namespace Microsoft.JSInterop
{ {
private readonly TValue _value; private readonly TValue _value;
private long _objectId; private long _objectId;
private JSRuntime _jsRuntime; private JSRuntime? _jsRuntime;
/// <summary> /// <summary>
/// Initializes a new instance of <see cref="DotNetObjectReference{TValue}" />. /// Initializes a new instance of <see cref="DotNetObjectReference{TValue}" />.
@ -57,7 +57,7 @@ namespace Microsoft.JSInterop
} }
} }
internal JSRuntime JSRuntime internal JSRuntime? JSRuntime
{ {
get get
{ {

View File

@ -34,14 +34,14 @@ namespace Microsoft.JSInterop.Infrastructure
/// <param name="invocationInfo">The <see cref="DotNetInvocationInfo"/>.</param> /// <param name="invocationInfo">The <see cref="DotNetInvocationInfo"/>.</param>
/// <param name="argsJson">A JSON representation of the parameters.</param> /// <param name="argsJson">A JSON representation of the parameters.</param>
/// <returns>A JSON representation of the return value, or null.</returns> /// <returns>A JSON representation of the return value, or null.</returns>
public static string Invoke(JSRuntime jsRuntime, in DotNetInvocationInfo invocationInfo, string argsJson) public static string? Invoke(JSRuntime jsRuntime, in DotNetInvocationInfo invocationInfo, string argsJson)
{ {
// This method doesn't need [JSInvokable] because the platform is responsible for having // This method doesn't need [JSInvokable] because the platform is responsible for having
// some way to dispatch calls here. The logic inside here is the thing that checks whether // some way to dispatch calls here. The logic inside here is the thing that checks whether
// the targeted method has [JSInvokable]. It is not itself subject to that restriction, // the targeted method has [JSInvokable]. It is not itself subject to that restriction,
// because there would be nobody to police that. This method *is* the police. // because there would be nobody to police that. This method *is* the police.
IDotNetObjectReference targetInstance = default; IDotNetObjectReference? targetInstance = default;
if (invocationInfo.DotNetObjectId != default) if (invocationInfo.DotNetObjectId != default)
{ {
targetInstance = jsRuntime.GetObjectReference(invocationInfo.DotNetObjectId); targetInstance = jsRuntime.GetObjectReference(invocationInfo.DotNetObjectId);
@ -75,9 +75,9 @@ namespace Microsoft.JSInterop.Infrastructure
var callId = invocationInfo.CallId; var callId = invocationInfo.CallId;
object syncResult = null; object? syncResult = null;
ExceptionDispatchInfo syncException = null; ExceptionDispatchInfo? syncException = null;
IDotNetObjectReference targetInstance = null; IDotNetObjectReference? targetInstance = null;
try try
{ {
if (invocationInfo.DotNetObjectId != default) if (invocationInfo.DotNetObjectId != default)
@ -126,7 +126,7 @@ namespace Microsoft.JSInterop.Infrastructure
} }
} }
private static object InvokeSynchronously(JSRuntime jsRuntime, in DotNetInvocationInfo callInfo, IDotNetObjectReference objectReference, string argsJson) private static object? InvokeSynchronously(JSRuntime jsRuntime, in DotNetInvocationInfo callInfo, IDotNetObjectReference? objectReference, string argsJson)
{ {
var assemblyName = callInfo.AssemblyName; var assemblyName = callInfo.AssemblyName;
var methodIdentifier = callInfo.MethodIdentifier; var methodIdentifier = callInfo.MethodIdentifier;
@ -168,14 +168,14 @@ namespace Microsoft.JSInterop.Infrastructure
if (tie.InnerException != null) if (tie.InnerException != null)
{ {
ExceptionDispatchInfo.Capture(tie.InnerException).Throw(); ExceptionDispatchInfo.Capture(tie.InnerException).Throw();
throw null; // unreached throw tie.InnerException; // Unreachable
} }
throw; throw;
} }
} }
internal static object[] ParseArguments(JSRuntime jsRuntime, string methodIdentifier, string arguments, Type[] parameterTypes) internal static object?[] ParseArguments(JSRuntime jsRuntime, string methodIdentifier, string arguments, Type[] parameterTypes)
{ {
if (parameterTypes.Length == 0) if (parameterTypes.Length == 0)
{ {
@ -189,7 +189,7 @@ namespace Microsoft.JSInterop.Infrastructure
throw new JsonException("Invalid JSON"); throw new JsonException("Invalid JSON");
} }
var suppliedArgs = new object[parameterTypes.Length]; var suppliedArgs = new object?[parameterTypes.Length];
var index = 0; var index = 0;
while (index < parameterTypes.Length && reader.Read() && reader.TokenType != JsonTokenType.EndArray) while (index < parameterTypes.Length && reader.Read() && reader.TokenType != JsonTokenType.EndArray)
@ -331,7 +331,7 @@ namespace Microsoft.JSInterop.Infrastructure
foreach (var method in invokableMethods) foreach (var method in invokableMethods)
{ {
var identifier = method.GetCustomAttribute<JSInvokableAttribute>(false).Identifier ?? method.Name; var identifier = method.GetCustomAttribute<JSInvokableAttribute>(false)!.Identifier ?? method.Name!;
var parameterTypes = method.GetParameters().Select(p => p.ParameterType).ToArray(); var parameterTypes = method.GetParameters().Select(p => p.ParameterType).ToArray();
if (result.ContainsKey(identifier)) if (result.ContainsKey(identifier))
@ -360,7 +360,7 @@ namespace Microsoft.JSInterop.Infrastructure
.Where(method => !method.ContainsGenericParameters && method.IsDefined(typeof(JSInvokableAttribute), inherit: false)); .Where(method => !method.ContainsGenericParameters && method.IsDefined(typeof(JSInvokableAttribute), inherit: false));
foreach (var method in invokableMethods) foreach (var method in invokableMethods)
{ {
var identifier = method.GetCustomAttribute<JSInvokableAttribute>(false).Identifier ?? method.Name; var identifier = method.GetCustomAttribute<JSInvokableAttribute>(false)!.Identifier ?? method.Name;
var parameterTypes = method.GetParameters().Select(p => p.ParameterType).ToArray(); var parameterTypes = method.GetParameters().Select(p => p.ParameterType).ToArray();
if (result.ContainsKey(identifier)) if (result.ContainsKey(identifier))
@ -400,7 +400,7 @@ namespace Microsoft.JSInterop.Infrastructure
public AssemblyKey(Assembly assembly) public AssemblyKey(Assembly assembly)
{ {
Assembly = assembly; Assembly = assembly;
AssemblyName = assembly.GetName().Name; AssemblyName = assembly.GetName().Name!;
} }
public AssemblyKey(string assemblyName) public AssemblyKey(string assemblyName)
@ -409,7 +409,7 @@ namespace Microsoft.JSInterop.Infrastructure
AssemblyName = assemblyName; AssemblyName = assemblyName;
} }
public Assembly Assembly { get; } public Assembly? Assembly { get; }
public string AssemblyName { get; } public string AssemblyName { get; }

View File

@ -12,7 +12,7 @@ namespace Microsoft.JSInterop.Infrastructure
/// </summary> /// </summary>
/// <param name="exception">The <see cref="System.Exception"/> that caused the failure.</param> /// <param name="exception">The <see cref="System.Exception"/> that caused the failure.</param>
/// <param name="errorKind">The error kind.</param> /// <param name="errorKind">The error kind.</param>
public DotNetInvocationResult(Exception exception, string errorKind) public DotNetInvocationResult(Exception exception, string? errorKind)
{ {
Result = default; Result = default;
Exception = exception ?? throw new ArgumentNullException(nameof(exception)); Exception = exception ?? throw new ArgumentNullException(nameof(exception));
@ -24,7 +24,7 @@ namespace Microsoft.JSInterop.Infrastructure
/// Constructor for a successful invocation. /// Constructor for a successful invocation.
/// </summary> /// </summary>
/// <param name="result">The result.</param> /// <param name="result">The result.</param>
public DotNetInvocationResult(object result) public DotNetInvocationResult(object? result)
{ {
Result = result; Result = result;
Exception = default; Exception = default;
@ -35,17 +35,17 @@ namespace Microsoft.JSInterop.Infrastructure
/// <summary> /// <summary>
/// Gets the <see cref="System.Exception"/> that caused the failure. /// Gets the <see cref="System.Exception"/> that caused the failure.
/// </summary> /// </summary>
public Exception Exception { get; } public Exception? Exception { get; }
/// <summary> /// <summary>
/// Gets the error kind. /// Gets the error kind.
/// </summary> /// </summary>
public string ErrorKind { get; } public string? ErrorKind { get; }
/// <summary> /// <summary>
/// Gets the result of a successful invocation. /// Gets the result of a successful invocation.
/// </summary> /// </summary>
public object Result { get; } public object? Result { get; }
/// <summary> /// <summary>
/// <see langword="true"/> if the invocation succeeded, otherwise <see langword="false"/>. /// <see langword="true"/> if the invocation succeeded, otherwise <see langword="false"/>.

View File

@ -27,7 +27,7 @@ namespace Microsoft.JSInterop.Infrastructure
var instanceType = typeToConvert.GetGenericArguments()[0]; var instanceType = typeToConvert.GetGenericArguments()[0];
var converterType = typeof(DotNetObjectReferenceJsonConverter<>).MakeGenericType(instanceType); var converterType = typeof(DotNetObjectReferenceJsonConverter<>).MakeGenericType(instanceType);
return (JsonConverter)Activator.CreateInstance(converterType, JSRuntime); return (JsonConverter)Activator.CreateInstance(converterType, JSRuntime)!;
} }
} }
} }

View File

@ -16,7 +16,7 @@ namespace Microsoft.JSInterop.Infrastructure
private static ConcurrentDictionary<Type, ITcsResultSetter> _cachedResultSetters private static ConcurrentDictionary<Type, ITcsResultSetter> _cachedResultSetters
= new ConcurrentDictionary<Type, ITcsResultSetter>(); = new ConcurrentDictionary<Type, ITcsResultSetter>();
public static void SetTaskCompletionSourceResult(object taskCompletionSource, object result) public static void SetTaskCompletionSourceResult(object taskCompletionSource, object? result)
=> CreateResultSetter(taskCompletionSource).SetResult(taskCompletionSource, result); => CreateResultSetter(taskCompletionSource).SetResult(taskCompletionSource, result);
public static void SetTaskCompletionSourceException(object taskCompletionSource, Exception exception) public static void SetTaskCompletionSourceException(object taskCompletionSource, Exception exception)
@ -25,7 +25,7 @@ namespace Microsoft.JSInterop.Infrastructure
public static Type GetTaskCompletionSourceResultType(object taskCompletionSource) public static Type GetTaskCompletionSourceResultType(object taskCompletionSource)
=> CreateResultSetter(taskCompletionSource).ResultType; => CreateResultSetter(taskCompletionSource).ResultType;
public static object GetTaskResult(Task task) public static object? GetTaskResult(Task task)
{ {
var getter = _cachedResultGetters.GetOrAdd(task.GetType(), taskInstanceType => var getter = _cachedResultGetters.GetOrAdd(task.GetType(), taskInstanceType =>
{ {
@ -33,12 +33,12 @@ namespace Microsoft.JSInterop.Infrastructure
return resultType == null return resultType == null
? new VoidTaskResultGetter() ? new VoidTaskResultGetter()
: (ITaskResultGetter)Activator.CreateInstance( : (ITaskResultGetter)Activator.CreateInstance(
typeof(TaskResultGetter<>).MakeGenericType(resultType)); typeof(TaskResultGetter<>).MakeGenericType(resultType))!;
}); });
return getter.GetResult(task); return getter.GetResult(task);
} }
private static Type GetTaskResultType(Type taskType) private static Type? GetTaskResultType(Type taskType)
{ {
// It might be something derived from Task or Task<T>, so we have to scan // It might be something derived from Task or Task<T>, so we have to scan
// up the inheritance hierarchy to find the Task or Task<T> // up the inheritance hierarchy to find the Task or Task<T>
@ -57,23 +57,23 @@ namespace Microsoft.JSInterop.Infrastructure
interface ITcsResultSetter interface ITcsResultSetter
{ {
Type ResultType { get; } Type ResultType { get; }
void SetResult(object taskCompletionSource, object result); void SetResult(object taskCompletionSource, object? result);
void SetException(object taskCompletionSource, Exception exception); void SetException(object taskCompletionSource, Exception exception);
} }
private interface ITaskResultGetter private interface ITaskResultGetter
{ {
object GetResult(Task task); object? GetResult(Task task);
} }
private class TaskResultGetter<T> : ITaskResultGetter private class TaskResultGetter<T> : ITaskResultGetter
{ {
public object GetResult(Task task) => ((Task<T>)task).Result; public object? GetResult(Task task) => ((Task<T>)task).Result!;
} }
private class VoidTaskResultGetter : ITaskResultGetter private class VoidTaskResultGetter : ITaskResultGetter
{ {
public object GetResult(Task task) public object? GetResult(Task task)
{ {
task.Wait(); // Throw if the task failed task.Wait(); // Throw if the task failed
return null; return null;
@ -84,7 +84,7 @@ namespace Microsoft.JSInterop.Infrastructure
{ {
public Type ResultType => typeof(T); public Type ResultType => typeof(T);
public void SetResult(object tcs, object result) public void SetResult(object tcs, object? result)
{ {
var typedTcs = (TaskCompletionSource<T>)tcs; var typedTcs = (TaskCompletionSource<T>)tcs;
@ -93,7 +93,7 @@ namespace Microsoft.JSInterop.Infrastructure
? resultT ? resultT
: (T)Convert.ChangeType(result, typeof(T)); : (T)Convert.ChangeType(result, typeof(T));
typedTcs.SetResult(typedResult); typedTcs.SetResult(typedResult!);
} }
public void SetException(object tcs, Exception exception) public void SetException(object tcs, Exception exception)
@ -109,7 +109,7 @@ namespace Microsoft.JSInterop.Infrastructure
{ {
var resultType = tcsType.GetGenericArguments().Single(); var resultType = tcsType.GetGenericArguments().Single();
return (ITcsResultSetter)Activator.CreateInstance( return (ITcsResultSetter)Activator.CreateInstance(
typeof(TcsResultSetter<>).MakeGenericType(resultType)); typeof(TcsResultSetter<>).MakeGenericType(resultType))!;
}); });
} }
} }

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Diagnostics.CodeAnalysis;
using System.Text.Json; using System.Text.Json;
namespace Microsoft.JSInterop namespace Microsoft.JSInterop
@ -17,6 +18,7 @@ namespace Microsoft.JSInterop
/// <param name="identifier">An identifier for the function to invoke. For example, the value <c>"someScope.someFunction"</c> will invoke the function <c>window.someScope.someFunction</c>.</param> /// <param name="identifier">An identifier for the function to invoke. For example, the value <c>"someScope.someFunction"</c> will invoke the function <c>window.someScope.someFunction</c>.</param>
/// <param name="args">JSON-serializable arguments.</param> /// <param name="args">JSON-serializable arguments.</param>
/// <returns>An instance of <typeparamref name="TValue"/> obtained by JSON-deserializing the return value.</returns> /// <returns>An instance of <typeparamref name="TValue"/> obtained by JSON-deserializing the return value.</returns>
[return: MaybeNull]
public TValue Invoke<TValue>(string identifier, params object[] args) public TValue Invoke<TValue>(string identifier, params object[] args)
{ {
var resultJson = InvokeJS(identifier, JsonSerializer.Serialize(args, JsonSerializerOptions)); var resultJson = InvokeJS(identifier, JsonSerializer.Serialize(args, JsonSerializerOptions));
@ -34,6 +36,6 @@ namespace Microsoft.JSInterop
/// <param name="identifier">The identifier for the function to invoke.</param> /// <param name="identifier">The identifier for the function to invoke.</param>
/// <param name="argsJson">A JSON representation of the arguments.</param> /// <param name="argsJson">A JSON representation of the arguments.</param>
/// <returns>A JSON representation of the result.</returns> /// <returns>A JSON representation of the result.</returns>
protected abstract string InvokeJS(string identifier, string argsJson); protected abstract string? InvokeJS(string identifier, string? argsJson);
} }
} }

View File

@ -20,7 +20,7 @@ namespace Microsoft.JSInterop
/// If not set, the identifier is taken from the name of the method. In this case the /// If not set, the identifier is taken from the name of the method. In this case the
/// method name must be unique within the assembly. /// method name must be unique within the assembly.
/// </summary> /// </summary>
public string Identifier { get; } public string? Identifier { get; }
/// <summary> /// <summary>
/// Constructs an instance of <see cref="JSInvokableAttribute"/> without setting /// Constructs an instance of <see cref="JSInvokableAttribute"/> without setting

View File

@ -62,14 +62,16 @@ namespace Microsoft.JSInterop
/// <param name="identifier">An identifier for the function to invoke. For example, the value <c>"someScope.someFunction"</c> will invoke the function <c>window.someScope.someFunction</c>.</param> /// <param name="identifier">An identifier for the function to invoke. For example, the value <c>"someScope.someFunction"</c> will invoke the function <c>window.someScope.someFunction</c>.</param>
/// <param name="args">JSON-serializable arguments.</param> /// <param name="args">JSON-serializable arguments.</param>
/// <returns>An instance of <typeparamref name="TValue"/> obtained by JSON-deserializing the return value.</returns> /// <returns>An instance of <typeparamref name="TValue"/> obtained by JSON-deserializing the return value.</returns>
public ValueTask<TValue> InvokeAsync<TValue>(string identifier, object[] args) public async ValueTask<TValue> InvokeAsync<TValue>(string identifier, object[] args)
{ {
if (DefaultAsyncTimeout.HasValue) if (DefaultAsyncTimeout.HasValue)
{ {
return InvokeWithDefaultCancellation<TValue>(identifier, args); using var cts = new CancellationTokenSource(DefaultAsyncTimeout.Value);
// We need to await here due to the using
return await InvokeAsync<TValue>(identifier, cts.Token, args);
} }
return InvokeAsync<TValue>(identifier, CancellationToken.None, args); return await InvokeAsync<TValue>(identifier, CancellationToken.None, args);
} }
/// <summary> /// <summary>
@ -130,22 +132,13 @@ namespace Microsoft.JSInterop
} }
} }
private async ValueTask<T> InvokeWithDefaultCancellation<T>(string identifier, object[] args)
{
using (var cts = new CancellationTokenSource(DefaultAsyncTimeout.Value))
{
// We need to await here due to the using
return await InvokeAsync<T>(identifier, cts.Token, args);
}
}
/// <summary> /// <summary>
/// Begins an asynchronous function invocation. /// Begins an asynchronous function invocation.
/// </summary> /// </summary>
/// <param name="taskId">The identifier for the function invocation, or zero if no async callback is required.</param> /// <param name="taskId">The identifier for the function invocation, or zero if no async callback is required.</param>
/// <param name="identifier">The identifier for the function to invoke.</param> /// <param name="identifier">The identifier for the function to invoke.</param>
/// <param name="argsJson">A JSON representation of the arguments.</param> /// <param name="argsJson">A JSON representation of the arguments.</param>
protected abstract void BeginInvokeJS(long taskId, string identifier, string argsJson); protected abstract void BeginInvokeJS(long taskId, string identifier, string? argsJson);
/// <summary> /// <summary>
/// Completes an async JS interop call from JavaScript to .NET /// Completes an async JS interop call from JavaScript to .NET

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks> <TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
@ -8,6 +8,7 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<IsPackable>true</IsPackable> <IsPackable>true</IsPackable>
<IsAspNetCoreApp>true</IsAspNetCoreApp> <IsAspNetCoreApp>true</IsAspNetCoreApp>
<Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'"> <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable disable
using System; using System;
using System.Linq; using System.Linq;
using System.Text.Json; using System.Text.Json;

View File

@ -80,7 +80,7 @@ namespace Microsoft.JSInterop.Infrastructure
var json = $"{{\"__dotNetObject\":{objectId}}}"; var json = $"{{\"__dotNetObject\":{objectId}}}";
// Act // Act
var deserialized = JsonSerializer.Deserialize<DotNetObjectReference<TestModel>>(json, JsonSerializerOptions); var deserialized = JsonSerializer.Deserialize<DotNetObjectReference<TestModel>>(json, JsonSerializerOptions)!;
// Assert // Assert
Assert.Same(input, deserialized.Value); Assert.Same(input, deserialized.Value);
@ -100,7 +100,7 @@ namespace Microsoft.JSInterop.Infrastructure
var json = $"[{{\"__dotNetObject\":{JSRuntime.TrackObjectReference(ref1)}}},{{\"__dotNetObject\":{JSRuntime.TrackObjectReference(ref2)}}}]"; var json = $"[{{\"__dotNetObject\":{JSRuntime.TrackObjectReference(ref1)}}},{{\"__dotNetObject\":{JSRuntime.TrackObjectReference(ref2)}}}]";
// Act // Act
var deserialized = JsonSerializer.Deserialize<DotNetObjectReference<TestModel>[]>(json, JsonSerializerOptions); var deserialized = JsonSerializer.Deserialize<DotNetObjectReference<TestModel>[]>(json, JsonSerializerOptions)!;
// Assert // Assert
Assert.Same(instance1, deserialized[0].Value); Assert.Same(instance1, deserialized[0].Value);
@ -121,7 +121,7 @@ namespace Microsoft.JSInterop.Infrastructure
}}"; }}";
// Act // Act
var deserialized = JsonSerializer.Deserialize<DotNetObjectReference<TestModel>>(json, JsonSerializerOptions); var deserialized = JsonSerializer.Deserialize<DotNetObjectReference<TestModel>>(json, JsonSerializerOptions)!;
// Assert // Assert
Assert.Same(input, deserialized.Value); Assert.Same(input, deserialized.Value);

View File

@ -21,7 +21,7 @@ namespace Microsoft.JSInterop
}; };
// Act // Act
var syncResult = runtime.Invoke<TestDTO>("test identifier 1", "arg1", 123, true); var syncResult = runtime.Invoke<TestDTO>("test identifier 1", "arg1", 123, true)!;
var call = runtime.InvokeCalls.Single(); var call = runtime.InvokeCalls.Single();
// Assert // Assert
@ -80,7 +80,7 @@ namespace Microsoft.JSInterop
"test identifier", "test identifier",
DotNetObjectReference.Create(obj1), DotNetObjectReference.Create(obj1),
"some other arg", "some other arg",
DotNetObjectReference.Create(obj2)); DotNetObjectReference.Create(obj2))!;
var call = runtime.InvokeCalls.Single(); var call = runtime.InvokeCalls.Single();
// Assert // Assert
@ -90,16 +90,16 @@ namespace Microsoft.JSInterop
class TestDTO class TestDTO
{ {
public int IntValue { get; set; } public int IntValue { get; set; }
public string StringValue { get; set; } public string? StringValue { get; set; }
} }
class TestJSInProcessRuntime : JSInProcessRuntime class TestJSInProcessRuntime : JSInProcessRuntime
{ {
public List<InvokeArgs> InvokeCalls { get; set; } = new List<InvokeArgs>(); public List<InvokeArgs> InvokeCalls { get; set; } = new List<InvokeArgs>();
public string NextResultJson { get; set; } public string? NextResultJson { get; set; }
protected override string InvokeJS(string identifier, string argsJson) protected override string? InvokeJS(string identifier, string? argsJson)
{ {
InvokeCalls.Add(new InvokeArgs { Identifier = identifier, ArgsJson = argsJson }); InvokeCalls.Add(new InvokeArgs { Identifier = identifier, ArgsJson = argsJson });
return NextResultJson; return NextResultJson;
@ -107,11 +107,11 @@ namespace Microsoft.JSInterop
public class InvokeArgs public class InvokeArgs
{ {
public string Identifier { get; set; } public string? Identifier { get; set; }
public string ArgsJson { get; set; } public string? ArgsJson { get; set; }
} }
protected override void BeginInvokeJS(long asyncHandle, string identifier, string argsJson) protected override void BeginInvokeJS(long asyncHandle, string identifier, string? argsJson)
=> throw new NotImplementedException("This test only covers sync calls"); => throw new NotImplementedException("This test only covers sync calls");
protected internal override void EndInvokeDotNet(DotNetInvocationInfo invocationInfo, in DotNetInvocationResult invocationResult) protected internal override void EndInvokeDotNet(DotNetInvocationInfo invocationInfo, in DotNetInvocationResult invocationResult)

View File

@ -322,14 +322,14 @@ namespace Microsoft.JSInterop
private class JSError private class JSError
{ {
public string Message { get; set; } public string? Message { get; set; }
} }
private class TestPoco private class TestPoco
{ {
public int Id { get; set; } public int Id { get; set; }
public string Name { get; set; } public string? Name { get; set; }
} }
class TestJSRuntime : JSRuntime class TestJSRuntime : JSRuntime
@ -348,18 +348,18 @@ namespace Microsoft.JSInterop
public class BeginInvokeAsyncArgs public class BeginInvokeAsyncArgs
{ {
public long AsyncHandle { get; set; } public long AsyncHandle { get; set; }
public string Identifier { get; set; } public string? Identifier { get; set; }
public string ArgsJson { get; set; } public string? ArgsJson { get; set; }
} }
public class EndInvokeDotNetArgs public class EndInvokeDotNetArgs
{ {
public string CallId { get; set; } public string? CallId { get; set; }
public bool Success { get; set; } public bool Success { get; set; }
public object ResultOrError { get; set; } public object? ResultOrError { get; set; }
} }
public Func<DotNetInvocationInfo, object> OnDotNetException { get; set; } public Func<DotNetInvocationInfo, object>? OnDotNetException { get; set; }
protected internal override void EndInvokeDotNet(DotNetInvocationInfo invocationInfo, in DotNetInvocationResult invocationResult) protected internal override void EndInvokeDotNet(DotNetInvocationInfo invocationInfo, in DotNetInvocationResult invocationResult)
{ {
@ -377,7 +377,7 @@ namespace Microsoft.JSInterop
}); });
} }
protected override void BeginInvokeJS(long asyncHandle, string identifier, string argsJson) protected override void BeginInvokeJS(long asyncHandle, string identifier, string? argsJson)
{ {
BeginInvokeCalls.Add(new BeginInvokeAsyncArgs BeginInvokeCalls.Add(new BeginInvokeAsyncArgs
{ {

View File

@ -2,6 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>$(DefaultNetCoreTargetFramework);net472</TargetFrameworks> <TargetFrameworks>$(DefaultNetCoreTargetFramework);net472</TargetFrameworks>
<Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -8,7 +8,7 @@ namespace Microsoft.JSInterop
{ {
internal class TestJSRuntime : JSRuntime internal class TestJSRuntime : JSRuntime
{ {
protected override void BeginInvokeJS(long asyncHandle, string identifier, string argsJson) protected override void BeginInvokeJS(long asyncHandle, string identifier, string? argsJson)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }