Fixing Silent Failures in Blazor: Properly Including JavaScript Files

JavaScript interop is a powerful feature in Blazor that bridges the gap between C# and JavaScript. However, a subtle misstep in script file inclusion can lead to frustrating debugging sessions where everything compiles but fails silently at runtime and somewhat confusion documentation can make debugging time consuming. In this post, I'll explain why this happens, particularly with Visual Studio’s misleading ~/ suggestion, and how to fix it.

Blazor empowers developers to write interactive web applications entirely in C#. However, certain scenarios—such as some fine-grained control over DOM events—still require JavaScript. This is where interop comes in, enabling seamless integration between C# and JavaScript.

TL;DR

When including JavaScript files in Blazor, use this:

<script src="jsinterop.js"></script>

Not this:

<script src="~/jsinterop.js"></script>

What is JavaScript Interop

I was assisting an engineer at a client site who had run into an issue with using JavaScript interop with Blazor. The error was a bit strange to a relatively new Blazor user, there was no error message, and the help on the topic was contradictory. In Blazor, Microsoft’s .NET framework for building interactive web UIs, interop allows C# code to call JavaScript functions and vice versa.

This client application was built using C# and Blazor with a limited amount of JavaScript. The use of interop between C# and JavaScript was being used in this application to interrupt a call to the server and prevent a page component from performing error checks and re-rendering.

Example call JavaScript from C# razor:

The two parameters for InvokeVoidAsync:

  1. String identifier – which is the function name in the interop file; jsinterop.js (see below)

  2. Parameter – the form-id. specifies the JavaScript function and the form it should target.

Interop file – jsinterop.js contains the JavaScript functions needed for interop. This file is accessed globally and should be placed in wwwroot with all other static content. There is an event listener added to the JavaScript function defining when it should fire.

The Role of App.razor

The App.razor file in Blazor plays a key role in defining the structure and behavior of a Blazor application. It essentially serves as the root component for the Single Page Application (SPA) and is responsible for orchestrating the app's routing and layout. Any global scripts required for interop must be included here to ensure they're available across all components. If the JavaScript functionality is needed throughout the application, placing the <script> tag in App.razor ensures it is loaded globally.

The issue in App.razor & The Fix:

The issue arises in the updating of the App.razor file.

In traditional ASP.NET applications, ~/ resolves paths relative to the application root on the server. However, Blazor runs on the client (either via WebAssembly or SignalR), where the browser doesn’t recognize ~/. As a result, the script file isn’t properly loaded.

In .NET 8 the developer must manually update this file. In Visual Studio Intellisense will recommend the src file name as; ~/jsinterop.js and in addition Google’s AI Overview Search will either be silent on the topic or suggest the same incorrect path as IntelliSense. Microsoft’s documentation can be confusing on this topic.

The application will compile and run but will not work as desired. The function will not fire and the page render would not be blocked.  This is because the App.razor file must be updated as below without the “~/”:

<script src=”jsinterop.js”></script>

Adding <script src="jsinterop.js"></script> ensures that Blazor can access JavaScript functions defined in jsinterop.js via interop. This explicit inclusion gives developers fine-grained control over which scripts are loaded and when, aligning with Blazor's lightweight and modular approach. Placing the script in App.razor ensures it is globally available in the Blazor component hierarchy.

While this may not be a highly technical issue, understanding it can save you valuable time debugging and help ensure your Blazor app runs smoothly.

Next
Next

AI Agent Based Implementation of “Cobots” in Healthcare Office Administration: A Cloud-Native Solution using Microsoft Technologies