Blazor Javascript Interoperability

Introduction

The impetus of this article is to determine how to process JavaScript promises within C#.  There are features available in browsers that we may want to interact with that require us to be able to invoke JavaScript methods from C# and respond to the resulting promises returned from these JavaScript methods.  This post is going to dive into the inner workings of the Microsoft.JSInterop.

Note the source code for this project can be found at github.

Invoking JavaScript Functions from .NET Methods

Initially we’ll look at invoking JavaScript functions from .Net.  There are times when you need to access browser capabilities that are only exposed via a JavaScript library.  These function(s) may be defined within the <head> element of the wwwroot/index.html (Blazor client-side), Pages/_Hosts.cshtml (Blazor server-side), or a separate JavaScript file that can be referenced.  The implementation presented in this post uses a separately referenced JavaScript file located in wwwroot.

To invoke a JavaScript function from .NET requires the use of the IJSRuntime abstraction.  Specifically the JSRuntime.InvokeAsync<T>() method.  This method takes a string identifier for the JavaScript function to be invoked, a collection of JSON serializable arguments, and an optional cancellation token.  Note: the JavaScript function name is relative to the global ‘window’ object.  Therefore invoking a method window.somejavascriptfunction() you need only supply somejavascriptfunction().

Figure 1

Figure 1 shows the JavaScript function that converts the unsigned int array into a string.  This code is in wwwroot/ExampleJsInterop.js.

It should be noted that while the Blazor server side app is pre-rendering, invoking JavaScript functions is not permitted.  Once the connection to the browser is established, the JavaScript functions can be called.  To determine whether the Blazor component is pre-rendering, use the OnAfterRender or OnAfterRenderAsync lifecycle events.

Figure 2

Figure 2 shows the C# Razor page CallJsMethod that invokes the JavaScript function in Figure 1.

Figure 3
Before Clicking the Convert Array Button
Figure 4
After Clicking the Convert Array Button

Figure3 and Figure 4 show the results of calling ConvertArray() JavaScript function from .Net.

Invoking .Net Methods from JavaScript

There are two approaches to invoking .Net methods from JavaScript.  The first is invoking static methods of a class.  The other is invoking instance methods of a class object.

Invoking Static Methods from a Class

To invoke a static class method from JavaScript, we need to use the DotNet.InvokeMethod() or DotNet.InvokeMethodAsync() functions.  These methods take the following arguments:

  • The static method identifier
  • The name of the assembly containing the class and static method
  • Any associated arguments

The .Net method must be:

  • A public static method
  • The method must be decorated with the [JSInvokable] attribute

Invoking open generic methods is currently not supported.  When open generic methods are supported, we can then develop generic classes/methods and use them to process JavaScript calls for specific type of arguments.  More on this later when we talk about processing JavaScript promises asynchronously using JSInterop to process JavaScript promises in .Net.

Figure 5

The button invokes the JavaScript function JavascriptToDotNet.returnArrayJsAsync().  See Figure 5 above.  This method in-turn invokes the static method of the class BlazorInterop.Client.ReturnArrayAsync()BlazorInterop.Client.ReturnArrayAsync() returns the array [1, 2, 3], see Figure 6 below.  Once the result is returned to JavaScript function, the promise then pushes the number 4 onto the array as shown in Figure 7 below.

Figure 6
Figure 7

The array is then logged to the developers console as shown in Figure 8 below.

Figure 8

Invoking Instance Methods of a Class

In addition to calling static class methods, you can also invoke class instance methods.  In order to invoke an instance method you have to:

  • Pass the .Net instance to JavaScript by wrapping it in a DotNetObjectReference instance. This .Net instance is then passed by reference to the JavaScript method.
  • Invoke the .Net instance methods on the instance using the invokeMethod() or invokeMethodAsync() functions.  The .Net instance can also be passed as an argument when invoking other .Net methods from JavaScript.

