--- title: Call .NET methods from JavaScript functions in ASP.NET Core Blazor author: guardrex description: Learn how to invoke .NET methods from JavaScript functions in Blazor apps. monikerRange: '>= aspnetcore-3.1' ms.author: riande ms.custom: mvc ms.date: 08/12/2020 no-loc: ["ASP.NET Core Identity", cookie, Cookie, Blazor, "Blazor Server", "Blazor WebAssembly", "Identity", "Let's Encrypt", Razor, SignalR] uid: blazor/call-dotnet-from-javascript --- # Call .NET methods from JavaScript functions in ASP.NET Core Blazor By [Javier Calvarro Nelson](https://github.com/javiercn), [Daniel Roth](https://github.com/danroth27), [Shashikant Rudrawadi](http://wisne.co), and [Luke Latham](https://github.com/guardrex) A Blazor app can invoke JavaScript functions from .NET methods and .NET methods from JavaScript functions. These scenarios are called *JavaScript interoperability* (*JS interop*). This article covers invoking .NET methods from JavaScript. For information on how to call JavaScript functions from .NET, see . [View or download sample code](https://github.com/dotnet/AspNetCore.Docs/tree/master/aspnetcore/blazor/common/samples/) ([how to download](xref:index#how-to-download-a-sample)) ## Static .NET method call To invoke a static .NET method from JavaScript, use the `DotNet.invokeMethod` or `DotNet.invokeMethodAsync` functions. Pass in the identifier of the static method you wish to call, the name of the assembly containing the function, and any arguments. The asynchronous version is preferred to support Blazor Server scenarios. The .NET method must be public, static, and have the [`[JSInvokable]`](xref:Microsoft.JSInterop.JSInvokableAttribute) attribute. Calling open generic methods isn't currently supported. The sample app includes a C# method to return an `int` array. The [`[JSInvokable]`](xref:Microsoft.JSInterop.JSInvokableAttribute) attribute is applied to the method. `Pages/JsInterop.razor`: ```razor @code { [JSInvokable] public static Task ReturnArrayAsync() { return Task.FromResult(new int[] { 1, 2, 3 }); } } ``` JavaScript served to the client invokes the C# .NET method. `wwwroot/exampleJsInterop.js`: [!code-javascript[](./common/samples/3.x/BlazorWebAssemblySample/wwwroot/exampleJsInterop.js?highlight=8-14)] When the **`Trigger .NET static method ReturnArrayAsync`** button is selected, examine the console output in the browser's web developer tools. The console output is: ```console Array(4) [ 1, 2, 3, 4 ] ``` The fourth array value is pushed to the array (`data.push(4);`) returned by `ReturnArrayAsync`. By default, the method identifier is the method name, but you can specify a different identifier using the [`[JSInvokable]`](xref:Microsoft.JSInterop.JSInvokableAttribute) attribute constructor: ```csharp @code { [JSInvokable("DifferentMethodName")] public static Task ReturnArrayAsync() { return Task.FromResult(new int[] { 1, 2, 3 }); } } ``` In the client-side JavaScript file: ```javascript returnArrayAsyncJs: function () { DotNet.invokeMethodAsync('{APP ASSEMBLY}', 'DifferentMethodName') .then(data => { data.push(4); console.log(data); }); } ``` The placeholder `{APP ASSEMBLY}` is the app's app assembly name (for example, `BlazorSample`). ## Instance method call You can also call .NET instance methods from JavaScript. To invoke a .NET instance method from JavaScript: * Pass the .NET instance by reference to JavaScript: * Make a static call to . * Wrap the instance in a instance and call on the instance. Dispose of objects (an example appears later in this section). * Invoke .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. > [!NOTE] > The sample app logs messages to the client-side console. For the following examples demonstrated by the sample app, examine the browser's console output in the browser's developer tools. When the **`Trigger .NET instance method HelloHelper.SayHello`** button is selected, `ExampleJsInterop.CallHelloHelperSayHello` is called and passes a name, `Blazor`, to the method. `Pages/JsInterop.razor`: ```razor @code { public async Task TriggerNetInstanceMethod() { var exampleJsInterop = new ExampleJsInterop(JSRuntime); await exampleJsInterop.CallHelloHelperSayHello("Blazor"); } } ``` `CallHelloHelperSayHello` invokes the JavaScript function `sayHello` with a new instance of `HelloHelper`. `JsInteropClasses/ExampleJsInterop.cs`: [!code-csharp[](./common/samples/3.x/BlazorWebAssemblySample/JsInteropClasses/ExampleJsInterop.cs?name=snippet1&highlight=11-18)] `wwwroot/exampleJsInterop.js`: [!code-javascript[](./common/samples/3.x/BlazorWebAssemblySample/wwwroot/exampleJsInterop.js?highlight=15-18)] The name is passed to `HelloHelper`'s constructor, which sets the `HelloHelper.Name` property. When the JavaScript function `sayHello` is executed, `HelloHelper.SayHello` returns the `Hello, {Name}!` message, which is written to the console by the JavaScript function. `JsInteropClasses/HelloHelper.cs`: [!code-csharp[](./common/samples/3.x/BlazorWebAssemblySample/JsInteropClasses/HelloHelper.cs?name=snippet1&highlight=5,10-11)] Console output in the browser's web developer tools: ```console Hello, Blazor! ``` To avoid a memory leak and allow garbage collection on a component that creates a , adopt one of the following approaches: * Dispose of the object in the class that created the instance: ```csharp public class ExampleJsInterop : IDisposable { private readonly IJSRuntime jsRuntime; private DotNetObjectReference objRef; public ExampleJsInterop(IJSRuntime jsRuntime) { this.jsRuntime = jsRuntime; } public ValueTask CallHelloHelperSayHello(string name) { objRef = DotNetObjectReference.Create(new HelloHelper(name)); return jsRuntime.InvokeAsync( "exampleJsFunctions.sayHello", objRef); } public void Dispose() { objRef?.Dispose(); } } ``` The preceding pattern shown in the `ExampleJsInterop` class can also be implemented in a component: ```razor @page "/JSInteropComponent" @using {APP ASSEMBLY}.JsInteropClasses @implements IDisposable @inject IJSRuntime JSRuntime

JavaScript Interop

@code { private DotNetObjectReference objRef; public async Task TriggerNetInstanceMethod() { objRef = DotNetObjectReference.Create(new HelloHelper("Blazor")); await JSRuntime.InvokeAsync( "exampleJsFunctions.sayHello", objRef); } public void Dispose() { objRef?.Dispose(); } } ``` The placeholder `{APP ASSEMBLY}` is the app's app assembly name (for example, `BlazorSample`). * When the component or class doesn't dispose of the , dispose of the object on the client by calling `.dispose()`: ```javascript window.myFunction = (dotnetHelper) => { dotnetHelper.invokeMethodAsync('{APP ASSEMBLY}', 'MyMethod'); dotnetHelper.dispose(); } ``` ## Component instance method call To invoke a component's .NET methods: * Use the `invokeMethod` or `invokeMethodAsync` function to make a static method call to the component. * The component's static method wraps the call to its instance method as an invoked . > [!NOTE] > For Blazor Server apps, where several users might be concurrently using the same component, use a helper class to invoke instance methods. > > For more information, see the [Component instance method helper class](#component-instance-method-helper-class) section. In the client-side JavaScript: ```javascript function updateMessageCallerJS() { DotNet.invokeMethodAsync('{APP ASSEMBLY}', 'UpdateMessageCaller'); } ``` The placeholder `{APP ASSEMBLY}` is the app's app assembly name (for example, `BlazorSample`). `Pages/JSInteropComponent.razor`: ```razor @page "/JSInteropComponent"

Message: @message

@code { private static Action action; private string message = "Select the button."; protected override void OnInitialized() { action = UpdateMessage; } private void UpdateMessage() { message = "UpdateMessage Called!"; StateHasChanged(); } [JSInvokable] public static void UpdateMessageCaller() { action.Invoke(); } } ``` To pass arguments to the instance method: * Add parameters to the JS method invocation. In the following example, a name is passed to the method. Additional parameters can be added to the list as needed. ```javascript function updateMessageCallerJS(name) { DotNet.invokeMethodAsync('{APP ASSEMBLY}', 'UpdateMessageCaller', name); } ``` The placeholder `{APP ASSEMBLY}` is the app's app assembly name (for example, `BlazorSample`). * Provide the correct types to the for the parameters. Provide the parameter list to the C# methods. Invoke the (`UpdateMessage`) with the parameters (`action.Invoke(name)`). `Pages/JSInteropComponent.razor`: ```razor @page "/JSInteropComponent"

Message: @message

@code { private static Action action; private string message = "Select the button."; protected override void OnInitialized() { action = UpdateMessage; } private void UpdateMessage(string name) { message = $"{name}, UpdateMessage Called!"; StateHasChanged(); } [JSInvokable] public static void UpdateMessageCaller(string name) { action.Invoke(name); } } ``` Output `message` when the **Call JS Method** button is selected: ``` Sarah Jane, UpdateMessage Called! ``` ## Component instance method helper class The helper class is used to invoke an instance method as an . Helper classes are useful when: * Several components of the same type are rendered on the same page. * A Blazor Server app is used, where multiple users might be using a component concurrently. In the following example: * The `JSInteropExample` component contains several `ListItem` components. * Each `ListItem` component is composed of a message and a button. * When a `ListItem` component button is selected, that `ListItem`'s `UpdateMessage` method changes the list item text and hides the button. `MessageUpdateInvokeHelper.cs`: ```csharp using System; using Microsoft.JSInterop; public class MessageUpdateInvokeHelper { private Action action; public MessageUpdateInvokeHelper(Action action) { this.action = action; } [JSInvokable("{APP ASSEMBLY}")] public void UpdateMessageCaller() { action.Invoke(); } } ``` The placeholder `{APP ASSEMBLY}` is the app's app assembly name (for example, `BlazorSample`). In the client-side JavaScript: ```javascript window.updateMessageCallerJS = (dotnetHelper) => { dotnetHelper.invokeMethodAsync('{APP ASSEMBLY}', 'UpdateMessageCaller'); dotnetHelper.dispose(); } ``` The placeholder `{APP ASSEMBLY}` is the app's app assembly name (for example, `BlazorSample`). `Shared/ListItem.razor`: ```razor @inject IJSRuntime JsRuntime
  • @message
  • @code { private string message = "Select one of these list item buttons."; private string display = "inline-block"; private MessageUpdateInvokeHelper messageUpdateInvokeHelper; protected override void OnInitialized() { messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage); } protected async Task InteropCall() { await JsRuntime.InvokeVoidAsync("updateMessageCallerJS", DotNetObjectReference.Create(messageUpdateInvokeHelper)); } private void UpdateMessage() { message = "UpdateMessage Called!"; display = "none"; StateHasChanged(); } } ``` `Pages/JSInteropExample.razor`: ```razor @page "/JSInteropExample"

    List of components

    ``` [!INCLUDE[Share interop code in a class library](~/includes/blazor-share-interop-code.md)] ## Avoid circular object references Objects that contain circular references can't be serialized on the client for either: * .NET method calls. * JavaScript method calls from C# when the return type has circular references. For more information, see the following issues: * [Circular references are not supported, take two (dotnet/aspnetcore #20525)](https://github.com/dotnet/aspnetcore/issues/20525) * [Proposal: Add mechanism to handle circular references when serializing (dotnet/runtime #30820)](https://github.com/dotnet/runtime/issues/30820) ## Additional resources * * [`InteropComponent.razor` example (dotnet/AspNetCore GitHub repository, 3.1 release branch)](https://github.com/dotnet/AspNetCore/blob/release/3.1/src/Components/test/testassets/BasicTestApp/InteropComponent.razor) * [Perform large data transfers in Blazor Server apps](xref:blazor/advanced-scenarios#perform-large-data-transfers-in-blazor-server-apps)