Although Web Assembly has the ability to end our dependence on JavaScript, JavaScript won’t go away anytime soon. There’s still a lot of stuff Web Assembly just can’t do, particularly DOM manipulation. If you run the Blazor server side, you don’t even have Web Assembly as a choice. So how are we going to cope with this problem?
The solution to this is JavaScript interop. If we can’t do what we need to use.NET code on our own, we can use IJSRuntime abstraction to make calls to JavaScript functions. We can also have JavaScript functions to render calls to our C# language.
Before we go any further, I would like to point out a recent update in the way JS interop functions. Historically, developers could render JavaScript calls using JSRuntime.Current. This was a static version of JSRuntime, eliminating the need to insert something into modules or utilities.
This worked perfectly by using Blazor WebAssembly as the software was running in the local window, and no state was shared with anyone else. However, this created some severe problems while operating the Blazor Server. Since it was static, the action was highly volatile, so the team has now eliminated this static implementation, and developers will only use the IJSRuntime injection.
The first is InvokeAsync, and we use this anytime we want the JavaScript feature we’re calling to return something to us. It requires a string, an identifier, which is the identifier for the function to be named. This identifier is proportional to the window object because if you were to call the window.Blazored.LocalStorage.setItem, you’d go to ‘Blazored.LocalStorage.setItem.’ If you have any parameters that you need to pass to the JavaScript function, you can do so using the second statement.
Secondly, you can use InvokeVoidAsync any time for calling a JavaScript function that is not returning something. Using InvokeAsync the first argument will be the function you want to call, and it will help you use different arguments. You may have noted that all the methods are asynchronous.
This is crucial because if you want the code to function on both the Blazor client-side and the Blazor server-side, all Javascript interop calls must be asynchronous due to the SignalR link used by the Blazor server side.
If you have client-side situations that you need to call JavaScript synchronously, so you have the option to download IJSRuntime to IJSInProcessRuntime. This GUI gives us the same two processes, except this time they’re synchronous.
We’ve now addressed the resources available to us. Let’s look at an example of how we can use it to call a JavaScript feature. We are going to set up a part that will interrupt the following JavaScript function.
window.ShowAlert = (message) => { alert(message); }
The code above is clearly wrapping a call to the JavaScript warning feature that allows one to transfer a message to be shown.
Find out what the code looks like to call this feature from the Razor Part.
@inject IJSRuntime jsRuntime <input type="text" @bind="message" /> <button @onclick="ShowAlert">Show Alert</button> @code { string message = ""; private async Task ShowAlert() { await jsRuntime.InvokeVoidAsync("ShowAlert", message); } }
Starting from the end, we request an instance of IJSRuntime from the DI container using the @inject directive. We have an entry that we can use to insert a request, then a button that activates an interop call to the JS function.
As I said earlier, you can always, by default, async calls whenever possible to make sure that the code is running in both client and server scenarios. But if you need to, because you know the code won’t be running on the server, you should make a sync call.
@inject IJSRuntime jsRuntime <input type="text" @bind="message" /> <button @onclick="ShowAlert">Show Alert</button> @code { string message = ""; private void ShowAlert() { ((IJSInProcessRuntime)jsRuntime).InvokeVoid("ShowAlert", message); } }
As you can see, we downcast IJSRuntime to IJSInProcessRuntime, which gave us access to the synchronous InvokeVoid system. Apart from changing the signature of the ShowAlert process, we didn’t have to make any more adjustments to make our code work synchronously.
Again, this is not going to work with the Blazor Server. If you attempt to run the code above, you will end up with InvalidCastException. Just use this approach if you are confident that the code will only be running on the client-side.
Often you need JavaScript functions to render calls to your C# file. One example of this is the use of JavaScript commitments. The pledge may be resolved sometime after the initial call, and you need to know the outcome. There are two choices for naming the C# code. The first is to call static methods, and the second is to call instance methods.
When calling static protocols, either DotNet.invokeMethod or DotNet.invokeMethodAsync may be used. As before, you can still use the Async version wherever possible, as this would make the code compliant for client and server scenarios. We use the DotNet.invokeMethodAsync function given by the Blazor system.
The first argument is the name of the assembly comprising the form that we choose to use. The second argument is the name of the process. As the call is intermittent, the commitment returns. When the promise resolves, we take the message that arrives from our C# code and logs it to the console.