Llamada a métodos de .NET desde funciones de JavaScript en ASP.NET Core Blazor
En este artículo se describe cómo invocar métodos de .NET desde JavaScript (JS). Para obtener información sobre cómo llamar a funciones de JS desde .NET, consulte Llamada a funciones de JavaScript con métodos de .NET en Blazor de ASP.NET Core.
Invocación de un método de .NET estático
Para invocar un método de .NET estático desde JavaScript (JS), use las funciones DotNet.invokeMethod o DotNet.invokeMethodAsync de JS. Pase el nombre del ensamblado que contiene el método, el identificador del método estático de .NET y cualquier argumento.
En el ejemplo siguiente:
- El marcador de posición
{ASSEMBLY NAME}es el nombre de ensamblado de la aplicación. - El marcador de posición
{.NET METHOD ID}es el identificador del método de .NET. - El marcador de posición
{ARGUMENTS}son argumentos opcionales separados por comas que se pasan al método , y cada uno de ellos debe ser serializable con JSON.
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS});
DotNet.invokeMethod devuelve el resultado de la operación. DotNet.invokeMethodAsync devuelve un JS Promise que representa el resultado de la operación.
La función asincrónica (invokeMethodAsync) se prefiere a la versión sincrónica (invokeMethod) para admitir escenarios de Blazor Server.
El método de .NET debe ser público y estático, y debe tener el atributo [JSInvokable].
En el ejemplo siguiente:
- El marcador de posición
{<T>}indica el tipo de valor devuelto, que solo es necesario para los métodos que devuelven un valor. - El marcador de posición
{.NET METHOD ID}es el identificador del método.
@code {
[JSInvokable]
public static Task{<T>} {.NET METHOD ID}()
{
...
}
}
La llamada a métodos genéricos abiertos no se admite con métodos estáticos de .NET, pero se admite con métodos de instancia, que se describen más adelante en este artículo.
En el componente CallDotNetExample1 siguiente, el método de C# ReturnArrayAsync devuelve una matriz int. El atributo [JSInvokable] se aplica al método, lo que hace que el método sea invocable por JS.
Pages/CallDotNetExample1.razor:
@page "/call-dotnet-example-1"
<h1>Call .NET Example 1</h1>
<p>
<button onclick="returnArrayAsync()">
Trigger .NET static method
</button>
</p>
@code {
[JSInvokable]
public static Task<int[]> ReturnArrayAsync()
{
return Task.FromResult(new int[] { 1, 2, 3 });
}
}
El atributo HTML onclick del elemento <button> es la asignación del controlador de eventos onclick de JavaScript para procesar eventos click, y no el atributo de directiva @onclick de Blazor. La función returnArrayAsync de JS se asigna como controlador.
La siguiente función returnArrayAsync de JS llama al método de .NET ReturnArrayAsync del componente CallDotNetExample1 anterior y registra el resultado en la consola de herramientas para desarrolladores web del explorador. BlazorSample es el nombre del ensamblado de la aplicación.
Dentro de la etiqueta </body> de cierre de wwwroot/index.html (Blazor WebAssembly) o Pages/_Layout.cshtml (Blazor Server):
<script>
window.returnArrayAsync = () => {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
.then(data => {
console.log(data);
});
};
</script>
Cuando se selecciona el botón Trigger .NET static method , la salida de la consola de las herramientas de desarrollo del explorador muestra los datos de la matriz. El formato de la salida difiere ligeramente entre los exploradores. En la salida siguiente se muestra el formato utilizado por Microsoft Edge:
Array(3) [ 1, 2, 3 ]
De forma predeterminada, el identificador de método de .NET para la llamada de JS es el nombre del método de .NET, pero puede especificar un identificador distinto mediante el constructor del atributo [JSInvokable]. En el ejemplo siguiente, DifferentMethodName es el identificador del método asignado para el método ReturnArrayAsync:
[JSInvokable("DifferentMethodName")]
En la llamada a DotNet.invokeMethod o DotNet.invokeMethodAsync, llame a DifferentMethodName para ejecutar el método de .NET ReturnArrayAsync:
DotNet.invokeMethod('BlazorSample', 'DifferentMethodName');DotNet.invokeMethodAsync('BlazorSample', 'DifferentMethodName');
Nota
El ejemplo de método ReturnArrayAsync de esta sección devuelve el resultado de un Task sin el uso de las palabras clave async y await de C# explícitas. La codificación de métodos con async y await es típica de los métodos que usan la palabra clave await para devolver el valor de las operaciones asincrónicas.
El método ReturnArrayAsync compuesto con las palabras clave async y await:
[JSInvokable]
public static async Task<int[]> ReturnArrayAsync()
{
return await Task.FromResult(new int[] { 1, 2, 3 });
}
Para obtener más información, vea Programación asincrónica con async y await en la guía de C#.
Invocación de un método de .NET de instancia
Para invocar un método de .NET de instancia desde JavaScript (JS):
- Pase la instancia de .NET por referencia a JS encapsulando la instancia en un DotNetObjectReference y llamando a Create en ella.
- Invoque un método de instancia de .NET desde JS mediante
invokeMethodoinvokeMethodAsyncdesde la clase DotNetObjectReference pasada. La instancia de .NET también se puede pasar como argumento al invocar otros métodos de .NET desde JS. - Deseche DotNetObjectReference.
Ejemplos de instancias de componente
La función sayHello1 de JS siguiente recibe DotNetObjectReference y llama a invokeMethodAsync para invocar el método de .NET GetHelloMethod de un componente.
Dentro de la etiqueta </body> de cierre de wwwroot/index.html (Blazor WebAssembly) o Pages/_Layout.cshtml (Blazor Server):
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
Para el componente CallDotNetExample2 siguiente:
- El componente tiene un método de .NET invocable por JS llamado
GetHelloMessage. - Cuando se selecciona el botón
Trigger .NET instance method, se llama a la funciónsayHello1de JS con DotNetObjectReference. sayHello1:- Llama a
GetHelloMessagey recibe el resultado del mensaje. - Devuelve el resultado del mensaje al método
TriggerDotNetInstanceMethodque realiza la llamada.
- Llama a
- El mensaje devuelto de
sayHello1enresultse muestra al usuario. - Para evitar una pérdida de memoria y permitir la recolección de elementos no utilizados, la referencia de objeto de .NET creada por DotNetObjectReference se elimina en el método
Dispose.
Pages/CallDotNetExample2.razor:
@page "/call-dotnet-example-2"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 2</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<CallDotNetExample2>? objRef;
public async Task TriggerDotNetInstanceMethod()
{
objRef = DotNetObjectReference.Create(this);
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
public void Dispose()
{
objRef?.Dispose();
}
}
Para pasar argumentos al método de instancia:
Agregue parámetros a la invocación del método de .NET. En el ejemplo siguiente, se pasa un nombre al método. Agregue parámetros adicionales a la lista según sea necesario.
<script> window.sayHello2 = (dotNetHelper, name) => { return dotNetHelper.invokeMethodAsync('GetHelloMessage', name); }; </script>Proporcione la lista de parámetros al método de .NET.
Pages/CallDotNetExample3.razor:@page "/call-dotnet-example-3" @implements IDisposable @inject IJSRuntime JS <h1>Call .NET Example 3</h1> <p> <label> Name: <input @bind="name" /> </label> </p> <p> <button @onclick="TriggerDotNetInstanceMethod"> Trigger .NET instance method </button> </p> <p> @result </p> @code { private string? name; private string? result; private DotNetObjectReference<CallDotNetExample3>? objRef; public async Task TriggerDotNetInstanceMethod() { objRef = DotNetObjectReference.Create(this); result = await JS.InvokeAsync<string>("sayHello2", objRef, name); } [JSInvokable] public string GetHelloMessage(string passedName) => $"Hello, {passedName}!"; public void Dispose() { objRef?.Dispose(); } }
Ejemplos de instancias de clase
La siguiente función sayHello1 de JS:
- Llama al método de .NET
GetHelloMessageen la clase DotNetObjectReference pasada. - Devuelve el mensaje de
GetHelloMessageal autor de la llamadasayHello1.
Dentro de la etiqueta </body> de cierre de wwwroot/index.html (Blazor WebAssembly) o Pages/_Layout.cshtml (Blazor Server):
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
La clase HelloHelper siguiente tiene un método de .NET invocable por JS llamado GetHelloMessage. Cuando se crea HelloHelper, el nombre de la propiedad Name se usa para devolver un mensaje de GetHelloMessage.
HelloHelper.cs:
using Microsoft.JSInterop;
public class HelloHelper
{
public HelloHelper(string? name)
{
Name = name ?? "No Name";
}
public string? Name { get; set; }
[JSInvokable]
public string GetHelloMessage() => $"Hello, {Name}!";
}
El método CallHelloHelperGetHelloMessage de la clase JsInteropClasses3 siguiente invoca la función sayHello1 de JS con una nueva instancia de HelloHelper.
JsInteropClasses3.cs:
using System;
using System.Threading.Tasks;
using Microsoft.JSInterop;
public class JsInteropClasses3 : IDisposable
{
private readonly IJSRuntime js;
private DotNetObjectReference<HelloHelper>? objRef;
public JsInteropClasses3(IJSRuntime js)
{
this.js = js;
}
public ValueTask<string> CallHelloHelperGetHelloMessage(string? name)
{
objRef = DotNetObjectReference.Create(new HelloHelper(name));
return js.InvokeAsync<string>("sayHello1", objRef);
}
public void Dispose()
{
objRef?.Dispose();
}
}
Para evitar una pérdida de memoria y permitir la recolección de elementos no utilizados, la referencia de objeto de .NET creada por DotNetObjectReference se elimina en el método Dispose.
Cuando se selecciona el botón Trigger .NET instance method en el componente CallDotNetExample4 siguiente, se llama a JsInteropClasses3.CallHelloHelperGetHelloMessage con el valor de name.
Pages/CallDotNetExample4.razor:
@page "/call-dotnet-example-4"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 4</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private JsInteropClasses3? jsInteropClasses;
private async Task TriggerDotNetInstanceMethod()
{
jsInteropClasses = new JsInteropClasses3(JS);
result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
}
public void Dispose()
{
jsInteropClasses?.Dispose();
}
}
En la imagen siguiente se muestra el componente representado con el nombre Amy Pond en el campo Name. Una vez seleccionado el botón, Hello, Amy Pond! se muestra en la interfaz de usuario:

