From 4a0612f56d9c064208545d1b05f67cf9983e34ee Mon Sep 17 00:00:00 2001 From: Luke Latham Date: Wed, 25 Nov 2020 09:50:13 -0600 Subject: [PATCH] Update and improve Blazor unmarshalled JS (#20747) --- .../blazor/call-javascript-from-dotnet.md | 178 +++++++++++++++--- 1 file changed, 154 insertions(+), 24 deletions(-) diff --git a/aspnetcore/blazor/call-javascript-from-dotnet.md b/aspnetcore/blazor/call-javascript-from-dotnet.md index 17faee1db6..ce29caef13 100644 --- a/aspnetcore/blazor/call-javascript-from-dotnet.md +++ b/aspnetcore/blazor/call-javascript-from-dotnet.md @@ -5,13 +5,13 @@ description: Learn how to invoke JavaScript functions from .NET methods in Blazo monikerRange: '>= aspnetcore-3.1' ms.author: riande ms.custom: mvc, devx-track-js -ms.date: 10/20/2020 +ms.date: 11/25/2020 no-loc: [appsettings.json, "ASP.NET Core Identity", cookie, Cookie, Blazor, "Blazor Server", "Blazor WebAssembly", "Identity", "Let's Encrypt", Razor, SignalR] uid: blazor/call-javascript-from-dotnet --- # Call JavaScript functions from .NET methods in ASP.NET Core Blazor -By [Javier Calvarro Nelson](https://github.com/javiercn), [Daniel Roth](https://github.com/danroth27), and [Luke Latham](https://github.com/guardrex) +By [Javier Calvarro Nelson](https://github.com/javiercn), [Daniel Roth](https://github.com/danroth27), [Pranav Krishnamoorthy](https://github.com/pranavkm), and [Luke Latham](https://github.com/guardrex) A Blazor app can invoke JavaScript functions from .NET methods and .NET methods from JavaScript functions. These scenarios are called *JavaScript interoperability* (*JS interop*). @@ -526,28 +526,6 @@ public async ValueTask Prompt(string message) `IJSInProcessObjectReference` represents a reference to a JavaScript object whose functions can be invoked synchronously. -`IJSUnmarshalledObjectReference` represents a reference to an JavaScript object whose functions can be invoked without the overhead of serializing .NET data. This can be used in Blazor WebAssembly when performance is crucial: - -```javascript -window.unmarshalledInstance = { - helloWorld: function (personNamePointer) { - const personName = Blazor.platform.readStringField(value, 0); - return `Hello ${personName}`; - } -}; -``` - -```csharp -var unmarshalledRuntime = (IJSUnmarshalledRuntime)js; -var jsUnmarshalledReference = unmarshalledRuntime - .InvokeUnmarshalled("unmarshalledInstance"); - -string helloWorldString = jsUnmarshalledReference.InvokeUnmarshalled( - "helloWorld"); -``` - -In the preceding example, the service is injected into the class and assigned to `js` (not shown). - ## Use of JavaScript libraries that render UI (DOM elements) Sometimes you may wish to use JavaScript libraries that produce visible user interface elements within the browser DOM. At first glance, this might seem difficult because Blazor's diffing system relies on having control over the tree of DOM elements and runs into errors if some external code mutates the DOM tree and invalidates its mechanism for applying diffs. This isn't a Blazor-specific limitation. The same challenge occurs with any diff-based UI framework. @@ -691,6 +669,158 @@ Consider the following guidance when developing code that transfers a large amou For JS isolation, JS interop works with the browser's default support for [EcmaScript modules (ESM)](https://developer.mozilla.org/docs/Web/JavaScript/Guide/Modules) ([ECMAScript specification](https://tc39.es/ecma262/#sec-modules)). +## Unmarshalled JS interop + +Blazor WebAssembly components may experience poor performance when .NET objects are serialized for JS interop and either of the following are true: + +* A high volume of .NET objects are rapidly serialized. Example: JS interop calls are made on the basis of moving an input device, such as spinning a mouse wheel. +* Large .NET objects or many .NET objects must be serialized for JS interop. Example: JS interop calls require serializing dozens of files. + + represents a reference to an JavaScript object whose functions can be invoked without the overhead of serializing .NET data. + +In the following example: + +* A [struct](/dotnet/csharp/language-reference/builtin-types/struct) containing a string and an integer is passed unserialized to JavaScript. +* JavaScript functions process the data and return either a boolean or string to the caller. +* A JavaScript string isn't directly convertible into a .NET `string` object. The `unmarshalledFunctionReturnString` function calls `BINDING.js_string_to_mono_string` to manage the conversion of a Javascript string. + +> [!NOTE] +> The following examples aren't typical use cases for this scenario because the [struct](/dotnet/csharp/language-reference/builtin-types/struct) passed to JavaScript doesn't result in poor component performance. The example uses a small object merely to demonstrate the concepts for passing unserialized .NET data. + +Content of a `