I ran into an issue recently where I needed to call some C# code from JavaScript. The Microsoft documentation on JavaScript to .NET interop is very detailed and covers a lot of scenarios including the one that would seem to fit the bill (invoking instance methods), but my requirements meant that I couldn’t use this exact approach.
In the example code the JavaScript isn’t being called directly; it’s .NET calling JavaScript which in turn calls the .NET method you want. The reason for this somewhat circular approach is that we need to pass an instance of our current .NET class to the JavaScript so that it can act upon it and call non-static methods. As such, the steps in the example are:
- Click the button, calling a C# method (
TriggerDotNetInstanceMethod
) - In
TriggerDotNetInstanceMethod
:- Bundle up the class using
DotNetObjectReference.Create(this)
- Send the bundled class instance through to the JavaScript function using
InvokeAsync
- Bundle up the class using
- On the JavaScript side, receive the class instance as a parameter and use it to call the C# method (optionally passing parameters as well)
This works well for a situation where you’re in control of that initial call (such as with a button press) and it does allow you to call .NET methods from JavaScript, but if you’re trying to provide a callback to a 3rd party JS library or have another reason that you can’t call the JavaScript from .NET first the above approach won’t work as outlined since you can’t grab the class instance directly from JavaScript.
Thankfully there is a way to resolve this!
Approach
I’ve put together a demo solution that shows this approach in action! The code is based on the Microsoft documentation on JavaScript to .NET interop with some tweaks.
In order to call the JavaScript directly without having to kick it off from C# first, we’ll need to modify the Microsoft example by breaking it into two discrete steps; bundling/sending the class instance and invoking a method on it.
Bring on the code!
Setting the Class Instance
Step 1 is to pass the class instance to JavaScript since we’ll need access to it later. To do this we need to add calling code in the Blazor page and a JavaScript function to accept and store the instance.
Here we have the code-behind file Index.razor.cs
:
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
namespace InvokeDotNETInstanceMethodFromJavaScript.Pages;
public partial class Index: IDisposable
{
[Inject] private IJSRuntime? JsRuntime { get; set; }
private DotNetObjectReference<Index>? _objRef;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await BundleAndSendDotNetHelper();
await base.OnAfterRenderAsync(firstRender);
}
private async Task BundleAndSendDotNetHelper()
{
_objRef = DotNetObjectReference.Create(this);
if (JsRuntime != null)
{
await JsRuntime.InvokeAsync<string>("SetDotNetHelper", _objRef);
}
}
public void Dispose()
{
_objRef?.Dispose();
}
}
When the page calls OnAfterRenderAsync
as part of the render lifecycle it invokes BundleAndSendDotNetHelper
. This method has two statements: the first creates _objRef
by rolling up the current class instance, while the second calls a JavaScript function called SetDotNetHelper
using InvokeAsync
and passes in that class instance. SetDotNetHelper
is stored in a file called BlazorInterop.js
and referenced in _Layout.cshtml
so we have access to it across the app:
function SetDotNetHelper(dotNetHelper) {
window.dotNetHelper = dotNetHelper;
}
This takes the class instance we’ve passed from C# and stores it as a global variable for later retrieval and use!
Invoking the Method
So we’ve done the setup, how do we go about actually invoking it?
Let’s first add a button to Index.razor
so we can fire off a JavaScript function:
<button onclick="CallBlazorMethod()">Call JavaScript Function</button>
Since CallBlazorMethod
isn’t declared yet, we’ll need to add that to our new BlazorInterop.js
file:
function CallBlazorMethod()
{
window.dotNetHelper.invokeMethodAsync('BlazorMethod');
}
This grabs the global dotNetHelper
instance we stored earlier (by referencing it with window.dotNetHelper
) and invokes a method on it called BlazorMethod
. We’ll need to add this to our Index.razor.cs
:
private int _currentNumber;
[JSInvokable]
public void BlazorMethod()
{
_currentNumber++;
StateHasChanged();
}
Here we can see the JSInvokable
attribute which is the magic that allows JavaScript to invoke the method (hence the name)!
I’ve also added an integer so that we can increment and display it on Index.razor
:
<p>The number is currently set to: @_currentNumber</p>
And that’s it!

Review
Let’s take a high level view of what we’ve got set up now:
OnAfterRenderAsync
inIndex.razor.cs
calls the C# methodBundleAndSendDotNetHelper
as part of the render lifecycleBundleAndSendDotNetHelper
bundles the current class instance and sends it through to the JavaScript functionSetDotNetHelper
SetDotNetHelper
takes the class instance and stores it globally so that we can access it later- The JavaScript function
CallBlazorMethod
is invoked (from a button press, a callback etc), which grabs the globaldotNetHelper
instance and calls the .NET methodBlazorMethod
on it BlazorMethod
increments the_currentNumber
variable and callsStateHasChanged
to trigger a re-render of the page
Conclusion
Calling .NET instance methods from JavaScript can take a bit of setup, but once configured it works pretty seamlessly! I still prefer to keep the page/business logic in the land of .NET as far as possible since it promotes code re-use and allows for more type safety, but for those situations where you can’t keep it all in one place this approach (or the other approaches listed in the Microsoft documentation for JavaScript to .NET interop) should fit the bill!