El patrón anterior que se muestra en la clase JsInteropClasses3 también se puede implementar íntegramente en un componente.
Pages/CallDotNetExample5.razor:
@page "/call-dotnet-example-5"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 5</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string? name;
private string? result;
private DotNetObjectReference<HelloHelper>? objRef;
public async Task TriggerDotNetInstanceMethod()
{
objRef = DotNetObjectReference.Create(new HelloHelper(name));
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
public void Dispose()
{
objRef?.Dispose();
}
}
Para evitar una pérdida de memoria y permitir la recolección de elementos no utilizados, la referencia de objeto de .NET creada por DotNetObjectReference se elimina en el método Dispose.
La salida mostrada por el componente CallDotNetExample5 es Hello, Amy Pond! cuando el nombre Amy Pond se proporciona en el campo Name.
En el componente CallDotNetExample5 anterior, se elimina la referencia al objeto de .NET. Si una clase o un componente no elimina DotNetObjectReference, deséchelo del cliente llamando a dispose en la clase DotNetObjectReference pasada:
window.jsFunction = (dotnetHelper) => {
dotnetHelper.invokeMethodAsync('{ASSEMBLY NAME}', '{.NET METHOD ID}');
dotnetHelper.dispose();
}
En el ejemplo anterior:
- El marcador de posición
{ASSEMBLY NAME}es el nombre de ensamblado de la aplicación. - El marcador de posición
{.NET METHOD ID}es el identificador del método de .NET.
Clase auxiliar del método de .NET de la instancia de componente
Una clase auxiliar puede invocar un método de instancia de .NET como Action. Las clases auxiliares son útiles en los siguientes escenarios:
- Cuando se representan varios componentes del mismo tipo en la misma página.
- En una aplicación de Blazor Server, donde varios usuarios usan simultáneamente el mismo componente.
En el ejemplo siguiente:
- El componente
CallDotNetExample6contiene varios componentesListItem, que es un componente compartido en la carpetaSharedde la aplicación. - Cada componente
ListItemconsta de un mensaje y un botón. - Cuando se selecciona un botón de componente
ListItem, el métodoUpdateMessagede ese objetoListItemcambia el texto del elemento de lista y oculta el botón.
La clase MessageUpdateInvokeHelper siguiente mantiene un método de .NET invocable por JS, UpdateMessageCaller, para invocar el elemento Action especificado cuando se crea una instancia de la clase. BlazorSample es el nombre del ensamblado de la aplicación.
MessageUpdateInvokeHelper.cs:
using System;
using Microsoft.JSInterop;
public class MessageUpdateInvokeHelper
{
private Action action;
public MessageUpdateInvokeHelper(Action action)
{
this.action = action;
}
[JSInvokable("BlazorSample")]
public void UpdateMessageCaller()
{
action.Invoke();
}
}
La función updateMessageCaller de JS siguiente invoca el método de .NET UpdateMessageCaller. BlazorSample es el nombre del ensamblado de la aplicación.
Dentro de la etiqueta </body> de cierre de wwwroot/index.html (Blazor WebAssembly) o Pages/_Layout.cshtml (Blazor Server):
<script>
window.updateMessageCaller = (dotnetHelper) => {
dotnetHelper.invokeMethodAsync('BlazorSample', 'UpdateMessageCaller');
dotnetHelper.dispose();
}
</script>
El componente ListItem siguiente es un componente compartido que se puede usar varias veces en un componente primario y crea elementos de lista (<li>...</li>) para una lista HTML (<ul>...</ul> o <ol>...</ol>). Cada instancia de componente ListItem establece una instancia de MessageUpdateInvokeHelper con un elemento Action establecido en su método UpdateMessage.
Cuando se selecciona un botón InteropCall del componente ListItem, se invoca a updateMessageCaller con un elemento DotNetObjectReference creado para la instancia MessageUpdateInvokeHelper. Esto permite que el marco llame a UpdateMessageCaller en esa instancia MessageUpdateInvokeHelper de ListItem. La clase DotNetObjectReference pasada se elimina en JS (dotnetHelper.dispose()).
Shared/ListItem.razor:
@inject IJSRuntime JS
<li>
@message
<button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>
@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()
{
if (messageUpdateInvokeHelper is not null)
{
await JS.InvokeVoidAsync("updateMessageCaller",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
Se llama a StateHasChanged para actualizar la interfaz de usuario cuando message se establece en UpdateMessage. Si no se llama a StateHasChanged, Blazor no tiene ninguna manera de saber que la interfaz de usuario debe actualizarse cuando se invoca a Action.
El siguiente componente primario CallDotNetExample6 incluye cuatro elementos de lista, y cada uno de ellos es una instancia del componente ListItem.
Pages/CallDotNetExample6.razor:
@page "/call-dotnet-example-6"
<h1>Call .NET Example 6</h1>
<ul>
<ListItem />
<ListItem />
<ListItem />
<ListItem />
</ul>
En la imagen siguiente se muestra el componente primario CallDotNetExample6 representado después de seleccionar el segundo botón InteropCall :
- El segundo componente
ListItemha mostrado el mensajeUpdateMessage Called!. - El botón
InteropCalldel segundo componenteListItemno es visible porque la propiedaddisplayde CSS del botón está establecida ennone.

Ubicación de JavaScript
Cargue código de JavaScript (JS) mediante cualquiera de los enfoques descritos en el artículo de información general sobre interoperabilidad de JS:
- Cargar un script en el marcado
<head>(en general, no se recomienda) - Cargar un script en el marcado
<body> - Cargar un script desde un archivo JS externo (
.js) - Insertar un script después del inicio de Blazor
Para obtener información sobre cómo aislar scripts en los módulos JS, consulte la sección Aislamiento de JavaScript en módulos de JavaScript.
Advertencia
No coloque una etiqueta <script> en un archivo de componente (.razor), porque la etiqueta <script> no se puede actualizar dinámicamente.
Evitar referencias de objetos circulares
Los objetos que contienen referencias circulares no se pueden serializar en el cliente para:
- Llamadas de método .NET.
- Llamadas de método JavaScript desde C# cuando el tipo de valor devuelto tiene referencias circulares.
Compatibilidad con matrices de bytes
Blazor admite la interoperabilidad de JS de matriz de bytes optimizada que evita la codificación o descodificación de matrices de bytes en Base64. En el ejemplo siguiente se usa la interoperabilidad de JS para pasar una matriz de bytes a .NET.
Dentro de la etiqueta de cierre </body> de wwwroot/index.html (Blazor WebAssembly) o Pages/_Layout.cshtml (Blazor Server), proporciona una función de JS sendByteArray. Un botón del componente llama a la función y no devuelve un valor:
<script>
window.sendByteArray = () => {
const data = new Uint8Array([0x45,0x76,0x65,0x72,0x79,0x74,0x68,0x69,
0x6e,0x67,0x27,0x73,0x20,0x73,0x68,0x69,0x6e,0x79,0x2c,
0x20,0x43,0x61,0x70,0x74,0x69,0x61,0x6e,0x2e,0x20,0x4e,
0x6f,0x74,0x20,0x74,0x6f,0x20,0x66,0x72,0x65,0x74,0x2e]);
DotNet.invokeMethodAsync('BlazorSample', 'ReceiveByteArray', data)
.then(str => {
alert(str);
});
};
</script>
Pages/CallDotNetExample7.razor:
@page "/call-dotnet-example-7"
@using System.Text
<h1>Call .NET Example 7</h1>
<p>
<button onclick="sendByteArray()">Send Bytes</button>
</p>
<p>
Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>:
<a href="https://www.uphe.com/movies/serenity">Serenity</a><br>
<a href="https://www.imdb.com/name/nm0821612/">Jewel Staite on IMDB</a>
</p>
@code {
[JSInvokable]
public static Task<string> ReceiveByteArray(byte[] receivedBytes)
{
return Task.FromResult(
Encoding.UTF8.GetString(receivedBytes, 0, receivedBytes.Length));
}
}
Para obtener información sobre el uso de una matriz de bytes al llamar a JavaScript desde .NET, vea Llamada a funciones de JavaScript con métodos de .NET en Blazor de ASP.NET Core.
Transmisión de JavaScript a .NET
Blazor admite el streaming de datos directamente desde JavaScript a .NET. Los flujos se solicitan mediante la interfaz Microsoft.JSInterop.IJSStreamReference.
Microsoft.JSInterop.IJSStreamReference.OpenReadStreamAsync devuelve un objeto Stream y usa los siguientes parámetros:
maxAllowedSize: número máximo de bytes permitidos para la operación de lectura de JavaScript, cuyo valor predeterminado es 512 000 bytes si no se especifica.cancellationToken: un objeto CancellationToken para cancelar la lectura.
En JavaScript:
function streamToDotNet() {
return new Uint8Array(10000000);
}
En código de C#:
var dataReference =
await JS.InvokeAsync<IJSStreamReference>("streamToDotNet");
using var dataReferenceStream =
await dataReference.OpenReadStreamAsync(maxAllowedSize: 10_000_000);
var outputPath = Path.Combine(Path.GetTempPath(), "file.txt");
using var outputFileStream = File.OpenWrite(outputPath);
await dataReferenceStream.CopyToAsync(outputFileStream);
En el ejemplo anterior:
JSes una instancia de IJSRuntime insertada.dataReferenceStreamse escribe en el disco (file.txt) en la ruta de la carpeta temporal del usuario actual (GetTempPath).
Llamada a funciones de JavaScript con métodos de .NET en Blazor de ASP.NET Core trata la operación inversa, el streaming de .NET a JavaScript mediante DotNetStreamReference.
Cargas de archivos de ASP.NET Core Blazor describe cómo cargar un archivo en Blazor.
Límites de tamaño en las llamadas de interoperabilidad de JavaScript
This section only applies to Blazor Server apps. In Blazor WebAssembly, the framework doesn't impose a limit on the size of JavaScript (JS) interop inputs and outputs.
In Blazor Server, JS interop calls are limited in size by the maximum incoming SignalR message size permitted for hub methods, which is enforced by HubOptions.MaximumReceiveMessageSize (default: 32 KB). JS to .NET SignalR messages larger than MaximumReceiveMessageSize throw an error. The framework doesn't impose a limit on the size of a SignalR message from the hub to a client.
When SignalR logging isn't set to Debug or Trace, a message size error only appears in the browser's developer tools console:
Error: Connection disconnected with error 'Error: Server returned an error on close: Connection closed with an error.'.
When SignalR server-side logging is set to Debug or Trace, server-side logging surfaces an InvalidDataException for a message size error.
appsettings.Development.json:
{
"DetailedErrors": true,
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.AspNetCore.SignalR": "Debug"
}
}
}
Error:
System.IO.InvalidDataException: The maximum message size of 32768B was exceeded. The message size can be configured in AddHubOptions.
Increase the limit by setting MaximumReceiveMessageSize in Program.cs. The following example sets the maximum receive message size to 64 KB (64 * 1024) in ASP.NET Core 6.0 or later:
builder.Services.AddServerSideBlazor()
.AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024);
In Startup.ConfigureServices for versions of ASP.NET Core earlier than 6.0:
services.AddServerSideBlazor()
.AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024);
Increasing the SignalR incoming message size limit comes at the cost of requiring more server resources, and it exposes the server to increased risks from a malicious user. Additionally, reading a large amount of content in to memory as strings or byte arrays can also result in allocations that work poorly with the garbage collector, resulting in additional performance penalties.
Nota
Los enlaces de la documentación del origen de referencia de ASP.NET Core cargan la rama main del repositorio, que representa el desarrollo actual de la unidad de producto para la próxima versión de ASP.NET Core. Para seleccionar la rama de una versión diferente, use la lista desplegable Switch branches or tags (Cambiar ramas o etiquetas) para seleccionar la rama. Por ejemplo, seleccione la rama release/5.0 para la versión 5.0 de ASP.NET Core.
Consider the following guidance when developing code that transfers a large amount of data between JS and Blazor in Blazor Server apps:
- For ASP.NET Core 6.0 and newer:
- Leverage the native streaming interop support to transfer data larger than the SignalR incoming message size limit.
- For versions of ASP.NET Core earlier than 6.0:
- Slice the data into smaller pieces, and send the data segments sequentially as a Stream until all of the data is received by the server.
- Don't block the main UI thread for long periods when sending or receiving data.
- For an example that demonstrates sending large binary payloads in Blazor Server, see the Binary Submit sample app.
- General tips:
- Don't allocate large objects in JS and C# code.
- Free consumed memory when the process is completed or cancelled.
- Enforce the following additional requirements for security purposes:
- Declare the maximum file or data size that can be passed.
- Declare the minimum upload rate from the client to the server.
- After the data is received by the server, the data can be:
- Temporarily stored in a memory buffer until all of the segments are collected.
- Consumed immediately. For example, the data can be stored immediately in a database or written to disk as each segment is received.
Aislamiento de JavaScript en módulos de JavaScript
Blazor permite el aislamiento de JavaScript (JS) en módulos de JavaScript estándar (especificación de ECMAScript).
El aislamiento de JS proporciona las siguientes ventajas:
- El JS importado no contamina el espacio de nombres global.
- No es necesario que los consumidores de una biblioteca y los componentes importen el JS relacionado.
Para obtener más información, vea Llamada a funciones de JavaScript con métodos de .NET en Blazor de ASP.NET Core.
Recursos adicionales
- Llamada a funciones de JavaScript con métodos de .NET en Blazor de ASP.NET Core
- Ejemplo de
InteropComponent.razor(ramamaindel repositorio de GitHub dotnet/AspNetCore): la ramamainrepresenta el desarrollo actual de la unidad de producto para la próxima versión de ASP.NET Core. Para seleccionar la rama de una versión diferente (por ejemplo,release/5.0), use la lista desplegable Switch branches or tags (Cambiar ramas o etiquetas). - Interacción con Document Object Model (DOM)
En este artículo se describe cómo invocar métodos de .NET desde JavaScript (JS). Para obtener información sobre cómo llamar a funciones de JS desde .NET, consulte Llamada a funciones de JavaScript con métodos de .NET en Blazor de ASP.NET Core.
Invocación de un método de .NET estático
Para invocar un método de .NET estático desde JavaScript (JS), use las funciones DotNet.invokeMethod o DotNet.invokeMethodAsync de JS. Pase el nombre del ensamblado que contiene el método, el identificador del método estático de .NET y cualquier argumento.
En el ejemplo siguiente:
- El marcador de posición
{ASSEMBLY NAME}es el nombre de ensamblado de la aplicación. - El marcador de posición
{.NET METHOD ID}es el identificador del método de .NET. - El marcador de posición
{ARGUMENTS}son argumentos opcionales separados por comas que se pasan al método , y cada uno de ellos debe ser serializable con JSON.
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS});
DotNet.invokeMethod devuelve el resultado de la operación. DotNet.invokeMethodAsync devuelve un JS Promise que representa el resultado de la operación.
La función asincrónica (invokeMethodAsync) se prefiere a la versión sincrónica (invokeMethod) para admitir escenarios de Blazor Server.
El método de .NET debe ser público y estático, y debe tener el atributo [JSInvokable].
En el ejemplo siguiente:
- El marcador de posición
{<T>}indica el tipo de valor devuelto, que solo es necesario para los métodos que devuelven un valor. - El marcador de posición
{.NET METHOD ID}es el identificador del método.
@code {
[JSInvokable]
public static Task{<T>} {.NET METHOD ID}()
{
...
}
}
La llamada a métodos genéricos abiertos no se admite con métodos estáticos de .NET, pero se admite con métodos de instancia, que se describen más adelante en este artículo.
En el componente CallDotNetExample1 siguiente, el método de C# ReturnArrayAsync devuelve una matriz int. El atributo [JSInvokable] se aplica al método, lo que hace que el método sea invocable por JS.
Pages/CallDotNetExample1.razor:
@page "/call-dotnet-example-1"
<h1>Call .NET Example 1</h1>
<p>
<button onclick="returnArrayAsync()">
Trigger .NET static method
</button>
</p>
@code {
[JSInvokable]
public static Task<int[]> ReturnArrayAsync()
{
return Task.FromResult(new int[] { 1, 2, 3 });
}
}
El atributo HTML onclick del elemento <button> es la asignación del controlador de eventos onclick de JavaScript para procesar eventos click, y no el atributo de directiva @onclick de Blazor. La función returnArrayAsync de JS se asigna como controlador.
La siguiente función returnArrayAsync de JS llama al método de .NET ReturnArrayAsync del componente CallDotNetExample1 anterior y registra el resultado en la consola de herramientas para desarrolladores web del explorador. BlazorSample es el nombre del ensamblado de la aplicación.
Dentro de la etiqueta </body> de cierre de wwwroot/index.html (Blazor WebAssembly) o Pages/_Host.cshtml (Blazor Server):
<script>
window.returnArrayAsync = () => {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
.then(data => {
console.log(data);
});
};
</script>
Cuando se selecciona el botón Trigger .NET static method , la salida de la consola de las herramientas de desarrollo del explorador muestra los datos de la matriz. El formato de la salida difiere ligeramente entre los exploradores. En la salida siguiente se muestra el formato utilizado por Microsoft Edge:
Array(3) [ 1, 2, 3 ]
De forma predeterminada, el identificador de método de .NET para la llamada de JS es el nombre del método de .NET, pero puede especificar un identificador distinto mediante el constructor del atributo [JSInvokable]. En el ejemplo siguiente, DifferentMethodName es el identificador del método asignado para el método ReturnArrayAsync:
[JSInvokable("DifferentMethodName")]
En la llamada a DotNet.invokeMethod o DotNet.invokeMethodAsync, llame a DifferentMethodName para ejecutar el método de .NET ReturnArrayAsync:
DotNet.invokeMethod('BlazorSample', 'DifferentMethodName');DotNet.invokeMethodAsync('BlazorSample', 'DifferentMethodName');
Nota
El ejemplo de método ReturnArrayAsync de esta sección devuelve el resultado de un Task sin el uso de las palabras clave async y await de C# explícitas. La codificación de métodos con async y await es típica de los métodos que usan la palabra clave await para devolver el valor de las operaciones asincrónicas.
El método ReturnArrayAsync compuesto con las palabras clave async y await:
[JSInvokable]
public static async Task<int[]> ReturnArrayAsync()
{
return await Task.FromResult(new int[] { 1, 2, 3 });
}
Para obtener más información, vea Programación asincrónica con async y await en la guía de C#.
Invocación de un método de .NET de instancia
Para invocar un método de .NET de instancia desde JavaScript (JS):
- Pase la instancia de .NET por referencia a JS encapsulando la instancia en un DotNetObjectReference y llamando a Create en ella.
- Invoque un método de instancia de .NET desde JS mediante
invokeMethodoinvokeMethodAsyncdesde la clase DotNetObjectReference pasada. La instancia de .NET también se puede pasar como argumento al invocar otros métodos de .NET desde JS. - Deseche DotNetObjectReference.
Ejemplos de instancias de componente
La función sayHello1 de JS siguiente recibe DotNetObjectReference y llama a invokeMethodAsync para invocar el método de .NET GetHelloMethod de un componente.
Dentro de la etiqueta </body> de cierre de wwwroot/index.html (Blazor WebAssembly) o Pages/_Host.cshtml (Blazor Server):
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
Para el componente CallDotNetExample2 siguiente:
- El componente tiene un método de .NET invocable por JS llamado
GetHelloMessage. - Cuando se selecciona el botón
Trigger .NET instance method, se llama a la funciónsayHello1de JS con DotNetObjectReference. sayHello1:- Llama a
GetHelloMessagey recibe el resultado del mensaje. - Devuelve el resultado del mensaje al método
TriggerDotNetInstanceMethodque realiza la llamada.
- Llama a
- El mensaje devuelto de
sayHello1enresultse muestra al usuario. - Para evitar una pérdida de memoria y permitir la recolección de elementos no utilizados, la referencia de objeto de .NET creada por DotNetObjectReference se elimina en el método
Dispose.
Pages/CallDotNetExample2.razor:
@page "/call-dotnet-example-2"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 2</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private DotNetObjectReference<CallDotNetExample2> objRef;
public async Task TriggerDotNetInstanceMethod()
{
objRef = DotNetObjectReference.Create(this);
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
public void Dispose()
{
objRef?.Dispose();
}
}
Para pasar argumentos al método de instancia:
Agregue parámetros a la invocación del método de .NET. En el ejemplo siguiente, se pasa un nombre al método. Agregue parámetros adicionales a la lista según sea necesario.
<script> window.sayHello2 = (dotNetHelper, name) => { return dotNetHelper.invokeMethodAsync('GetHelloMessage', name); }; </script>Proporcione la lista de parámetros al método de .NET.
Pages/CallDotNetExample3.razor:@page "/call-dotnet-example-3" @implements IDisposable @inject IJSRuntime JS <h1>Call .NET Example 3</h1> <p> <label> Name: <input @bind="name" /> </label> </p> <p> <button @onclick="TriggerDotNetInstanceMethod"> Trigger .NET instance method </button> </p> <p> @result </p> @code { private string name; private string result; private DotNetObjectReference<CallDotNetExample3> objRef; public async Task TriggerDotNetInstanceMethod() { objRef = DotNetObjectReference.Create(this); result = await JS.InvokeAsync<string>("sayHello2", objRef, name); } [JSInvokable] public string GetHelloMessage(string passedName) => $"Hello, {passedName}!"; public void Dispose() { objRef?.Dispose(); } }
Ejemplos de instancias de clase
La siguiente función sayHello1 de JS:
- Llama al método de .NET
GetHelloMessageen la clase DotNetObjectReference pasada. - Devuelve el mensaje de
GetHelloMessageal autor de la llamadasayHello1.
Dentro de la etiqueta </body> de cierre de wwwroot/index.html (Blazor WebAssembly) o Pages/_Host.cshtml (Blazor Server):
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
La clase HelloHelper siguiente tiene un método de .NET invocable por JS llamado GetHelloMessage. Cuando se crea HelloHelper, el nombre de la propiedad Name se usa para devolver un mensaje de GetHelloMessage.
HelloHelper.cs:
using Microsoft.JSInterop;
public class HelloHelper
{
public HelloHelper(string name)
{
Name = name;
}
public string Name { get; set; }
[JSInvokable]
public string GetHelloMessage() => $"Hello, {Name}!";
}
El método CallHelloHelperGetHelloMessage de la clase JsInteropClasses3 siguiente invoca la función sayHello1 de JS con una nueva instancia de HelloHelper.
JsInteropClasses3.cs:
using System;
using System.Threading.Tasks;
using Microsoft.JSInterop;
public class JsInteropClasses3 : IDisposable
{
private readonly IJSRuntime js;
private DotNetObjectReference<HelloHelper> objRef;
public JsInteropClasses3(IJSRuntime js)
{
this.js = js;
}
public ValueTask<string> CallHelloHelperGetHelloMessage(string name)
{
objRef = DotNetObjectReference.Create(new HelloHelper(name));
return js.InvokeAsync<string>("sayHello1", objRef);
}
public void Dispose()
{
objRef?.Dispose();
}
}
Para evitar una pérdida de memoria y permitir la recolección de elementos no utilizados, la referencia de objeto de .NET creada por DotNetObjectReference se elimina en el método Dispose.
Cuando se selecciona el botón Trigger .NET instance method en el componente CallDotNetExample4 siguiente, se llama a JsInteropClasses3.CallHelloHelperGetHelloMessage con el valor de name.
Pages/CallDotNetExample4.razor:
@page "/call-dotnet-example-4"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 4</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private JsInteropClasses3 jsInteropClasses;
private async Task TriggerDotNetInstanceMethod()
{
jsInteropClasses = new JsInteropClasses3(JS);
result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
}
public void Dispose()
{
jsInteropClasses?.Dispose();
}
}
En la imagen siguiente se muestra el componente representado con el nombre Amy Pond en el campo Name. Una vez seleccionado el botón, Hello, Amy Pond! se muestra en la interfaz de usuario:

