In the previous two articles of this series, we have learned how to call JavaScript functions from C#. Now, as a logical continuation, we are going to learn how to call C# methods from JavaScript in our Blazor WebAssembly application.
If you want to see complete navigation for this series, you can visit our Blazor WebAssembly Page and find all of the articles from this series and many other articles as well.
Let’s get started.
Preparing Files and Components
Before we start with the main topic of this article, we have to create additional files and components and also add some modifications to the existing files.
So, let’s start with a JavaScript file creation in the scripts
folder. We are going to name this file jsExamples2
.
Then, let’s import this file in the index.html
file:
<script src="scripts/jsExamples2.js"></script>
In the previous articles, we didn’t have to do this because we used the JSObjectReference
class to import the JS module only when we needed it. But now, since we are going to show you how to call C# methods from JavaScript, we have to import the js file.
Now, let’s create the CallDotNetFromJavaScript.razor
and CallDotNetFromJavaScript.razr.cs
files in the Pages
folder:
Let’s just modify the .razor file, by adding a route directive and a title:
@page "/dotnetinjs" <h2>Call DotNet From JavaScript</h2> <br />
Okay. Now we can modify the Index.razor
file:
@page "/" <h3> Use the following links to explore different examples of using a JS code with .NET in Blazor WebAssembly Project: </h3> <ul> <li> <a href="/jsindotnet"> How to call JavaScript code from .NET </a> </li> <li> <a href="/dotnetinjs"> How to call .NET code from JavaScript </a> </li> </ul>
This is a simple navigation link to our previously created component.
If we start our application and click this link, we are going to be navigated to the CallDotNetFromJavaScript
component.
Excellent.
All the preparations are over and we can move on to the main topic of this article.
Calling a Static C# Method From JavaScript
The first thing we have to do is to create a new static method in the CallDotNetFromJavaScript.razor.cs
file:
public partial class CallDotNetFromJavaScript { [JSInvokable] public static string CalculateSquareRoot(int number) { var result = Math.Sqrt(number); return $"The square root of {number} is {result}"; } }
So, this is a very basic logic for calculating the square root of a number. The important part is the [JSInvokable]
attribute. This attribute indicates that this method is invokable by the JavaScript code.
Now, let’s run our app, navigate to this new component, open the developer tools window (F12), and type DotNet
in the console:
The DotNet
object is an object we use to call static C# methods from JavaScript. As you can see it contains two properties – invokeMethod and invokeMethodAsync – that we can use to call static C# methods. In our example, we are going to use the async one.
That said, let’s get back to our project and modify the jsExamples2.js
file:
var jsFunctions = {}; jsFunctions.calculateSquareRoot = function () { const number = prompt("Enter your number"); DotNet.invokeMethodAsync("BlazorWasmJSInteropExamples", "CalculateSquareRoot", parseInt(number)) .then(result => { var el = document.getElementById("string-result"); el.innerHTML = result; }); }
Here, we create a global jsFunctions
object and assign the calculateSquareRoot
function. In this function, we prompt the user to enter a number and then use the DotNet
object and the invokeMethodAsync
function to call our method from .NET. We pass three arguments to this function. The first one is the Assembly name, the second one is the name of the method, and the last one is the parameter expected in the c# method.
You can add additional checks on the number
variable if you want (Is it a number, is it null…).
An additional thing to mention here is that the invokeMethodAsync function returns a promise. So, we use the .then
function to subscribe to that promise. Inside, we just fetch the element with the string-result
id and store the result in it.
Lastly, we have to modify the CallDotNetFromJavaScript.razor
file:
<div class="row"> <div class="col-md-4"> <h4>Calling static method from JS</h4> </div> <div class="col-md-2"> <button type="button" class="btn btn-success" onclick="jsFunctions.calculateSquareRoot()"> Calculate </button> </div> <div class="col-md-4"> <span id="string-result" class="form-text"></span> </div> </div>
The main thing to notice here is that we are not using the @onclick event handler because we are not calling the method from the .cs
file. What we do is calling the javascript function and thus the onclick
event handler.
So, as soon as we click the Calculate button, the prompt window will appear. We are going to enter 25 and click Ok:
There we go. We have a response from the C# method.
Using Custom Identifiers to Call C# Methods from JavaScript
While calling static C# methods from JavaScript, we have to provide an identifier as an argument for the invokeMethodAsync
function. The identifier for this static method in the javascript function is the combination of the assembly name and the name of the method:
DotNet.invokeMethodAsync("BlazorWasmJSInteropExamples", "CalculateSquareRoot", parseInt(number))
The identifier must be unique across the entire assembly. So, having another class with the same-named method in the same assembly won’t work.
Having two methods with the same name is quite common in C#. To support that with JavaScript, we have to use a different overload of the JSInvokable
attribute that accepts the identifier
parameter:
[JSInvokable("CalculateSquareRootWithJustResult")] public static string CalculateSquareRoot(int number, bool justResult) { var result = Math.Sqrt(number); return !justResult ? $"The square root of {number} is {result}" : result.ToString(); }
As you can see, we are providing a different identifier for this method.
Now, in the JavaScript file, we can create a similar call with a different identifier:
jsFunctions.calculateSquareRootWithJustResult = function () { const number = prompt("Enter your number"); DotNet.invokeMethodAsync("BlazorWasmJSInteropExamples", "CalculateSquareRootWithJustResult", parseInt(number), true) .then(result => { var el = document.getElementById("result"); el.innerHTML = result; }); }
You can see we invoke a new method identifier with the additional bool parameter.
Finally, we can create an HTML markup for this:
<div class="row"> <div class="col-md-4"> <h4>Calling static method from JS with Custom Identifier</h4> </div> <div class="col-md-2"> <button type="button" class="btn btn-success" onclick="jsFunctions.calculateSquareRootWithJustResult()"> Calculate </button> </div> <div class="col-md-4"> <span id="result" class="form-text"></span> </div> </div>
Excellent.
If we start our app, navigate to the component, and click any button on the page, we will see that both works but with different results.
Calling C# Instance Methods From JavaScript
Up until now, we’ve been calling static C# methods from JavaScript, but we can do the same with the non-static ones. For this situation, the flow is a bit different. We have to pass the DotNetObjectReference to the JavaScript function and then use it in that function to call the C# instance method.
Let’s see this with an example where we are going to show how to display the mouse coordinates on the screen.
First of all, we have to create a method in our class file that will send the DotNetObjectReference
instance to the JavaScript function:
public partial class CallDotNetFromJavaScript { [Inject] public IJSRuntime JSRuntime { get; set; } ... private async Task SendDotNetInstanceToJS() { var dotNetObjRef = DotNetObjectReference.Create(this); await JSRuntime.InvokeVoidAsync("jsFunctions.showMouseCoordinates", dotNetObjRef); } }
So here, we inject the IJSRuntime
service and create the SendDotNetInstanceToJS
method. Inside this method, we create a new DotNetObjectReference
instance using the Create
method. The DotNetObjectReference
static class comes from the Microsoft.JSInterop
namespace. Then, we use the JSRuntime
property and call the JS function passing our instance to it.
Now, it is obvious that we need the JS function named showMouseCoordinates
:
jsFunctions.showMouseCoordinates = function (dotNetObjRef) { dotNetObjRef.invokeMethodAsync("ShowCoordinates", { x: window.event.screenX, y: window.event.screenY } ); }
The dotNetObjRef
parameter is the one we accept from the C# invocation, and it contains two methods invokeMethodAsync
and invokeMethod
– the same as the DotNet
object does, which we use to call static C# methods. So, as you can see, we are using the async method to invoke the C# method named ShowCoordinates
and as an argument, we pass an object containing two properties the X
and Y
coordinates.
JSInvokable Method and Additional Logic
Now, let’s get back to the class file:
public partial class CallDotNetFromJavaScript { private MouseCoordinates _coordinates = new MouseCoordinates(); [Inject] public IJSRuntime JSRuntime { get; set; } ... private async Task SendDotNetInstanceToJS() { var dotNetObjRef = DotNetObjectReference.Create(this); await JSRuntime.InvokeVoidAsync("jsFunctions.showMouseCoordinates", dotNetObjRef); } [JSInvokable] public void ShowCoordinates(MouseCoordinates coordinates) { _coordinates = coordinates; StateHasChanged(); } } public class MouseCoordinates { public int X { get; set; } public int Y { get; set; } }
Here, we create another MouseCoordinates
class with the X
and Y
properties. We are keeping it in the same file due to the sake of simplicity.
Then in the main class, we create the MouseCoordinates
instance and create the ShowCoordinates
method which accepts the coordinates
parameter from the JavaScript function. We can see that this function has the [JSInvokable]
attribute. Also in this method, we initialize our _coordinates
object and call the StateHasChanged
method to rerender our component.
HTML Markup
Finally, let’s add the required HTML markup:
<div class="row"> <div class="col-md-4"> <h4>Calling instance method from JS </h4> </div> <div class="col-md-2"> <button type="button" class="btn btn-success" @onclick="SendDotNetInstanceToJS"> Send Instance </button> </div> <div class="col-md-4"> <p id="coordinates" style="height: 200px; width: 400px; background-color: #d6d8d6; text-align:center; font-size:20px;"> @_coordinates.X - @_coordinates.Y </p> </div> </div>
So, once we click the Send Instance
button, we are going to call the SendDotNetInstanceToJS
method from our C# class. That method is going to create DotNetObjectReference
instance and send it to the JS function. In the JS function, we create an object with two (X, Y) properties, and we call the ShowCoordinates
method passing that object. Finally, this method initializes the _coordinates
object that we use to show the X
and Y
coordinates on the screen:
Also, you can click anywhere on the button and different values will be displayed in the gray box.
But let’s improve this solution a bit.
Improving Solution
What we want is to send the instance to the JS function by clicking the Send Instance
button, but also to be able to move our mouse inside the gray box and see different coordinate values.
To do that, we have to modify the showMouseCoordinates
function in the JS file:
jsFunctions.registerMouseCoordinatesHandler = function (dotNetObjRef) { function mouseCoordinatesHandler() { dotNetObjRef.invokeMethodAsync("ShowCoordinates", { x: window.event.screenX, y: window.event.screenY } ); }; mouseCoordinatesHandler(); document.getElementById("coordinates").onmousemove = mouseCoordinatesHandler; }
Now we have the registerMouseCoordinatesHandler
function that accepts the dotNetObjRef
parameter. In this function, we have another function that is almost the same as the one we had previously, just with a new name mouseCoordinatesHandler
and without a parameter. Then, we call this mouseCoordinatesHandler
function once to show the coordinates right away. After that, we attach the onmousemove
event handler to the gray box. This onmousemove
event handler will trigger the mouseCoordinatesHandler
function every time our mouse move.
Now, all we have to do is to go back to the class file and modify the SendDotNetInstanceToJS
method, to call a different JS function:
private async Task SendDotNetInstanceToJS() { var dotNetObjRef = DotNetObjectReference.Create(this); await JSRuntime.InvokeVoidAsync("jsFunctions.registerMouseCoordinatesHandler", dotNetObjRef); }
At this point, we can start our application and navigate to the component. As soon as we click the Send Instance button, we are going to see the coordinates in the gray box. But also, as soon as we hover over the gray box with our mouse, the coordinates will start to change. We can move the pointer inside the gray box to see different coordinate values:
Excellent.
Conclusion
So, there you go.
We have learned how to call static C# methods from JavaScript and also how to do the same but with the instance methods. Also, we have learned how to change identifiers for our methods if we want to overload some of them.
In the next article, we are going to learn how to use JSInterop in Razor Class Libraries and how to use browser functionalities.
So, see you there.