The button invokes the TriggerNetInstanceMethod.  This method calls the CallHelloHelperSayHello method which creates a DotNetObjectReference object from the HelloHelper class passing in the name to return when called from JavaScript.  See Figures 9 & 10 below.

Figure 9
Figure 10

This DotNetObjectReference object is then used as an argument when calling the JavaScriptToDotNet.sayHello() JavaScript function.  On the JavaScript side, the DotNetObjectReference object is the first (and only) argument in the sayHello() function.  The dotNetHelper object is then used to invoke the SayHello() instance method of the HelloHelper C# object.  See Figure 11 below.

Figure 11

Which in-turn outputs the string “Hello Blazor!” which is then logged to the browsers developer console as shown below in Figure 12.

Figure 12

Using JavaScript Interoperability to Process JavaScript Promises Asynchronously using async/await

Lastly we’re going to discuss using JavaScript interoperability to process JavaScript promises from C#.  There are numerous JavaScript libraries available to the browser.  To more effectively interact with these libraries in Blazor, we need a way to invoke these library methods and process promises generated by these libraries that contain needed results.

Invoking a JavaScript Method that Successfully Resolves  a Promise

The first method we’re going to call will execute a JavaScript function that generates a promise and returns the results after a timeout of 2 seconds.  The ‘Run Promise to get result’ button calls the CallFunctionWithPromise() function which creates the PromiseHandler DotNetObjectReference object and invokes the JavaScript function JavascriptWithPromises.runPromiseFunction(). See Figures 13 – 15.

Figure 13
Figure 14
Figure 15

The JavascriptWithPromises.runPromiseFunction() is passed the PromiseHandler (DotNetObjectReference), the name of the method to call, and the argument to that method.  The window.FunctionWithPromise() function is called and returns a promise with the supplied message.  In the runPromiseFunction()’s promise.then clause, our C# DotNetObjectReference PromiseHandler (See Figure 16 & 17) will invoke the PromiseHandler.SetResult() method to set the resulting value (See Figure 18).  This is then returned to the page’s promiseResult by awaiting the async call ExampleJsInterop(JsRuntime).CallFunctionWithPromise() asynchronous method.  The promise result is then displayed on the page See Figures 19 & 20).

Figure 16
Figure 17
Figure 18
Figure 19
Before Calling the ‘Run Promise to get result’ Button
Figure 20
After Calling the ‘Run Promise to get result’ Button

Invoking a JavaScript Function that Encounters an Error and Rejects the Promise and Returns an Error

This time the JavaScript function that gets invoked will instead reject the promise after two seconds.  The rejected promise will then propagate through the promise handler and set the associated error on the page.

The ‘Run promise to get result (this time the promise rejects and returns an error)’ button calls the RunMethodThatGeneratesAnError() function which creates the PromiseHandler DotNetObjectReference object and invokes the JavaScript function JavascriptWithPromises.runPromiseFunction().  This time the JavaScript function called is functionThatMakesAnError(). See Figures 21 – 25.

Figure 21
Figure 22
Figure 23
Figure 24
Figure 25

The rejected promise is then caught in the try catch block of the runPromiseFunction() function. The catch error handler then uses our C# DotNetObjectReference PromiseHandler will invoke the PromiseHandler.SetError() method to raise an exception See Figure 26.  This exception is then caught in the RunMethodThatGeneratesAnError() page method, see Figure 21 and 22.  The exception handler in this method then surfaces the error to be displayed on the page.

Figure 26

Figure 27 and 28 show the before and after clicking the ‘Run promise to get result (this time the promise rejects and returns an error)’ button.

Figure 27
Before Calling the ‘Run promise to get result (this time the promise rejects and returns an error)’ Button
Figure 28
After Calling the ‘Run promise to get result (this time the promise rejects and returns an error)’ Button

Summary

In this post, we’ve covered how to make C# calls into JavaScript and how to have JavaScript functions make calls back into C#.  Lastly we took a detailed look at how we could process JavaScript promises within C#.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this:
search previous next tag category expand menu location phone mail time cart zoom edit close