El patrón anterior que se muestra en la clase JsInteropClasses3 también se puede implementar íntegramente en un componente.
Pages/CallDotNetExample5.razor:
@page "/call-dotnet-example-5"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 5</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private DotNetObjectReference<HelloHelper> objRef;
public async Task TriggerDotNetInstanceMethod()
{
objRef = DotNetObjectReference.Create(new HelloHelper(name));
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
public void Dispose()
{
objRef?.Dispose();
}
}
Para evitar una pérdida de memoria y permitir la recolección de elementos no utilizados, la referencia de objeto de .NET creada por DotNetObjectReference se elimina en el método Dispose.
La salida mostrada por el componente CallDotNetExample5 es Hello, Amy Pond! cuando el nombre Amy Pond se proporciona en el campo Name.
En el componente CallDotNetExample5 anterior, se elimina la referencia al objeto de .NET. Si una clase o un componente no elimina DotNetObjectReference, deséchelo del cliente llamando a dispose en la clase DotNetObjectReference pasada:
window.jsFunction = (dotnetHelper) => {
dotnetHelper.invokeMethodAsync('{ASSEMBLY NAME}', '{.NET METHOD ID}');
dotnetHelper.dispose();
}
En el ejemplo anterior:
- El marcador de posición
{ASSEMBLY NAME}es el nombre de ensamblado de la aplicación. - El marcador de posición
{.NET METHOD ID}es el identificador del método de .NET.
Clase auxiliar del método de .NET de la instancia de componente
Una clase auxiliar puede invocar un método de instancia de .NET como Action. Las clases auxiliares son útiles en los siguientes escenarios:
- Cuando se representan varios componentes del mismo tipo en la misma página.
- En una aplicación de Blazor Server, donde varios usuarios usan simultáneamente el mismo componente.
En el ejemplo siguiente:
- El componente
CallDotNetExample6contiene varios componentesListItem, que es un componente compartido en la carpetaSharedde la aplicación. - Cada componente
ListItemconsta de un mensaje y un botón. - Cuando se selecciona un botón de componente
ListItem, el métodoUpdateMessagede ese objetoListItemcambia el texto del elemento de lista y oculta el botón.
La clase MessageUpdateInvokeHelper siguiente mantiene un método de .NET invocable por JS, UpdateMessageCaller, para invocar el elemento Action especificado cuando se crea una instancia de la clase. BlazorSample es el nombre del ensamblado de la aplicación.
MessageUpdateInvokeHelper.cs:
using System;
using Microsoft.JSInterop;
public class MessageUpdateInvokeHelper
{
private Action action;
public MessageUpdateInvokeHelper(Action action)
{
this.action = action;
}
[JSInvokable("BlazorSample")]
public void UpdateMessageCaller()
{
action.Invoke();
}
}
La función updateMessageCaller de JS siguiente invoca el método de .NET UpdateMessageCaller. BlazorSample es el nombre del ensamblado de la aplicación.
Dentro de la etiqueta </body> de cierre de wwwroot/index.html (Blazor WebAssembly) o Pages/_Host.cshtml (Blazor Server):
<script>
window.updateMessageCaller = (dotnetHelper) => {
dotnetHelper.invokeMethodAsync('BlazorSample', 'UpdateMessageCaller');
dotnetHelper.dispose();
}
</script>
El componente ListItem siguiente es un componente compartido que se puede usar varias veces en un componente primario y crea elementos de lista (<li>...</li>) para una lista HTML (<ul>...</ul> o <ol>...</ol>). Cada instancia de componente ListItem establece una instancia de MessageUpdateInvokeHelper con un elemento Action establecido en su método UpdateMessage.
Cuando se selecciona un botón InteropCall del componente ListItem, se invoca a updateMessageCaller con un elemento DotNetObjectReference creado para la instancia MessageUpdateInvokeHelper. Esto permite que el marco llame a UpdateMessageCaller en esa instancia MessageUpdateInvokeHelper de ListItem. La clase DotNetObjectReference pasada se elimina en JS (dotnetHelper.dispose()).
Shared/ListItem.razor:
@inject IJSRuntime JS
<li>
@message
<button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>
@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 JS.InvokeVoidAsync("updateMessageCaller",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
Se llama a StateHasChanged para actualizar la interfaz de usuario cuando message se establece en UpdateMessage. Si no se llama a StateHasChanged, Blazor no tiene ninguna manera de saber que la interfaz de usuario debe actualizarse cuando se invoca a Action.
El siguiente componente primario CallDotNetExample6 incluye cuatro elementos de lista, y cada uno de ellos es una instancia del componente ListItem.
Pages/CallDotNetExample6.razor:
@page "/call-dotnet-example-6"
<h1>Call .NET Example 6</h1>
<ul>
<ListItem />
<ListItem />
<ListItem />
<ListItem />
</ul>
En la imagen siguiente se muestra el componente primario CallDotNetExample6 representado después de seleccionar el segundo botón InteropCall :
- El segundo componente
ListItemha mostrado el mensajeUpdateMessage Called!. - El botón
InteropCalldel segundo componenteListItemno es visible porque la propiedaddisplayde CSS del botón está establecida ennone.

Ubicación de JavaScript
Cargue código de JavaScript (JS) mediante cualquiera de los enfoques descritos en el artículo de información general sobre interoperabilidad de JS:
- Cargar un script en el marcado
<head>(en general, no se recomienda) - Cargar un script en el marcado
<body> - Cargar un script desde un archivo JS externo (
.js) - Insertar un script después del inicio de Blazor
Para obtener información sobre cómo aislar scripts en los módulos JS, consulte la sección Aislamiento de JavaScript en módulos de JavaScript.
Advertencia
No coloque una etiqueta <script> en un archivo de componente (.razor), porque la etiqueta <script> no se puede actualizar dinámicamente.
Evitar referencias de objetos circulares
Los objetos que contienen referencias circulares no se pueden serializar en el cliente para:
- Llamadas de método .NET.
- Llamadas de método JavaScript desde C# cuando el tipo de valor devuelto tiene referencias circulares.
Límites de tamaño en las llamadas de interoperabilidad de JavaScript
This section only applies to Blazor Server apps. In Blazor WebAssembly, the framework doesn't impose a limit on the size of JavaScript (JS) interop inputs and outputs.
In Blazor Server, JS interop calls are limited in size by the maximum incoming SignalR message size permitted for hub methods, which is enforced by HubOptions.MaximumReceiveMessageSize (default: 32 KB). JS to .NET SignalR messages larger than MaximumReceiveMessageSize throw an error. The framework doesn't impose a limit on the size of a SignalR message from the hub to a client.
When SignalR logging isn't set to Debug or Trace, a message size error only appears in the browser's developer tools console:
Error: Connection disconnected with error 'Error: Server returned an error on close: Connection closed with an error.'.
When SignalR server-side logging is set to Debug or Trace, server-side logging surfaces an InvalidDataException for a message size error.
appsettings.Development.json:
{
"DetailedErrors": true,
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.AspNetCore.SignalR": "Debug"
}
}
}
Error:
System.IO.InvalidDataException: The maximum message size of 32768B was exceeded. The message size can be configured in AddHubOptions.
Increase the limit by setting MaximumReceiveMessageSize in Program.cs. The following example sets the maximum receive message size to 64 KB (64 * 1024) in ASP.NET Core 6.0 or later:
builder.Services.AddServerSideBlazor()
.AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024);
In Startup.ConfigureServices for versions of ASP.NET Core earlier than 6.0:
services.AddServerSideBlazor()
.AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024);
Increasing the SignalR incoming message size limit comes at the cost of requiring more server resources, and it exposes the server to increased risks from a malicious user. Additionally, reading a large amount of content in to memory as strings or byte arrays can also result in allocations that work poorly with the garbage collector, resulting in additional performance penalties.
Nota
Los enlaces de la documentación del origen de referencia de ASP.NET Core cargan la rama main del repositorio, que representa el desarrollo actual de la unidad de producto para la próxima versión de ASP.NET Core. Para seleccionar la rama de una versión diferente, use la lista desplegable Switch branches or tags (Cambiar ramas o etiquetas) para seleccionar la rama. Por ejemplo, seleccione la rama release/5.0 para la versión 5.0 de ASP.NET Core.
Consider the following guidance when developing code that transfers a large amount of data between JS and Blazor in Blazor Server apps:
- For ASP.NET Core 6.0 and newer:
- Leverage the native streaming interop support to transfer data larger than the SignalR incoming message size limit.
- For versions of ASP.NET Core earlier than 6.0:
- Slice the data into smaller pieces, and send the data segments sequentially as a Stream until all of the data is received by the server.
- Don't block the main UI thread for long periods when sending or receiving data.
- For an example that demonstrates sending large binary payloads in Blazor Server, see the Binary Submit sample app.
- General tips:
- Don't allocate large objects in JS and C# code.
- Free consumed memory when the process is completed or cancelled.
- Enforce the following additional requirements for security purposes:
- Declare the maximum file or data size that can be passed.
- Declare the minimum upload rate from the client to the server.
- After the data is received by the server, the data can be:
- Temporarily stored in a memory buffer until all of the segments are collected.
- Consumed immediately. For example, the data can be stored immediately in a database or written to disk as each segment is received.
Aislamiento de JavaScript en módulos de JavaScript
Blazor permite el aislamiento de JavaScript (JS) en módulos de JavaScript estándar (especificación de ECMAScript).
El aislamiento de JS proporciona las siguientes ventajas:
- El JS importado no contamina el espacio de nombres global.
- No es necesario que los consumidores de una biblioteca y los componentes importen el JS relacionado.
Para obtener más información, vea Llamada a funciones de JavaScript con métodos de .NET en Blazor de ASP.NET Core.
Recursos adicionales
- Llamada a funciones de JavaScript con métodos de .NET en Blazor de ASP.NET Core
- Ejemplo de
InteropComponent.razor(ramamaindel repositorio de GitHub dotnet/AspNetCore): la ramamainrepresenta el desarrollo actual de la unidad de producto para la próxima versión de ASP.NET Core. Para seleccionar la rama de una versión diferente (por ejemplo,release/5.0), use la lista desplegable Switch branches or tags (Cambiar ramas o etiquetas). - Interacción con Document Object Model (DOM)
En este artículo se describe cómo invocar métodos de .NET desde JavaScript (JS). Para obtener información sobre cómo llamar a funciones de JS desde .NET, consulte Llamada a funciones de JavaScript con métodos de .NET en Blazor de ASP.NET Core.
Invocación de un método de .NET estático
Para invocar un método de .NET estático desde JavaScript (JS), use las funciones DotNet.invokeMethod o DotNet.invokeMethodAsync de JS. Pase el nombre del ensamblado que contiene el método, el identificador del método estático de .NET y cualquier argumento.
En el ejemplo siguiente:
- El marcador de posición
{ASSEMBLY NAME}es el nombre de ensamblado de la aplicación. - El marcador de posición
{.NET METHOD ID}es el identificador del método de .NET. - El marcador de posición
{ARGUMENTS}son argumentos opcionales separados por comas que se pasan al método , y cada uno de ellos debe ser serializable con JSON.
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS});
DotNet.invokeMethod devuelve el resultado de la operación. DotNet.invokeMethodAsync devuelve un JS Promise que representa el resultado de la operación.
La función asincrónica (invokeMethodAsync) se prefiere a la versión sincrónica (invokeMethod) para admitir escenarios de Blazor Server.
El método de .NET debe ser público y estático, y debe tener el atributo [JSInvokable].
En el ejemplo siguiente:
- El marcador de posición
{<T>}indica el tipo de valor devuelto, que solo es necesario para los métodos que devuelven un valor. - El marcador de posición
{.NET METHOD ID}es el identificador del método.
@code {
[JSInvokable]
public static Task{<T>} {.NET METHOD ID}()
{
...
}
}
La llamada a métodos genéricos abiertos no se admite con métodos estáticos de .NET, pero se admite con métodos de instancia, que se describen más adelante en este artículo.
En el componente CallDotNetExample1 siguiente, el método de C# ReturnArrayAsync devuelve una matriz int. El atributo [JSInvokable] se aplica al método, lo que hace que el método sea invocable por JS.
Pages/CallDotNetExample1.razor:
@page "/call-dotnet-example-1"
<h1>Call .NET Example 1</h1>
<p>
<button onclick="returnArrayAsync()">
Trigger .NET static method
</button>
</p>
@code {
[JSInvokable]
public static Task<int[]> ReturnArrayAsync()
{
return Task.FromResult(new int[] { 1, 2, 3 });
}
}
El atributo HTML onclick del elemento <button> es la asignación del controlador de eventos onclick de JavaScript para procesar eventos click, y no el atributo de directiva @onclick de Blazor. La función returnArrayAsync de JS se asigna como controlador.
La siguiente función returnArrayAsync de JS llama al método de .NET ReturnArrayAsync del componente CallDotNetExample1 anterior y registra el resultado en la consola de herramientas para desarrolladores web del explorador. BlazorSample es el nombre del ensamblado de la aplicación.
Dentro de la etiqueta </body> de cierre de wwwroot/index.html (Blazor WebAssembly) o Pages/_Host.cshtml (Blazor Server):
<script>
window.returnArrayAsync = () => {
DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
.then(data => {
console.log(data);
});
};
</script>
Cuando se selecciona el botón Trigger .NET static method , la salida de la consola de las herramientas de desarrollo del explorador muestra los datos de la matriz. El formato de la salida difiere ligeramente entre los exploradores. En la salida siguiente se muestra el formato utilizado por Microsoft Edge:
Array(3) [ 1, 2, 3 ]
De forma predeterminada, el identificador de método de .NET para la llamada de JS es el nombre del método de .NET, pero puede especificar un identificador distinto mediante el constructor del atributo [JSInvokable]. En el ejemplo siguiente, DifferentMethodName es el identificador del método asignado para el método ReturnArrayAsync:
[JSInvokable("DifferentMethodName")]
En la llamada a DotNet.invokeMethod o DotNet.invokeMethodAsync, llame a DifferentMethodName para ejecutar el método de .NET ReturnArrayAsync:
DotNet.invokeMethod('BlazorSample', 'DifferentMethodName');DotNet.invokeMethodAsync('BlazorSample', 'DifferentMethodName');
Nota
El ejemplo de método ReturnArrayAsync de esta sección devuelve el resultado de un Task sin el uso de las palabras clave async y await de C# explícitas. La codificación de métodos con async y await es típica de los métodos que usan la palabra clave await para devolver el valor de las operaciones asincrónicas.
El método ReturnArrayAsync compuesto con las palabras clave async y await:
[JSInvokable]
public static async Task<int[]> ReturnArrayAsync()
{
return await Task.FromResult(new int[] { 1, 2, 3 });
}
Para obtener más información, vea Programación asincrónica con async y await en la guía de C#.
Invocación de un método de .NET de instancia
Para invocar un método de .NET de instancia desde JavaScript (JS):
- Pase la instancia de .NET por referencia a JS encapsulando la instancia en un DotNetObjectReference y llamando a Create en ella.
- Invoque un método de instancia de .NET desde JS mediante
invokeMethodoinvokeMethodAsyncdesde la clase DotNetObjectReference pasada. La instancia de .NET también se puede pasar como argumento al invocar otros métodos de .NET desde JS. - Deseche DotNetObjectReference.
Ejemplos de instancias de componente
La función sayHello1 de JS siguiente recibe DotNetObjectReference y llama a invokeMethodAsync para invocar el método de .NET GetHelloMethod de un componente.
Dentro de la etiqueta </body> de cierre de wwwroot/index.html (Blazor WebAssembly) o Pages/_Host.cshtml (Blazor Server):
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
Para el componente CallDotNetExample2 siguiente:
- El componente tiene un método de .NET invocable por JS llamado
GetHelloMessage. - Cuando se selecciona el botón
Trigger .NET instance method, se llama a la funciónsayHello1de JS con DotNetObjectReference. sayHello1:- Llama a
GetHelloMessagey recibe el resultado del mensaje. - Devuelve el resultado del mensaje al método
TriggerDotNetInstanceMethodque realiza la llamada.
- Llama a
- El mensaje devuelto de
sayHello1enresultse muestra al usuario. - Para evitar una pérdida de memoria y permitir la recolección de elementos no utilizados, la referencia de objeto de .NET creada por DotNetObjectReference se elimina en el método
Dispose.
Pages/CallDotNetExample2.razor:
@page "/call-dotnet-example-2"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 2</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private DotNetObjectReference<CallDotNetExample2> objRef;
public async Task TriggerDotNetInstanceMethod()
{
objRef = DotNetObjectReference.Create(this);
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
[JSInvokable]
public string GetHelloMessage() => $"Hello, {name}!";
public void Dispose()
{
objRef?.Dispose();
}
}
Para pasar argumentos al método de instancia:
Agregue parámetros a la invocación del método de .NET. En el ejemplo siguiente, se pasa un nombre al método. Agregue parámetros adicionales a la lista según sea necesario.
<script> window.sayHello2 = (dotNetHelper, name) => { return dotNetHelper.invokeMethodAsync('GetHelloMessage', name); }; </script>Proporcione la lista de parámetros al método de .NET.
Pages/CallDotNetExample3.razor:@page "/call-dotnet-example-3" @implements IDisposable @inject IJSRuntime JS <h1>Call .NET Example 3</h1> <p> <label> Name: <input @bind="name" /> </label> </p> <p> <button @onclick="TriggerDotNetInstanceMethod"> Trigger .NET instance method </button> </p> <p> @result </p> @code { private string name; private string result; private DotNetObjectReference<CallDotNetExample3> objRef; public async Task TriggerDotNetInstanceMethod() { objRef = DotNetObjectReference.Create(this); result = await JS.InvokeAsync<string>("sayHello2", objRef, name); } [JSInvokable] public string GetHelloMessage(string passedName) => $"Hello, {passedName}!"; public void Dispose() { objRef?.Dispose(); } }
Ejemplos de instancias de clase
La siguiente función sayHello1 de JS:
- Llama al método de .NET
GetHelloMessageen la clase DotNetObjectReference pasada. - Devuelve el mensaje de
GetHelloMessageal autor de la llamadasayHello1.
Dentro de la etiqueta </body> de cierre de wwwroot/index.html (Blazor WebAssembly) o Pages/_Host.cshtml (Blazor Server):
<script>
window.sayHello1 = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
</script>
La clase HelloHelper siguiente tiene un método de .NET invocable por JS llamado GetHelloMessage. Cuando se crea HelloHelper, el nombre de la propiedad Name se usa para devolver un mensaje de GetHelloMessage.
HelloHelper.cs:
using Microsoft.JSInterop;
public class HelloHelper
{
public HelloHelper(string name)
{
Name = name;
}
public string Name { get; set; }
[JSInvokable]
public string GetHelloMessage() => $"Hello, {Name}!";
}
El método CallHelloHelperGetHelloMessage de la clase JsInteropClasses3 siguiente invoca la función sayHello1 de JS con una nueva instancia de HelloHelper.
JsInteropClasses3.cs:
using System;
using System.Threading.Tasks;
using Microsoft.JSInterop;
public class JsInteropClasses3 : IDisposable
{
private readonly IJSRuntime js;
private DotNetObjectReference<HelloHelper> objRef;
public JsInteropClasses3(IJSRuntime js)
{
this.js = js;
}
public ValueTask<string> CallHelloHelperGetHelloMessage(string name)
{
objRef = DotNetObjectReference.Create(new HelloHelper(name));
return js.InvokeAsync<string>("sayHello1", objRef);
}
public void Dispose()
{
objRef?.Dispose();
}
}
Para evitar una pérdida de memoria y permitir la recolección de elementos no utilizados, la referencia de objeto de .NET creada por DotNetObjectReference se elimina en el método Dispose.
Cuando se selecciona el botón Trigger .NET instance method en el componente CallDotNetExample4 siguiente, se llama a JsInteropClasses3.CallHelloHelperGetHelloMessage con el valor de name.
Pages/CallDotNetExample4.razor:
@page "/call-dotnet-example-4"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 4</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private JsInteropClasses3 jsInteropClasses;
private async Task TriggerDotNetInstanceMethod()
{
jsInteropClasses = new JsInteropClasses3(JS);
result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
}
public void Dispose()
{
jsInteropClasses?.Dispose();
}
}
En la imagen siguiente se muestra el componente representado con el nombre Amy Pond en el campo Name. Una vez seleccionado el botón, Hello, Amy Pond! se muestra en la interfaz de usuario:

