diff --git a/Blazor.sln b/Blazor.sln
index a4e7f1292a..4171202807 100644
--- a/Blazor.sln
+++ b/Blazor.sln
@@ -99,7 +99,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.JSInterop", "src\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.JSInterop.Test", "test\Microsoft.JSInterop.Test\Microsoft.JSInterop.Test.csproj", "{BA1CE1FD-89D8-423F-A21B-6B212674EB39}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.WebAssembly.Interop", "src\mono\Mono.WebAssembly.Interop\Mono.WebAssembly.Interop.csproj", "{C56873E6-8F49-476E-AF51-B5D187832CF5}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.WebAssembly.Interop", "src\Mono.WebAssembly.Interop\Mono.WebAssembly.Interop.csproj", "{C56873E6-8F49-476E-AF51-B5D187832CF5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/samples/MonoSanityClient/MonoSanityClient.csproj b/samples/MonoSanityClient/MonoSanityClient.csproj
index 24d807b2a0..1d08f2fe19 100644
--- a/samples/MonoSanityClient/MonoSanityClient.csproj
+++ b/samples/MonoSanityClient/MonoSanityClient.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/src/Microsoft.AspNetCore.Blazor.Browser/Microsoft.AspNetCore.Blazor.Browser.csproj b/src/Microsoft.AspNetCore.Blazor.Browser/Microsoft.AspNetCore.Blazor.Browser.csproj
index a82fde786c..44a5f58afd 100644
--- a/src/Microsoft.AspNetCore.Blazor.Browser/Microsoft.AspNetCore.Blazor.Browser.csproj
+++ b/src/Microsoft.AspNetCore.Blazor.Browser/Microsoft.AspNetCore.Blazor.Browser.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/src/Mono.WebAssembly.Interop/InternalCalls.cs b/src/Mono.WebAssembly.Interop/InternalCalls.cs
new file mode 100644
index 0000000000..6ed65db5e7
--- /dev/null
+++ b/src/Mono.WebAssembly.Interop/InternalCalls.cs
@@ -0,0 +1,25 @@
+// 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 Mono.WebAssembly.Interop
+{
+ ///
+ /// Methods that map to the functions compiled into the Mono WebAssembly runtime,
+ /// as defined by 'mono_add_internal_call' calls in driver.c
+ ///
+ internal class InternalCalls
+ {
+ // The exact namespace, type, and method names must match the corresponding entries
+ // in driver.c in the Mono distribution
+
+ // We're passing asyncHandle by ref not because we want it to be writable, but so it gets
+ // passed as a pointer (4 bytes). We can pass 4-byte values, but not 8-byte ones.
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ public static extern string InvokeJSMarshalled(out string exception, ref long asyncHandle, string functionIdentifier, string argsJson);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ public static extern TRes InvokeJSUnmarshalled(out string exception, string functionIdentifier, T0 arg0, T1 arg1, T2 arg2);
+ }
+}
diff --git a/src/Mono.WebAssembly.Interop/Mono.WebAssembly.Interop.csproj b/src/Mono.WebAssembly.Interop/Mono.WebAssembly.Interop.csproj
new file mode 100644
index 0000000000..81f1173b55
--- /dev/null
+++ b/src/Mono.WebAssembly.Interop/Mono.WebAssembly.Interop.csproj
@@ -0,0 +1,11 @@
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
diff --git a/src/Mono.WebAssembly.Interop/MonoWebAssemblyJSRuntime.cs b/src/Mono.WebAssembly.Interop/MonoWebAssemblyJSRuntime.cs
new file mode 100644
index 0000000000..19a2a568ef
--- /dev/null
+++ b/src/Mono.WebAssembly.Interop/MonoWebAssemblyJSRuntime.cs
@@ -0,0 +1,87 @@
+// 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 Microsoft.JSInterop;
+
+namespace Mono.WebAssembly.Interop
+{
+ ///
+ /// Provides methods for invoking JavaScript functions for applications running
+ /// on the Mono WebAssembly runtime.
+ ///
+ public class MonoWebAssemblyJSRuntime : JSInProcessRuntimeBase
+ {
+ ///
+ protected override string InvokeJS(string identifier, string argsJson)
+ {
+ var noAsyncHandle = default(long);
+ var result = InternalCalls.InvokeJSMarshalled(out var exception, ref noAsyncHandle, identifier, argsJson);
+ return exception != null
+ ? throw new JSException(exception)
+ : result;
+ }
+
+ ///
+ protected override void BeginInvokeJS(long asyncHandle, string identifier, string argsJson)
+ {
+ InternalCalls.InvokeJSMarshalled(out _, ref asyncHandle, identifier, argsJson);
+ }
+
+ #region Custom MonoWebAssemblyJSRuntime methods
+
+ ///
+ /// Invokes the JavaScript function registered with the specified identifier.
+ ///
+ /// The .NET type corresponding to the function's return value type.
+ /// The identifier used when registering the target function.
+ /// The result of the function invocation.
+ public TRes InvokeUnmarshalled(string identifier)
+ => InvokeUnmarshalled