Blazor Bites - JavaScript Interop

Blazor Bites Series


Post valid for: Blazor 0.2.0
Please remember that Blazor is an experimental project and is going to be changing regularly. IT IS NOT PRODUCTION READY.


JavaScript Interop

It's great that with Blazor we can now use C# in the browser. But, unfortunately, we can't yet do everything with it. Currently WebAssembly isn't able to directly access the DOM API, which means that Blazor is not able to either. But fear not, JavaScript and WebAssembly can work together; WebAssembly is able to call JavaScript functions.

Part of Blazor is implemented and lives in the JavaScript world. It is though this interface that Blazor is able to manipulate the DOM to render the UI and to hook into various DOM events. It is also how developers can register and call their own JavaScript functions from C# code.

Registering JavaScript functions with C#

In order to use a JavaScript function from C# it has to be registered with one of Blazors JavaScript functions, registerFunction. This is a simple function which takes an identifier, which is the identifier you will use to call this function from C#. And a implementation, which is the JavaScript function to be called.

One thing to note is that currently your JS function must have a return value. If you don't provide one, things blow up.

Example
<script>
    Blazor.registerFunction('JavaScriptAlert', (message) => {
        alert(message);
        return true;
    });
</script>

Calling JavaScript functions from C#

From C#, you can then use either RegisteredFunction.Invoke or RegisteredFunction.InvokeUnmarshalled, with your identifier, to run your JavaScript function. The difference between Invoke and InvokeUnmarshalled is that when calling Invoke all arguments and return values are marshalled (passed) using JSON. When calling InvokeUnmarshalled this is not the case, you would have to handle how you pass objects across the C#/JavaScript boundary manually.

Example
public static void TriggerJsAlert()
{
    RegisteredFunction.Invoke<bool>("JavaScriptAlert", "I was invoked from C#!");
}

Registering C# methods with JavaScript

As well as calling JavaScript from C#, you may also wish to do the opposite and call C# methods from JavaScript. In order to do this you have to use the platform.findMethod on Blazors JavaScript side. This function takes 4 arguments, assemblyName, namespace, className and methodName. It will then return you a MethodHandle which you will need in order to invoke the C# method.

Example
namespace BlazorExamples
{
    public static class Utils(string message)
    {
        public static void LogToConsole(string message)
        {
            Console.WriteLine(message);
        }
    }
}
const logToConsoleMethod = Blazor.platform.findMethod(
                                'BlazorExamples',   // Assembly name
                                'BlazorExamples',   // Namespace
                                'Utils',            // Class name
                                'LogToConsole'      // Method name
                            );

Calling C# methods from JavaScript

In order to call your C# method, you will need to pass the MethodHandle returned from the findMethod function to the platform.callMethod function. callMethod takes 3 arguments. The first is the MethodHandle, discussed above. The second is a Target, this is an object instance, but as we are invoking a static method it can be null. The third is an array of arguments to pass to the C# method.

Note: There is a restriction in the Mono platform regarding the number of arguments you can pass from JS to .NET. This limit is currently set at 4. If you attempt to pass any more than 4 the platform will throw an error.

let message = 'Hello from JS!';
let messageAsDotNetString = Blazor.platform.toDotNetString(message);

Blazor.platform.callMethod(
                    logToConsoleMethod,         // Method handle
                    null,                       // Target
                    [ messageAsDotNetString ]   // Arguments
                );

Wrapping up

That's the end of another Blazor Bites post. I have been getting some really good feeback about the series which is great to hear. If there is anything specific you want me to cover please leave a comment below and I'll see what I can do.