Remove old marshalled-interop API and update MonoSanity sample to use newer API
This commit is contained in:
parent
99a08da321
commit
09eccb52c5
|
|
@ -104,6 +104,19 @@
|
||||||
function triggerJsException() {
|
function triggerJsException() {
|
||||||
throw new Error('This is a JavaScript exception.');
|
throw new Error('This is a JavaScript exception.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Normally, applications would use the higher-level APIs for registering invocable
|
||||||
|
// functions, and for invoking them with automatic argument/result marshalling.
|
||||||
|
// But since this project is trying to test low-level Mono runtime capabilities,
|
||||||
|
// we implement our own marshalling here.
|
||||||
|
window.__blazorRegisteredFunctions = {
|
||||||
|
evaluateJsExpression: function (dotNetStringExpression) {
|
||||||
|
var result = eval(dotnetStringToJavaScriptString(dotNetStringExpression));
|
||||||
|
return result === null || result === undefined
|
||||||
|
? result // Pass through null/undefined so we can verify this is handled upstream
|
||||||
|
: javaScriptStringToDotNetString(result.toString());
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,21 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
window.dotnetStringToJavaScriptString = function dotnetStringToJavaScriptString(mono_obj) {
|
||||||
|
if (mono_obj === 0)
|
||||||
|
return null;
|
||||||
|
var mono_string_get_utf8 = Module.cwrap('mono_wasm_string_get_utf8', 'number', ['number']);
|
||||||
|
var raw = mono_string_get_utf8(mono_obj);
|
||||||
|
var res = Module.UTF8ToString(raw);
|
||||||
|
Module._free(raw);
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
window.javaScriptStringToDotNetString = function dotnetStringToJavaScriptString(javaScriptString) {
|
||||||
|
var mono_string = Module.cwrap('mono_wasm_string_from_js', 'number', ['string']);
|
||||||
|
return mono_string(javaScriptString);
|
||||||
|
};
|
||||||
|
|
||||||
function preloadAssemblies(loadAssemblyUrls) {
|
function preloadAssemblies(loadAssemblyUrls) {
|
||||||
var loadBclAssemblies = [
|
var loadBclAssemblies = [
|
||||||
'mscorlib',
|
'mscorlib',
|
||||||
|
|
@ -77,21 +92,10 @@
|
||||||
xhr.onerror = onerror;
|
xhr.onerror = onerror;
|
||||||
xhr.send(null);
|
xhr.send(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
function dotnetStringToJavaScriptString(mono_obj) {
|
|
||||||
if (mono_obj === 0)
|
|
||||||
return null;
|
|
||||||
var mono_string_get_utf8 = Module.cwrap('mono_wasm_string_get_utf8', 'number', ['number']);
|
|
||||||
var raw = mono_string_get_utf8(mono_obj);
|
|
||||||
var res = Module.UTF8ToString(raw);
|
|
||||||
Module._free(raw);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
function callMethod(method, target, args) {
|
function callMethod(method, target, args) {
|
||||||
var stack = Module.Runtime.stackSave();
|
var stack = Module.Runtime.stackSave();
|
||||||
var invoke_method = Module.cwrap('mono_wasm_invoke_method', 'number', ['number', 'number', 'number']);
|
var invoke_method = Module.cwrap('mono_wasm_invoke_method', 'number', ['number', 'number', 'number']);
|
||||||
var mono_string = Module.cwrap('mono_wasm_string_from_js', 'number', ['string']);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var argsBuffer = Module.Runtime.stackAlloc(args.length);
|
var argsBuffer = Module.Runtime.stackAlloc(args.length);
|
||||||
|
|
@ -103,7 +107,7 @@
|
||||||
Module.setValue(managedInt, argVal, 'i32');
|
Module.setValue(managedInt, argVal, 'i32');
|
||||||
Module.setValue(argsBuffer + i * 4, managedInt, 'i32');
|
Module.setValue(argsBuffer + i * 4, managedInt, 'i32');
|
||||||
} else if (typeof argVal === 'string') {
|
} else if (typeof argVal === 'string') {
|
||||||
var managedString = mono_string(argVal);
|
var managedString = javaScriptStringToDotNetString(argVal);
|
||||||
Module.setValue(argsBuffer + i * 4, managedString, 'i32');
|
Module.setValue(argsBuffer + i * 4, managedString, 'i32');
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Unsupported arg type: ' + typeof argVal);
|
throw new Error('Unsupported arg type: ' + typeof argVal);
|
||||||
|
|
|
||||||
|
|
@ -31,10 +31,10 @@ namespace MonoSanityClient
|
||||||
|
|
||||||
public static string EvaluateJavaScript(string expression)
|
public static string EvaluateJavaScript(string expression)
|
||||||
{
|
{
|
||||||
var result = Runtime.InvokeJS(expression, out var resultIsException);
|
var result = Runtime.InvokeJS<string, object, object, string>(out var exceptionMessage, "evaluateJsExpression", expression, null, null);
|
||||||
if (resultIsException != 0)
|
if (exceptionMessage != null)
|
||||||
{
|
{
|
||||||
return $".NET got exception: {result}";
|
return $".NET got exception: {exceptionMessage}";
|
||||||
}
|
}
|
||||||
|
|
||||||
return $".NET received: {(result ?? "(NULL)")}";
|
return $".NET received: {(result ?? "(NULL)")}";
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,9 @@
|
||||||
<!-- Local alternative to <PackageReference Include="Microsoft.Blazor.Build" /> -->
|
<!-- Local alternative to <PackageReference Include="Microsoft.Blazor.Build" /> -->
|
||||||
<Import Project="..\..\src\Microsoft.Blazor.Build\ReferenceFromSource.props" />
|
<Import Project="..\..\src\Microsoft.Blazor.Build\ReferenceFromSource.props" />
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<!-- Share the WebAssembly.Runtime.cs source here so we get access to the same interop externs -->
|
||||||
|
<Compile Include="..\..\src\Microsoft.Blazor.Browser\Interop\WebAssembly.Runtime.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace WebAssembly
|
|
||||||
{
|
|
||||||
internal static class Runtime
|
|
||||||
{
|
|
||||||
// The exact namespace, type, and method name must match the corresponding entry in
|
|
||||||
// driver.c in the Mono distribution
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
public static extern string InvokeJS(string str, out int resultIsException);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using WebAssembly;
|
||||||
|
|
||||||
|
namespace Microsoft.Blazor.Browser.Interop
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides methods for invoking preregistered JavaScript functions from .NET code.
|
||||||
|
/// </summary>
|
||||||
|
public static class RegisteredFunction
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the JavaScript function registered with the specified identifier.
|
||||||
|
///
|
||||||
|
/// When using this overload, all arguments will be supplied as <see cref="System.Object" />
|
||||||
|
/// references, meaning that any reference types will be boxed. If you are passing
|
||||||
|
/// 3 or fewer arguments, it is preferable to instead call the overload that
|
||||||
|
/// specifies generic type arguments for each argument.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TRes">The .NET type corresponding to the function's return value type.</typeparam>
|
||||||
|
/// <param name="identifier">The identifier used when registering the target function.</param>
|
||||||
|
/// <param name="args">The arguments to pass, each of which will be supplied as a <see cref="System.Object" /> instance.</param>
|
||||||
|
/// <returns>The result of the function invocation.</returns>
|
||||||
|
public static TRes Invoke<TRes>(string identifier, params object[] args)
|
||||||
|
{
|
||||||
|
var result = Runtime.InvokeJSArray<TRes>(out var exception, identifier, args);
|
||||||
|
return exception != null
|
||||||
|
? throw new JavaScriptException(exception)
|
||||||
|
: result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the JavaScript function registered with the specified identifier.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TRes">The .NET type corresponding to the function's return value type.</typeparam>
|
||||||
|
/// <param name="identifier">The identifier used when registering the target function.</param>
|
||||||
|
/// <returns>The result of the function invocation.</returns>
|
||||||
|
public static TRes Invoke<T0, TRes>(string identifier)
|
||||||
|
{
|
||||||
|
var result = Runtime.InvokeJS<object, object, object, TRes>(out var exception, identifier, null, null, null);
|
||||||
|
return exception != null
|
||||||
|
? throw new JavaScriptException(exception)
|
||||||
|
: result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the JavaScript function registered with the specified identifier.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T0">The type of the first argument.</typeparam>
|
||||||
|
/// <typeparam name="TRes">The .NET type corresponding to the function's return value type.</typeparam>
|
||||||
|
/// <param name="identifier">The identifier used when registering the target function.</param>
|
||||||
|
/// <param name="arg0">The first argument.</param>
|
||||||
|
/// <returns>The result of the function invocation.</returns>
|
||||||
|
public static TRes Invoke<T0, TRes>(string identifier, T0 arg0)
|
||||||
|
{
|
||||||
|
var result = Runtime.InvokeJS<T0, object, object, TRes>(out var exception, identifier, arg0, null, null);
|
||||||
|
return exception != null
|
||||||
|
? throw new JavaScriptException(exception)
|
||||||
|
: result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the JavaScript function registered with the specified identifier.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T0">The type of the first argument.</typeparam>
|
||||||
|
/// <typeparam name="T1">The type of the second argument.</typeparam>
|
||||||
|
/// <typeparam name="TRes">The .NET type corresponding to the function's return value type.</typeparam>
|
||||||
|
/// <param name="identifier">The identifier used when registering the target function.</param>
|
||||||
|
/// <param name="arg0">The first argument.</param>
|
||||||
|
/// <param name="arg1">The second argument.</param>
|
||||||
|
/// <returns>The result of the function invocation.</returns>
|
||||||
|
public static TRes Invoke<T0, T1, TRes>(string identifier, T0 arg0, T1 arg1)
|
||||||
|
{
|
||||||
|
var result = Runtime.InvokeJS<T0, T1, object, TRes>(out var exception, identifier, arg0, arg1, null);
|
||||||
|
return exception != null
|
||||||
|
? throw new JavaScriptException(exception)
|
||||||
|
: result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the JavaScript function registered with the specified identifier.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T0">The type of the first argument.</typeparam>
|
||||||
|
/// <typeparam name="T1">The type of the second argument.</typeparam>
|
||||||
|
/// <typeparam name="T2">The type of the third argument.</typeparam>
|
||||||
|
/// <typeparam name="TRes">The .NET type corresponding to the function's return value type.</typeparam>
|
||||||
|
/// <param name="identifier">The identifier used when registering the target function.</param>
|
||||||
|
/// <param name="arg0">The first argument.</param>
|
||||||
|
/// <param name="arg1">The second argument.</param>
|
||||||
|
/// <param name="arg2">The third argument.</param>
|
||||||
|
/// <returns>The result of the function invocation.</returns>
|
||||||
|
public static TRes Invoke<T0, T1, T2, TRes>(string identifier, T0 arg0, T1 arg1, T2 arg2)
|
||||||
|
{
|
||||||
|
var result = Runtime.InvokeJS<T0, T1, T2, TRes>(out var exception, identifier, arg0, arg1, arg2);
|
||||||
|
return exception != null
|
||||||
|
? throw new JavaScriptException(exception)
|
||||||
|
: result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,33 +1,19 @@
|
||||||
// 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 Microsoft.Blazor.Browser.Interop;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace WebAssembly
|
namespace WebAssembly
|
||||||
{
|
{
|
||||||
internal static class Runtime
|
internal static class Runtime
|
||||||
{
|
{
|
||||||
public static string EvaluateJavaScript(string expression)
|
// The exact namespace, type, and method names must match the corresponding entry in
|
||||||
{
|
|
||||||
var result = InvokeJS(expression, out var resultIsException);
|
|
||||||
|
|
||||||
if (resultIsException != 0)
|
|
||||||
{
|
|
||||||
throw new JavaScriptException(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The exact namespace, type, and method name must match the corresponding entry in
|
|
||||||
// driver.c in the Mono distribution
|
// driver.c in the Mono distribution
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
static extern string InvokeJS(string str, out int resultIsException);
|
|
||||||
|
|
||||||
// The exact namespace, type, and method name must match the corresponding entry in
|
|
||||||
// driver.c in the Mono distribution
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
public static extern object InvokeJSUnmarshalled(string funcExpression, object[] args, out int resultIsException);
|
public static extern TRes InvokeJS<T0, T1, T2, TRes>(out string exception, string funcName, T0 arg0, T1 arg1, T2 arg2);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
public static extern TRes InvokeJSArray<TRes>(out string exception, string funcName, object[] args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ namespace Microsoft.Blazor.Browser
|
||||||
{
|
{
|
||||||
public Renderer()
|
public Renderer()
|
||||||
{
|
{
|
||||||
WebAssembly.Runtime.EvaluateJavaScript("console.log('Renderer')");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ namespace Microsoft.Blazor.E2ETest.Tests
|
||||||
SetValue(Browser, "callJsEvalExpression", "triggerJsException()");
|
SetValue(Browser, "callJsEvalExpression", "triggerJsException()");
|
||||||
Browser.FindElement(By.CssSelector("#callJs button")).Click();
|
Browser.FindElement(By.CssSelector("#callJs button")).Click();
|
||||||
var result = GetValue(Browser, "callJsResult");
|
var result = GetValue(Browser, "callJsResult");
|
||||||
Assert.StartsWith(".NET got exception: Error: This is a JavaScript exception.", result);
|
Assert.StartsWith(".NET got exception: This is a JavaScript exception.", result);
|
||||||
|
|
||||||
// Also verify we got a stack trace
|
// Also verify we got a stack trace
|
||||||
Assert.Contains("at triggerJsException", result);
|
Assert.Contains("at triggerJsException", result);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue