Skip to content

Commit

Permalink
Merge pull request #42814 from pavelsavara/new_js_interop_minimal
Browse files Browse the repository at this point in the history
[blazor] Obsolete InvokeUnmarshalled
  • Loading branch information
pavelsavara authored Jul 20, 2022
2 parents 0602a32 + 5995535 commit e6f27b0
Show file tree
Hide file tree
Showing 17 changed files with 330 additions and 30 deletions.
258 changes: 239 additions & 19 deletions src/Components/Web.JS/@types/dotnet/dotnet.d.ts

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/Components/Web.JS/src/Boot.WebAssembly.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ async function boot(options?: Partial<WebAssemblyStartOptions>): Promise<void> {
jsInitializer.invokeAfterStartedCallbacks(Blazor);
}

// obsolete, legacy, don't use for new code!
function invokeJSFromDotNet(callInfo: Pointer, arg0: any, arg1: any, arg2: any): any {
const functionIdentifier = monoPlatform.readStringField(callInfo, 0)!;
const resultType = monoPlatform.readInt32Field(callInfo, 4);
Expand Down
22 changes: 16 additions & 6 deletions src/Components/Web.JS/src/Platform/Mono/MonoPlatform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { DotnetPublicAPI, BINDINGType, CreateDotnetRuntimeType, DotnetModuleConf
export let BINDING: BINDINGType = undefined as any;
export let MONO: MONOType = undefined as any;
export let Module: DotnetModuleConfig & EmscriptenModule = undefined as any;
export let IMPORTS: any = undefined as any;

const appBinDirName = 'appBinDir';
const uint64HighOrderShift = Math.pow(2, 32);
Expand Down Expand Up @@ -300,18 +301,19 @@ async function createEmscriptenModuleInstance(resourceLoader: WebAssemblyResourc
const createDotnetRuntime = await dotnetJsBeingLoaded;

await createDotnetRuntime((api) => {
const { MONO: mono, BINDING: binding, Module: module } = api;
const { MONO: mono, BINDING: binding, Module: module, IMPORTS: imports } = api;
Module = module;
BINDING = binding;
MONO = mono;
IMPORTS = imports;

// Override the mechanism for fetching the main wasm file so we can connect it to our cache
const instantiateWasm = (imports, successCallback) => {
const instantiateWasm = (wasmImports, successCallback) => {
(async () => {
let compiledInstance: WebAssembly.Instance;
try {
const dotnetWasmResource = await wasmBeingLoaded;
compiledInstance = await compileWasmModule(dotnetWasmResource, imports);
compiledInstance = await compileWasmModule(dotnetWasmResource, wasmImports);
} catch (ex) {
printErr((ex as Error).toString());
throw ex;
Expand Down Expand Up @@ -343,9 +345,7 @@ async function createEmscriptenModuleInstance(resourceLoader: WebAssemblyResourc
assembliesBeingLoaded.forEach(r => addResourceAsAssembly(r, changeExtension(r.name, '.dll')));
pdbsBeingLoaded.forEach(r => addResourceAsAssembly(r, r.name));

Blazor._internal.dotNetCriticalError = (message) => {
printErr(BINDING.conv_string(message) || '(null)');
};
Blazor._internal.dotNetCriticalError = (message) => printErr(message || '(null)');

// Wire-up callbacks for satellite assemblies. Blazor will call these as part of the application
// startup sequence to load satellite assemblies for the application's culture.
Expand Down Expand Up @@ -481,6 +481,16 @@ async function createEmscriptenModuleInstance(resourceLoader: WebAssemblyResourc
// -1 enables debugging with logging disabled. 0 disables debugging entirely.
MONO.mono_wasm_load_runtime(appBinDirName, hasDebuggingEnabled() ? -1 : 0);
MONO.mono_wasm_runtime_ready();
try {
BINDING.bind_static_method('invalid-fqn', '');
} catch (e) {
// HOTFIX: until https://github.com/dotnet/runtime/pull/72275
// this would always throw, but it will initialize runtime interop as side-effect
}

// makes Blazor._internal visible to [JSImport]
IMPORTS.Blazor = { _internal: Blazor._internal };

attachInteropInvoker();
runtimeReadyResolve(api);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,37 @@ public WebAssemblyJSObjectReference(WebAssemblyJSRuntime jsRuntime, long id)
_jsRuntime = jsRuntime;
}

#pragma warning disable CS0612 // Type or member is obsolete
[Obsolete("This method is obsolete. Use JSImportAttribute instead.")]
public TResult InvokeUnmarshalled<TResult>(string identifier)
{
ThrowIfDisposed();

return _jsRuntime.InvokeUnmarshalled<object?, object?, object?, TResult>(identifier, null, null, null, Id);
}

[Obsolete("This method is obsolete. Use JSImportAttribute instead.")]
public TResult InvokeUnmarshalled<T0, TResult>(string identifier, T0 arg0)
{
ThrowIfDisposed();

return _jsRuntime.InvokeUnmarshalled<T0, object?, object?, TResult>(identifier, arg0, null, null, Id);
}

[Obsolete("This method is obsolete. Use JSImportAttribute instead.")]
public TResult InvokeUnmarshalled<T0, T1, TResult>(string identifier, T0 arg0, T1 arg1)
{
ThrowIfDisposed();

return _jsRuntime.InvokeUnmarshalled<T0, T1, object?, TResult>(identifier, arg0, arg1, null, Id);
}

[Obsolete("This method is obsolete. Use JSImportAttribute instead.")]
public TResult InvokeUnmarshalled<T0, T1, T2, TResult>(string identifier, T0 arg0, T1 arg1, T2 arg2)
{
ThrowIfDisposed();

return _jsRuntime.InvokeUnmarshalled<T0, T1, T2, TResult>(identifier, arg0, arg1, arg2, Id);
}
#pragma warning restore CS0612 // Type or member is obsolete
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,21 @@ protected override void EndInvokeDotNet(DotNetInvocationInfo callInfo, in DotNet
var resultJsonOrErrorMessage = dispatchResult.Success
? dispatchResult.ResultJson!
: dispatchResult.Exception!.ToString();
#pragma warning disable CS0618 // Type or member is obsolete
InvokeUnmarshalled<string?, bool, string, object>("Blazor._internal.endInvokeDotNetFromJS",
callInfo.CallId, dispatchResult.Success, resultJsonOrErrorMessage);
#pragma warning restore CS0618 // Type or member is obsolete
}

/// <inheritdoc />
protected override void SendByteArray(int id, byte[] data)
{
#pragma warning disable CS0618 // Type or member is obsolete
InvokeUnmarshalled<int, byte[], object>("Blazor._internal.receiveByteArray", id, data);
#pragma warning restore CS0618 // Type or member is obsolete
}

[Obsolete("This method is obsolete. Use JSImportAttribute instead.")]
internal TResult InvokeUnmarshalled<T0, T1, T2, TResult>(string identifier, T0 arg0, T1 arg1, T2 arg2, long targetInstanceId)
{
var resultType = JSCallResultTypeHelper.FromGeneric<TResult>();
Expand Down Expand Up @@ -122,18 +127,22 @@ private IJSStreamReference DeserializeJSStreamReference(string serializedStreamR
}

/// <inheritdoc />
[Obsolete("This method is obsolete. Use JSImportAttribute instead.")]
public TResult InvokeUnmarshalled<TResult>(string identifier)
=> InvokeUnmarshalled<object?, object?, object?, TResult>(identifier, null, null, null, 0);

/// <inheritdoc />
[Obsolete("This method is obsolete. Use JSImportAttribute instead.")]
public TResult InvokeUnmarshalled<T0, TResult>(string identifier, T0 arg0)
=> InvokeUnmarshalled<T0, object?, object?, TResult>(identifier, arg0, null, null, 0);

/// <inheritdoc />
[Obsolete("This method is obsolete. Use JSImportAttribute instead.")]
public TResult InvokeUnmarshalled<T0, T1, TResult>(string identifier, T0 arg0, T1 arg1)
=> InvokeUnmarshalled<T0, T1, object?, TResult>(identifier, arg0, arg1, null, 0);

/// <inheritdoc />
[Obsolete("This method is obsolete. Use JSImportAttribute instead.")]
public TResult InvokeUnmarshalled<T0, T1, T2, TResult>(string identifier, T0 arg0, T1 arg1, T2 arg2)
=> InvokeUnmarshalled<T0, T1, T2, TResult>(identifier, arg0, arg1, arg2, 0);
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public virtual async ValueTask LoadCurrentCultureResourcesAsync()
// assemblies. We effectively want to resovle a Task<byte[][]> but there is no way to express this
// using interop. We'll instead do this in two parts:
// getSatelliteAssemblies resolves when all satellite assemblies to be loaded in .NET are fetched and available in memory.
#pragma warning disable CS0618 // Type or member is obsolete
var count = (int)await _invoker.InvokeUnmarshalled<string[], object?, object?, Task<object>>(
GetSatelliteAssemblies,
culturesToLoad.ToArray(),
Expand All @@ -91,6 +92,7 @@ public virtual async ValueTask LoadCurrentCultureResourcesAsync()
null,
null,
null);
#pragma warning restore CS0618 // Type or member is obsolete

for (var i = 0; i < assemblies.Length; i++)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ internal WebAssemblyHostBuilder(IJSUnmarshalledRuntime jsRuntime, JsonSerializer
[UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "Root components are expected to be defined in assemblies that do not get trimmed.")]
private void InitializeRegisteredRootComponents(IJSUnmarshalledRuntime jsRuntime)
{
#pragma warning disable CS0618 // Type or member is obsolete
var componentsCount = jsRuntime.InvokeUnmarshalled<int>(RegisteredComponentsInterop.GetRegisteredComponentsCount);
if (componentsCount == 0)
{
Expand All @@ -106,6 +107,7 @@ private void InitializeRegisteredRootComponents(IJSUnmarshalledRuntime jsRuntime
var serializedParameterValues = jsRuntime.InvokeUnmarshalled<int, object?, object?, string>(RegisteredComponentsInterop.GetParameterValues, id, null, null);
registeredComponents[i] = new WebAssemblyComponentMarker(WebAssemblyComponentMarker.ClientMarkerType, assembly, typeName, serializedParameterDefinitions, serializedParameterValues, id.ToString(CultureInfo.InvariantCulture));
}
#pragma warning restore CS0618 // Type or member is obsolete

var componentDeserializer = WebAssemblyComponentParameterDeserializer.Instance;
foreach (var registeredComponent in registeredComponents)
Expand All @@ -129,20 +131,26 @@ private void InitializeRegisteredRootComponents(IJSUnmarshalledRuntime jsRuntime

private void InitializePersistedState(IJSUnmarshalledRuntime jsRuntime)
{
#pragma warning disable CS0618 // Type or member is obsolete
_persistedState = jsRuntime.InvokeUnmarshalled<string>("Blazor._internal.getPersistedState");
#pragma warning restore CS0618 // Type or member is obsolete
}

private static void InitializeNavigationManager(IJSUnmarshalledRuntime jsRuntime)
{
#pragma warning disable CS0618 // Type or member is obsolete
var baseUri = jsRuntime.InvokeUnmarshalled<string>(BrowserNavigationManagerInterop.GetBaseUri);
var uri = jsRuntime.InvokeUnmarshalled<string>(BrowserNavigationManagerInterop.GetLocationHref);
#pragma warning restore CS0618 // Type or member is obsolete

WebAssemblyNavigationManager.Instance = new WebAssemblyNavigationManager(baseUri, uri);
}

private WebAssemblyHostEnvironment InitializeEnvironment(IJSUnmarshalledRuntime jsRuntime)
{
#pragma warning disable CS0618 // Type or member is obsolete
var applicationEnvironment = jsRuntime.InvokeUnmarshalled<string>("Blazor._internal.getApplicationEnvironment");
#pragma warning restore CS0618 // Type or member is obsolete
var hostEnvironment = new WebAssemblyHostEnvironment(applicationEnvironment, WebAssemblyNavigationManager.Instance.BaseUri);

Services.AddSingleton<IWebAssemblyHostEnvironment>(hostEnvironment);
Expand All @@ -155,8 +163,10 @@ private WebAssemblyHostEnvironment InitializeEnvironment(IJSUnmarshalledRuntime

foreach (var configFile in configFiles)
{
#pragma warning disable CS0618 // Type or member is obsolete
var appSettingsJson = jsRuntime.InvokeUnmarshalled<string, byte[]>(
"Blazor._internal.getConfig", configFile);
#pragma warning restore CS0618 // Type or member is obsolete

if (appSettingsJson != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ internal static async Task InitializeAsync()
// See https://github.com/dotnet/aspnetcore/issues/37357#issuecomment-941237000

var jsObjectReference = (IJSUnmarshalledObjectReference)(await DefaultWebAssemblyJSRuntime.Instance.InvokeAsync<IJSObjectReference>("import", "/_framework/blazor-hotreload.js"));
#pragma warning disable CS0618 // Type or member is obsolete
await jsObjectReference.InvokeUnmarshalled<Task<int>>("receiveHotReload");
#pragma warning restore CS0618 // Type or member is obsolete
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<Nullable>enable</Nullable>
<IsTrimmable>true</IsTrimmable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,12 @@ protected override void ProcessPendingRender()
/// <inheritdoc />
protected override Task UpdateDisplayAsync(in RenderBatch batch)
{
#pragma warning disable CS0618 // Type or member is obsolete
DefaultWebAssemblyJSRuntime.Instance.InvokeUnmarshalled<int, RenderBatch, object>(
"Blazor._internal.renderBatch",
RendererId,
batch);
#pragma warning restore CS0618 // Type or member is obsolete

if (WebAssemblyCallQueue.HasUnstartedWork)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ public static void BeginInvokeDotNet(string callId, string assemblyNameOrDotNetO
/// <param name="id">Id of the byte array</param>
public static void NotifyByteArrayAvailable(int id)
{
#pragma warning disable CS0618 // Type or member is obsolete
var data = Instance.InvokeUnmarshalled<byte[]>("Blazor._internal.retrieveByteArray");
#pragma warning restore CS0618 // Type or member is obsolete

DotNetDispatcher.ReceiveByteArray(Instance, id, data);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,18 +105,22 @@ private async Task<IEnumerable<Assembly>> LoadAssembliesInClientAsync(IEnumerabl
}

var jsRuntime = (IJSUnmarshalledRuntime)_jsRuntime;
#pragma warning disable CS0618 // Type or member is obsolete
var count = (int)await jsRuntime.InvokeUnmarshalled<string[], Task<object>>(
GetLazyAssemblies,
newAssembliesToLoad.ToArray());
#pragma warning restore CS0618 // Type or member is obsolete

if (count == 0)
{
return Array.Empty<Assembly>();
}

var loadedAssemblies = new List<Assembly>();
#pragma warning disable CS0618 // Type or member is obsolete
var assemblies = jsRuntime.InvokeUnmarshalled<byte[][]>(ReadLazyAssemblies);
var pdbs = jsRuntime.InvokeUnmarshalled<byte[][]>(ReadLazyPDBs);
#pragma warning restore CS0618 // Type or member is obsolete

for (int i = 0; i < assemblies.Length; i++)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Runtime.InteropServices.JavaScript;
using System.Text;
using Microsoft.Extensions.Logging;
using Microsoft.JSInterop;
Expand Down Expand Up @@ -79,19 +80,19 @@ private void WriteMessage(LogLevel logLevel, string logName, int eventId, string
// messages if you enable "Verbose" in the filter dropdown (which is off
// by default). As such "console.debug" is the best choice for messages
// with a lower severity level than "Information".
_jsRuntime.InvokeVoid("console.debug", formattedMessage);
ConsoleLoggerInterop.ConsoleDebug(formattedMessage);
break;
case LogLevel.Information:
_jsRuntime.InvokeVoid("console.info", formattedMessage);
ConsoleLoggerInterop.ConsoleInfo(formattedMessage);
break;
case LogLevel.Warning:
_jsRuntime.InvokeVoid("console.warn", formattedMessage);
ConsoleLoggerInterop.ConsoleWarn(formattedMessage);
break;
case LogLevel.Error:
_jsRuntime.InvokeVoid("console.error", formattedMessage);
ConsoleLoggerInterop.ConsoleError(formattedMessage);
break;
case LogLevel.Critical:
_jsRuntime.InvokeUnmarshalled<string, object>("Blazor._internal.dotNetCriticalError", formattedMessage);
ConsoleLoggerInterop.DotNetCriticalError(formattedMessage);
break;
default: // invalid enum values
Debug.Assert(logLevel != LogLevel.None, "This method is never called with LogLevel.None.");
Expand Down Expand Up @@ -165,3 +166,17 @@ private sealed class NoOpDisposable : IDisposable
public void Dispose() { }
}
}

internal static partial class ConsoleLoggerInterop
{
[JSImport("globalThis.console.debug")]
public static partial void ConsoleDebug(string message);
[JSImport("globalThis.console.info")]
public static partial void ConsoleInfo(string message);
[JSImport("globalThis.console.warn")]
public static partial void ConsoleWarn(string message);
[JSImport("globalThis.console.error")]
public static partial void ConsoleError(string message);
[JSImport("Blazor._internal.dotNetCriticalError")]
public static partial void DotNetCriticalError(string message);
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,15 @@ public async Task LoadCurrentCultureResourcesAsync_ReadsAssemblies()
// Arrange
using var cultureReplacer = new CultureReplacer("en-GB");
var invoker = new Mock<IJSUnmarshalledRuntime>();
#pragma warning disable CS0618 // Type or member is obsolete
invoker.Setup(i => i.InvokeUnmarshalled<string[], object, object, Task<object>>(GetSatelliteAssemblies, new[] { "en-GB", "en" }, null, null))
.Returns(Task.FromResult<object>(1))
.Verifiable();

invoker.Setup(i => i.InvokeUnmarshalled<object, object, object, object[]>(ReadSatelliteAssemblies, null, null, null))
.Returns(new object[] { File.ReadAllBytes(GetType().Assembly.Location) })
.Verifiable();
#pragma warning restore CS0618 // Type or member is obsolete

var loader = new WebAssemblyCultureProvider(invoker.Object, CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture);

Expand All @@ -56,17 +58,21 @@ public async Task LoadCurrentCultureResourcesAsync_DoesNotReadAssembliesWhenTher
// Arrange
using var cultureReplacer = new CultureReplacer("en-GB");
var invoker = new Mock<IJSUnmarshalledRuntime>();
#pragma warning disable CS0618 // Type or member is obsolete
invoker.Setup(i => i.InvokeUnmarshalled<string[], object, object, Task<object>>(GetSatelliteAssemblies, new[] { "en-GB", "en" }, null, null))
.Returns(Task.FromResult<object>(0))
.Verifiable();
#pragma warning restore CS0618 // Type or member is obsolete

var loader = new WebAssemblyCultureProvider(invoker.Object, CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture);

// Act
await loader.LoadCurrentCultureResourcesAsync();

#pragma warning disable CS0618 // Type or member is obsolete
// Assert
invoker.Verify(i => i.InvokeUnmarshalled<object, object, object, object[]>(ReadSatelliteAssemblies, null, null, null), Times.Never());
#pragma warning restore CS0618 // Type or member is obsolete
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@

// we should be able to downcast a IJSInProcessObjectReference as a IJSUnmarshalledObjectReference
var unmarshalledCast = (IJSUnmarshalledObjectReference)jsInProcObjectReference;
#pragma warning disable CS0618 // Type or member is obsolete
ReturnValues["jsCastedUnmarshalledObjectReference.unmarshalledFunction"] = unmarshalledCast.InvokeUnmarshalled<InteropStruct, bool>("unmarshalledFunction", new InteropStruct
{
Message = "Sent from .NET",
Expand All @@ -418,6 +419,7 @@


var dataReference = unmarshalledRuntime.InvokeUnmarshalled<IJSStreamReference>("jsToDotNetStreamReturnValue");
#pragma warning restore CS0618 // Type or member is obsolete
using var dataReferenceStream = await dataReference.OpenReadStreamAsync();
await ValidateStreamValuesAsync("jsToDotNetStreamReturnValueUnmarshalled", dataReferenceStream);
}
Expand Down
Loading

0 comments on commit e6f27b0

Please sign in to comment.