El patrón anterior que se muestra en la clase JsInteropClasses3 también se puede implementar íntegramente en un componente.
Pages/CallDotNetExample5.razor:
@page "/call-dotnet-example-5"
@implements IDisposable
@inject IJSRuntime JS
<h1>Call .NET Example 5</h1>
<p>
<label>
Name: <input @bind="name" />
</label>
</p>
<p>
<button @onclick="TriggerDotNetInstanceMethod">
Trigger .NET instance method
</button>
</p>
<p>
@result
</p>
@code {
private string name;
private string result;
private DotNetObjectReference<HelloHelper> objRef;
public async Task TriggerDotNetInstanceMethod()
{
objRef = DotNetObjectReference.Create(new HelloHelper(name));
result = await JS.InvokeAsync<string>("sayHello1", objRef);
}
public void Dispose()
{
objRef?.Dispose();
}
}
Para evitar una pérdida de memoria y permitir la recolección de elementos no utilizados, la referencia de objeto de .NET creada por DotNetObjectReference se elimina en el método Dispose.
La salida mostrada por el componente CallDotNetExample5 es Hello, Amy Pond! cuando el nombre Amy Pond se proporciona en el campo Name.
En el componente CallDotNetExample5 anterior, se elimina la referencia al objeto de .NET. Si una clase o un componente no elimina DotNetObjectReference, deséchelo del cliente llamando a dispose en la clase DotNetObjectReference pasada:
window.jsFunction = (dotnetHelper) => {
dotnetHelper.invokeMethodAsync('{ASSEMBLY NAME}', '{.NET METHOD ID}');
dotnetHelper.dispose();
}
En el ejemplo anterior:
- El marcador de posición
{ASSEMBLY NAME}es el nombre de ensamblado de la aplicación. - El marcador de posición
{.NET METHOD ID}es el identificador del método de .NET.
Clase auxiliar del método de .NET de la instancia de componente
Una clase auxiliar puede invocar un método de instancia de .NET como Action. Las clases auxiliares son útiles en los siguientes escenarios:
- Cuando se representan varios componentes del mismo tipo en la misma página.
- En una aplicación de Blazor Server, donde varios usuarios usan simultáneamente el mismo componente.
En el ejemplo siguiente:
- El componente
CallDotNetExample6contiene varios componentesListItem, que es un componente compartido en la carpetaSharedde la aplicación. - Cada componente
ListItemconsta de un mensaje y un botón. - Cuando se selecciona un botón de componente
ListItem, el métodoUpdateMessagede ese objetoListItemcambia el texto del elemento de lista y oculta el botón.
La clase MessageUpdateInvokeHelper siguiente mantiene un método de .NET invocable por JS, UpdateMessageCaller, para invocar el elemento Action especificado cuando se crea una instancia de la clase. BlazorSample es el nombre del ensamblado de la aplicación.
MessageUpdateInvokeHelper.cs:
using System;
using Microsoft.JSInterop;
public class MessageUpdateInvokeHelper
{
private Action action;
public MessageUpdateInvokeHelper(Action action)
{
this.action = action;
}
[JSInvokable("BlazorSample")]
public void UpdateMessageCaller()
{
action.Invoke();
}
}
La función updateMessageCaller de JS siguiente invoca el método de .NET UpdateMessageCaller. BlazorSample es el nombre del ensamblado de la aplicación.
Dentro de la etiqueta </body> de cierre de wwwroot/index.html (Blazor WebAssembly) o Pages/_Host.cshtml (Blazor Server):
<script>
window.updateMessageCaller = (dotnetHelper) => {
dotnetHelper.invokeMethodAsync('BlazorSample', 'UpdateMessageCaller');
dotnetHelper.dispose();
}
</script>
El componente ListItem siguiente es un componente compartido que se puede usar varias veces en un componente primario y crea elementos de lista (<li>...</li>) para una lista HTML (<ul>...</ul> o <ol>...</ol>). Cada instancia de componente ListItem establece una instancia de MessageUpdateInvokeHelper con un elemento Action establecido en su método UpdateMessage.
Cuando se selecciona un botón InteropCall del componente ListItem, se invoca a updateMessageCaller con un elemento DotNetObjectReference creado para la instancia MessageUpdateInvokeHelper. Esto permite que el marco llame a UpdateMessageCaller en esa instancia MessageUpdateInvokeHelper de ListItem. La clase DotNetObjectReference pasada se elimina en JS (dotnetHelper.dispose()).
Shared/ListItem.razor:
@inject IJSRuntime JS
<li>
@message
<button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>
@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 JS.InvokeVoidAsync("updateMessageCaller",
DotNetObjectReference.Create(messageUpdateInvokeHelper));
}
private void UpdateMessage()
{
message = "UpdateMessage Called!";
display = "none";
StateHasChanged();
}
}
Se llama a StateHasChanged para actualizar la interfaz de usuario cuando message se establece en UpdateMessage. Si no se llama a StateHasChanged, Blazor no tiene ninguna manera de saber que la interfaz de usuario debe actualizarse cuando se invoca a Action.
El siguiente componente primario CallDotNetExample6 incluye cuatro elementos de lista, y cada uno de ellos es una instancia del componente ListItem.
Pages/CallDotNetExample6.razor:
@page "/call-dotnet-example-6"
<h1>Call .NET Example 6</h1>
<ul>
<ListItem />
<ListItem />
<ListItem />
<ListItem />
</ul>
En la imagen siguiente se muestra el componente primario CallDotNetExample6 representado después de seleccionar el segundo botón InteropCall :
- El segundo componente
ListItemha mostrado el mensajeUpdateMessage Called!. - El botón
InteropCalldel segundo componenteListItemno es visible porque la propiedaddisplayde CSS del botón está establecida ennone.

Ubicación de JavaScript
Cargue código de JavaScript (JS) mediante cualquiera de los enfoques descritos en el artículo de información general sobre interoperabilidad de JS:
- Cargar un script en el marcado
<head>(en general, no se recomienda) - Cargar un script en el marcado
<body> - Cargar un script desde un archivo JS externo (
.js) - Inserción de un script después del inicio de Blazor
Advertencia
No coloque una etiqueta <script> en un archivo de componente (.razor), porque la etiqueta <script> no se puede actualizar dinámicamente.
Evitar referencias de objetos circulares
Los objetos que contienen referencias circulares no se pueden serializar en el cliente para:
- Llamadas de método .NET.
- Llamadas de método JavaScript desde C# cuando el tipo de valor devuelto tiene referencias circulares.
Límites de tamaño en las llamadas de interoperabilidad de JavaScript
This section only applies to Blazor Server apps. In Blazor WebAssembly, the framework doesn't impose a limit on the size of JavaScript (JS) interop inputs and outputs.
In Blazor Server, JS interop calls are limited in size by the maximum incoming SignalR message size permitted for hub methods, which is enforced by HubOptions.MaximumReceiveMessageSize (default: 32 KB). JS to .NET SignalR messages larger than MaximumReceiveMessageSize throw an error. The framework doesn't impose a limit on the size of a SignalR message from the hub to a client.
When SignalR logging isn't set to Debug or Trace, a message size error only appears in the browser's developer tools console:
Error: Connection disconnected with error 'Error: Server returned an error on close: Connection closed with an error.'.
When SignalR server-side logging is set to Debug or Trace, server-side logging surfaces an InvalidDataException for a message size error.
appsettings.Development.json:
{
"DetailedErrors": true,
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.AspNetCore.SignalR": "Debug"
}
}
}
Error:
System.IO.InvalidDataException: The maximum message size of 32768B was exceeded. The message size can be configured in AddHubOptions.
Increase the limit by setting MaximumReceiveMessageSize in Program.cs. The following example sets the maximum receive message size to 64 KB (64 * 1024) in ASP.NET Core 6.0 or later:
builder.Services.AddServerSideBlazor()
.AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024);
In Startup.ConfigureServices for versions of ASP.NET Core earlier than 6.0:
services.AddServerSideBlazor()
.AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024);
Increasing the SignalR incoming message size limit comes at the cost of requiring more server resources, and it exposes the server to increased risks from a malicious user. Additionally, reading a large amount of content in to memory as strings or byte arrays can also result in allocations that work poorly with the garbage collector, resulting in additional performance penalties.
Nota
Los enlaces de la documentación del origen de referencia de ASP.NET Core cargan la rama main del repositorio, que representa el desarrollo actual de la unidad de producto para la próxima versión de ASP.NET Core. Para seleccionar la rama de una versión diferente, use la lista desplegable Switch branches or tags (Cambiar ramas o etiquetas) para seleccionar la rama. Por ejemplo, seleccione la rama release/5.0 para la versión 5.0 de ASP.NET Core.
Consider the following guidance when developing code that transfers a large amount of data between JS and Blazor in Blazor Server apps:
- For ASP.NET Core 6.0 and newer:
- Leverage the native streaming interop support to transfer data larger than the SignalR incoming message size limit.
- For versions of ASP.NET Core earlier than 6.0:
- Slice the data into smaller pieces, and send the data segments sequentially as a Stream until all of the data is received by the server.
- Don't block the main UI thread for long periods when sending or receiving data.
- For an example that demonstrates sending large binary payloads in Blazor Server, see the Binary Submit sample app.
- General tips:
- Don't allocate large objects in JS and C# code.
- Free consumed memory when the process is completed or cancelled.
- Enforce the following additional requirements for security purposes:
- Declare the maximum file or data size that can be passed.
- Declare the minimum upload rate from the client to the server.
- After the data is received by the server, the data can be:
- Temporarily stored in a memory buffer until all of the segments are collected.
- Consumed immediately. For example, the data can be stored immediately in a database or written to disk as each segment is received.
Recursos adicionales
- Llamada a funciones de JavaScript con métodos de .NET en Blazor de ASP.NET Core
- Ejemplo de
InteropComponent.razor(ramamaindel repositorio de GitHub dotnet/AspNetCore): la ramamainrepresenta el desarrollo actual de la unidad de producto para la próxima versión de ASP.NET Core. Para seleccionar la rama de una versión diferente (por ejemplo,release/5.0), use la lista desplegable Switch branches or tags (Cambiar ramas o etiquetas). - Interacción con Document Object Model (DOM)