Interoperabilidad [JSImport]
/[JSExport]
de JavaScript con ASP.NET Core Blazor
Nota:
Esta no es la versión más reciente de este artículo. Para la versión actual, consulte la versión .NET 8 de este artículo.
Advertencia
Esta versión de ASP.NET Core ya no se admite. Para obtener más información, consulte la Directiva de soporte técnico de .NET y .NET Core. Para la versión actual, consulte la versión .NET 8 de este artículo.
Importante
Esta información hace referencia a un producto en versión preliminar, el cual puede sufrir importantes modificaciones antes de que se publique la versión comercial. Microsoft no proporciona ninguna garantía, expresa o implícita, con respecto a la información proporcionada aquí.
Para la versión actual, consulte la versión .NET 8 de este artículo.
En este artículo se explica cómo interactuar con JavaScript (JS) en componentes del lado cliente mediante JavaScript (JS) [JSImport]
/[JSExport]
API de interoperabilidad publicada para aplicaciones que adoptan .NET 7 o posterior.
Blazor proporciona su propio mecanismo de interoperabilidad de JS basado en la interfaz de IJSRuntime. La interoperabilidad JS de Blazor se admite uniformemente en los modos de representación de Blazor y en las aplicaciones de Blazor Hybrid. IJSRuntime también permite a los autores de bibliotecas crear bibliotecas de interoperabilidad de JS que se pueden compartir entre el ecosistema de Blazor y sigue siendo el enfoque recomendado para la interoperabilidad de JS en Blazor. Vea los artículos siguientes:
- Llamada a funciones de JavaScript con métodos de .NET en Blazor de ASP.NET Core
- Llamada a métodos de .NET desde funciones de JavaScript en ASP.NET Core Blazor
En este artículo se describe una alternativa JS enfoque de interoperabilidad específico de los componentes del lado cliente ejecutados en WebAssembly. Estos enfoques son adecuados cuando solo se espera que se ejecute en WebAssembly del lado cliente. Los autores de bibliotecas pueden usar estos enfoques para optimizar la interoperabilidad de JS comprobando durante la ejecución de código si la aplicación se ejecuta en WebAssembly en un explorador (OperatingSystem.IsBrowser). Los enfoques descritos en este artículo se deben usar para reemplazar la API de interoperabilidad JS obsoleta deserializada al migrar a .NET 7 o versiones posteriores.
Nota:
Este artículo se centra en JS interoperabilidad en componentes del lado cliente. Para obtener instrucciones sobre cómo llamar a .NET en aplicaciones de JavaScript, consulte Ejecución de .NET desde JavaScript.
API de interoperabilidad de JavaScript obsoleta
La interoperabilidad JS deserializada mediante la API IJSUnmarshalledRuntime está obsoleta en ASP.NET Core en .NET 7 o versiones posteriores. Siga las instrucciones de este artículo para reemplazar la API obsoleta.
Requisitos previos
Descarga e instala .NET 7 o posterior si aún no está instalado en el sistema o si el sistema no tiene instalada la versión más reciente.
Espacio de nombres
La API de interoperabilidad JS (JSHost.ImportAsync) descrita en este artículo se controla mediante atributos del espacio de nombres System.Runtime.InteropServices.JavaScript.
Habilitación de bloques no seguros
Habilite la propiedad AllowUnsafeBlocks en el archivo de proyecto de la aplicación, que permite que el generador de código del compilador de Roslyn use punteros para la interoperabilidad JS:
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
Advertencia
La API de interoperabilidad JS requiere habilitar AllowUnsafeBlocks. Tenga cuidado al implementar su propio código no seguro en aplicaciones .NET, pues puede introducir riesgos de seguridad y estabilidad. Para obtener más información, consulte: Código no seguro, tipos de puntero y punteros de función.
Razor biblioteca de clases (RCL) situada JS no se admite
Por lo general, la compatibilidad de ubicación JS para la interoperabilidad JS basada en IJSRuntime (ubicación de JavaScript en ASP.NET Core Blazor aplicaciones) también está presente para la [JSImport]
/[JSExport]
interoperabilidad descrita en este artículo. La única característica de ubicación JS no admitida es la colocación JS en una Razor biblioteca de clases (RCL).
En lugar de utilizar situados JS en una RCL, coloque el archivo JS en la carpeta wwwroot
de la RCL y haga referencia a él utilizando la ruta habitual para los recursos estáticos de la RCL:
_content/{PACKAGE ID}/{PATH}/{FILE NAME}.js
- El marcador de posición
{PACKAGE ID}
es el identificador de paquete de la RCL (o el nombre de biblioteca de una biblioteca de clases). - El marcador de posición
{PATH}
es la ruta de acceso al archivo. - El marcador de posición
{FILE NAME}
es el nombre de archivo.
Aunque la colocación JS en una RCL no está admitida por [JSImport]
/[JSExport]
interop, puede mantener sus archivos JS organizados adoptando uno o ambos de los siguientes enfoques:
- Nombre el archivo JS igual que el componente donde se utiliza el JS. Para un componente de la RCL denominada
CallJavaScriptFromLib
(CallJavaScriptFromLib.razor
), asigne al archivo el nombreCallJavaScriptFromLib.js
en la carpetawwwroot
. - Coloque los archivos JS específicos del componente en una carpeta
Components
dentro de la carpetawwwroot
de la RCL y utilice "Components
" en la ruta del archivo:_content/{PACKAGE ID}/Components/CallJavaScriptFromLib.js
.
Llamada a JavaScript desde .NET
En esta sección se explica cómo llamar a funciones JS desde .NET.
En el componente CallJavaScript1
siguiente:
- El módulo
CallJavaScript1
se importa de forma asincrónica desde el archivo JS combinado con JSHost.ImportAsync. - Se llama a la función importada
getMessage
JS medianteGetWelcomeMessage
. - La cadena de mensaje de bienvenida devuelta se muestra en la interfaz de usuario a través del campo
message
.
CallJavaScript1.razor
:
@page "/call-javascript-1"
@rendermode InteractiveWebAssembly
@using System.Runtime.InteropServices.JavaScript
<h1>
JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop
(Call JS Example 1)
</h1>
@(message is not null ? message : string.Empty)
@code {
private string? message;
protected override async Task OnInitializedAsync()
{
await JSHost.ImportAsync("CallJavaScript1",
"../Components/Pages/CallJavaScript1.razor.js");
message = GetWelcomeMessage();
}
}
@page "/call-javascript-1"
@using System.Runtime.InteropServices.JavaScript
<h1>
JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop
(Call JS Example 1)
</h1>
@(message is not null ? message : string.Empty)
@code {
private string? message;
protected override async Task OnInitializedAsync()
{
await JSHost.ImportAsync("CallJavaScript1",
"../Pages/CallJavaScript1.razor.js");
message = GetWelcomeMessage();
}
}
Nota:
Incluya un código de comprobación condicional con OperatingSystem.IsBrowser para asegurarse de que solo un componente representado en el cliente llama a la JS interoperabilidad. Esto es importante para las bibliotecas o paquetes NuGet que tienen como destino los componentes del lado servidor, que no pueden ejecutar el código proporcionado por esta API de interoperabilidad de JS.
Para importar una función JS para llamarla desde C#, use el atributo [JSImport]
en una firma de método de C# que coincida con la firma de la función JS. El primer parámetro para el atributo [JSImport]
es el nombre de la función JS que se va a importar, y el segundo parámetro es el nombre del módulo JS.
En el ejemplo siguiente, getMessage
es una función JS que devuelve un string
para un módulo denominado CallJavaScript1
. La firma del método de C# coincide: no se pasan parámetros a la función JS y la función JS devuelve un valor string
. GetWelcomeMessage
llama a la función JS en código de C#.
CallJavaScript1.razor.cs
:
using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;
namespace BlazorSample.Components.Pages;
[SupportedOSPlatform("browser")]
public partial class CallJavaScript1
{
[JSImport("getMessage", "CallJavaScript1")]
internal static partial string GetWelcomeMessage();
}
El espacio de nombres de la aplicación para la clase parcial anterior CallJavaScript1
es BlazorSample
. El espacio de nombres del componente es BlazorSample.Components.Pages
. Si usa el componente anterior en una aplicación de prueba local, actualice el espacio de nombres para que coincida con la aplicación. Por ejemplo, el espacio de nombres es ContosoApp.Components.Pages
si el espacio de nombres de la aplicación es ContosoApp
. Para más información, vea Componentes Razor de ASP.NET Core.
using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;
namespace BlazorSample.Pages;
[SupportedOSPlatform("browser")]
public partial class CallJavaScript1
{
[JSImport("getMessage", "CallJavaScript1")]
internal static partial string GetWelcomeMessage();
}
El espacio de nombres de la aplicación para la clase parcial anterior CallJavaScript1
es BlazorSample
. El espacio de nombres del componente es BlazorSample.Pages
. Si usa el componente anterior en una aplicación de prueba local, actualice el espacio de nombres para que coincida con la aplicación. Por ejemplo, el espacio de nombres es ContosoApp.Pages
si el espacio de nombres de la aplicación es ContosoApp
. Para más información, vea Componentes Razor de ASP.NET Core.
En la firma del método importado, puede usar tipos de .NET para parámetros y valores devueltos, que el tiempo de ejecución serializa automáticamente. Use JSMarshalAsAttribute<T> para controlar cómo se serializarán los parámetros del método importado. Por ejemplo, puede optar por serializar long
como System.Runtime.InteropServices.JavaScript.JSType.Number o System.Runtime.InteropServices.JavaScript.JSType.BigInt. Puede pasar devoluciones de llamada Action/Func<TResult> como parámetros, que se serializarán como funciones JS invocables. Puede pasar JS y las referencias de objetos administrados, y se serializarán como objetos proxy, manteniendo el objeto activo a través del límite hasta que se recopile el proxy como elemento no utilizado. También puede importar y exportar métodos asincrónicos con un resultado Task, que se serializa como promesas JS. La mayoría de los tipos serializados funcionan en ambas direcciones, como parámetros y como valores devueltos, en métodos importados y exportados, que se tratan en la sección Llamada a .NET desde JavaScript más adelante en este artículo.
En la tabla siguiente se indican las asignaciones de tipos admitidas.
.NET | JavaScript | Nullable |
Task a Promise |
JSMarshalAs opcional |
Array of |
---|---|---|---|---|---|
Boolean |
Boolean |
Compatible | Compatible | Compatible | No compatible |
Byte |
Number |
Compatible | Compatible | Compatible | Compatible |
Char |
String |
Compatible | Compatible | Compatible | No compatible |
Int16 |
Number |
Compatible | Compatible | Compatible | No compatible |
Int32 |
Number |
Compatible | Compatible | Compatible | Compatible |
Int64 |
Number |
Compatible | Compatible | No compatible | No compatible |
Int64 |
BigInt |
Compatible | Compatible | No compatible | No compatible |
Single |
Number |
Compatible | Compatible | Compatible | No compatible |
Double |
Number |
Compatible | Compatible | Compatible | Compatible |
IntPtr |
Number |
Compatible | Compatible | Compatible | No compatible |
DateTime |
Date |
Compatible | Compatible | No compatible | No compatible |
DateTimeOffset |
Date |
Compatible | Compatible | No compatible | No compatible |
Exception |
Error |
No compatible | Compatible | Compatible | No compatible |
JSObject |
Object |
No compatible | Compatible | Compatible | Compatible |
String |
String |
No compatible | Compatible | Compatible | Compatible |
Object |
Any |
No compatible | Compatible | No compatible | Compatible |
Span<Byte> |
MemoryView |
No compatible | No compatible | No compatible | No compatible |
Span<Int32> |
MemoryView |
No compatible | No compatible | No compatible | No compatible |
Span<Double> |
MemoryView |
No compatible | No compatible | No compatible | No compatible |
ArraySegment<Byte> |
MemoryView |
No compatible | No compatible | No compatible | No compatible |
ArraySegment<Int32> |
MemoryView |
No compatible | No compatible | No compatible | No compatible |
ArraySegment<Double> |
MemoryView |
No compatible | No compatible | No compatible | No compatible |
Task |
Promise |
No compatible | No compatible | Compatible | No compatible |
Action |
Function |
No compatible | No compatible | No compatible | No compatible |
Action<T1> |
Function |
No compatible | No compatible | No compatible | No compatible |
Action<T1, T2> |
Function |
No compatible | No compatible | No compatible | No compatible |
Action<T1, T2, T3> |
Function |
No compatible | No compatible | No compatible | No compatible |
Func<TResult> |
Function |
No compatible | No compatible | No compatible | No compatible |
Func<T1, TResult> |
Function |
No compatible | No compatible | No compatible | No compatible |
Func<T1, T2, TResult> |
Function |
No compatible | No compatible | No compatible | No compatible |
Func<T1, T2, T3, TResult> |
Function |
No compatible | No compatible | No compatible | No compatible |
Las condiciones siguientes se aplican a la asignación de tipos y a los valores serializados:
- La columna
Array of
indica si el tipo de .NET se puede serializar comoArray
de JS. Ejemplo: C#int[]
(Int32
) asignado aArray
de JS deNumber
s. - Al pasar un valor JS a C# con un valor del tipo incorrecto, el marco produce una excepción en la mayoría de los casos. El marco de trabajo no realiza la comprobación de tipos en tiempo de compilación en JS.
JSObject
,Exception
,Task
yArraySegment
creanGCHandle
y un proxy. Puede desencadenar la eliminación en el código de desarrollador o permitir que la recolección de elementos no utilizados de .NET elimine los objetos más adelante. Estos tipos conllevan una sobrecarga de rendimiento significativa.Array
: al serializar una matriz se crea una copia de dicha matriz en JS o .NET.MemoryView
MemoryView
es una clase JS para que el tiempo de ejecución de WebAssembly de .NET serialiceSpan
yArraySegment
.- A diferencia de serializar una matriz, serializar
Span
oArraySegment
no crea una copia de la memoria subyacente. - Solo se pueden crear instancias de
MemoryView
correctamente en el tiempo de ejecución de WebAssembly de .NET. Por lo tanto, no es posible importar una función JS como un método de .NET que tenga un parámetro deSpan
oArraySegment
. - Un elemento
MemoryView
creado para un elementoSpan
solo es válido durante la llamada de interoperabilidad. ComoSpan
se asigna en la pila de llamadas, la cual no se conserva después de la llamada de interoperabilidad, no es posible exportar un método de .NET que devuelva unSpan
. - Un elemento
MemoryView
creado para un elementoArraySegment
sigue disponible después de la llamada de interoperabilidad y es útil para compartir un búfer. La llamada adispose()
en un elementoMemoryView
creado para un elementoArraySegment
elimina el proxy y desancla la matriz .NET subyacente. Se recomienda llamar adispose()
en un bloquetry-finally
paraMemoryView
.
En la tabla siguiente se indican las asignaciones de tipos admitidas.
.NET | JavaScript | Nullable |
Task a Promise |
JSMarshalAs opcional |
Array of |
---|---|---|---|---|---|
Boolean |
Boolean |
Compatible | Compatible | Compatible | No compatible |
Byte |
Number |
Compatible | Compatible | Compatible | Compatible |
Char |
String |
Compatible | Compatible | Compatible | No compatible |
Int16 |
Number |
Compatible | Compatible | Compatible | No compatible |
Int32 |
Number |
Compatible | Compatible | Compatible | Compatible |
Int64 |
Number |
Compatible | Compatible | No compatible | No compatible |
Int64 |
BigInt |
Compatible | Compatible | No compatible | No compatible |
Single |
Number |
Compatible | Compatible | Compatible | No compatible |
Double |
Number |
Compatible | Compatible | Compatible | Compatible |
IntPtr |
Number |
Compatible | Compatible | Compatible | No compatible |
DateTime |
Date |
Compatible | Compatible | No compatible | No compatible |
DateTimeOffset |
Date |
Compatible | Compatible | No compatible | No compatible |
Exception |
Error |
No compatible | Compatible | Compatible | No compatible |
JSObject |
Object |
No compatible | Compatible | Compatible | Compatible |
String |
String |
No compatible | Compatible | Compatible | Compatible |
Object |
Any |
No compatible | Compatible | No compatible | Compatible |
Span<Byte> |
MemoryView |
No compatible | No compatible | No compatible | No compatible |
Span<Int32> |
MemoryView |
No compatible | No compatible | No compatible | No compatible |
Span<Double> |
MemoryView |
No compatible | No compatible | No compatible | No compatible |
ArraySegment<Byte> |
MemoryView |
No compatible | No compatible | No compatible | No compatible |
ArraySegment<Int32> |
MemoryView |
No compatible | No compatible | No compatible | No compatible |
ArraySegment<Double> |
MemoryView |
No compatible | No compatible | No compatible | No compatible |
Task |
Promise |
No compatible | No compatible | Compatible | No compatible |
Action |
Function |
No compatible | No compatible | No compatible | No compatible |
Action<T1> |
Function |
No compatible | No compatible | No compatible | No compatible |
Action<T1, T2> |
Function |
No compatible | No compatible | No compatible | No compatible |
Action<T1, T2, T3> |
Function |
No compatible | No compatible | No compatible | No compatible |
Func<TResult> |
Function |
No compatible | No compatible | No compatible | No compatible |
Func<T1, TResult> |
Function |
No compatible | No compatible | No compatible | No compatible |
Func<T1, T2, TResult> |
Function |
No compatible | No compatible | No compatible | No compatible |
Func<T1, T2, T3, TResult> |
Function |
No compatible | No compatible | No compatible | No compatible |
Las condiciones siguientes se aplican a la asignación de tipos y a los valores serializados:
- La columna
Array of
indica si el tipo de .NET se puede serializar comoArray
de JS. Ejemplo: C#int[]
(Int32
) asignado aArray
de JS deNumber
s. - Al pasar un valor JS a C# con un valor del tipo incorrecto, el marco produce una excepción en la mayoría de los casos. El marco de trabajo no realiza la comprobación de tipos en tiempo de compilación en JS.
JSObject
,Exception
,Task
yArraySegment
creanGCHandle
y un proxy. Puede desencadenar la eliminación en el código de desarrollador o permitir que la recolección de elementos no utilizados de .NET elimine los objetos más adelante. Estos tipos conllevan una sobrecarga de rendimiento significativa.Array
: al serializar una matriz se crea una copia de dicha matriz en JS o .NET.MemoryView
MemoryView
es una clase JS para que el tiempo de ejecución de WebAssembly de .NET serialiceSpan
yArraySegment
.- A diferencia de serializar una matriz, serializar
Span
oArraySegment
no crea una copia de la memoria subyacente. - Solo se pueden crear instancias de
MemoryView
correctamente en el tiempo de ejecución de WebAssembly de .NET. Por lo tanto, no es posible importar una función JS como un método de .NET que tenga un parámetro deSpan
oArraySegment
. - Un elemento
MemoryView
creado para un elementoSpan
solo es válido durante la llamada de interoperabilidad. ComoSpan
se asigna en la pila de llamadas, la cual no se conserva después de la llamada de interoperabilidad, no es posible exportar un método de .NET que devuelva unSpan
. - Un elemento
MemoryView
creado para un elementoArraySegment
sigue disponible después de la llamada de interoperabilidad y es útil para compartir un búfer. La llamada adispose()
en un elementoMemoryView
creado para un elementoArraySegment
elimina el proxy y desancla la matriz .NET subyacente. Se recomienda llamar adispose()
en un bloquetry-finally
paraMemoryView
.
El nombre del módulo en el atributo [JSImport]
y la llamada para cargar el módulo en el componente con JSHost.ImportAsync debe coincidir y ser único en la aplicación. Al crear una biblioteca para la implementación en un paquete NuGet, se recomienda usar el espacio de nombres del paquete NuGet como prefijo en los nombres de módulo. En el ejemplo siguiente, el nombre del módulo refleja el paquete Contoso.InteropServices.JavaScript
y una carpeta de clases de interoperabilidad de mensajes de usuario (UserMessages
):
[JSImport("getMessage",
"Contoso.InteropServices.JavaScript.UserMessages.CallJavaScript1")]
Las funciones accesibles en el espacio de nombres global se pueden importar mediante el prefijo globalThis
en el nombre de la función y mediante el uso del atributo [JSImport]
sin proporcionar un nombre de módulo. En el ejemplo siguiente, console.log
tiene el prefijo globalThis
. El método Log
de C# llama a la función importada y acepta un mensaje de cadena de C# (message
) y serializa la cadena de C# en un JSString
para console.log
:
[JSImport("globalThis.console.log")]
internal static partial void Log([JSMarshalAs<JSType.String>] string message);
Exporte scripts desde un módulo de JavaScript ES6 estándar, ya sea combinados con un componente o colocados con otros recursos estáticos de JavaScript en un archivo JS (por ejemplo, wwwroot/js/{FILE NAME}.js
, donde los recursos estáticos de JS se mantienen en una carpeta denominada js
en la carpeta wwwroot
de la aplicación y el marcador de posición {FILE NAME}
es el nombre de archivo).
En el ejemplo siguiente, se exporta una función JS denominada getMessage
desde un archivo combinado JS que devuelve un mensaje de bienvenida "¡Hola desde Blazor!" en portugués:
CallJavaScript1.razor.js
:
export function getMessage() {
return 'Olá do Blazor!';
}
Llamada a .NET desde JavaScript
En esta sección se explica cómo llamar a métodos de .NET desde JS.
El siguiente componente CallDotNet1
llama a JS,que interactúa directamente con DOM para representar la cadena de mensaje de bienvenida:
- El módulo
CallDotNet
JS se importa de forma asincrónica desde el archivo JS combinado para este componente. - Se llama a la función importada
setMessage
JS medianteSetWelcomeMessage
. - El mensaje de bienvenida devuelto se muestra mediante
setMessage
en la interfaz de usuario a través del campomessage
.
Importante
En el ejemplo de esta sección, la interoperabilidad JS se usa para mutar un elemento DOM exclusivamente con fines de demostración después de que el componente se represente en OnAfterRender
. Normalmente, solo debe mutar el DOM con JS cuando el objeto no interactúa con Blazor. El enfoque que se muestra en esta sección es similar a los casos en los que se usa una biblioteca de terceros JS en un componente Razor, donde el componente interactúa con la biblioteca JS a través de la interoperabilidad JS, la biblioteca de terceros JS interactúa con parte del DOM y Blazor no está implicado directamente con las actualizaciones de DOM de esa parte del DOM. Para más información, vea Interoperabilidad de JavaScript en Blazor de ASP.NET Core (interoperabilidad de JS).
CallDotNet1.razor
:
@page "/call-dotnet-1"
@rendermode InteractiveWebAssembly
@using System.Runtime.InteropServices.JavaScript
<h1>
JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop
(Call .NET Example 1)
</h1>
<p>
<span id="result">.NET method not executed yet</span>
</p>
@code {
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await JSHost.ImportAsync("CallDotNet1",
"../Components/Pages/CallDotNet1.razor.js");
SetWelcomeMessage();
}
}
}
@page "/call-dotnet-1"
@using System.Runtime.InteropServices.JavaScript
<h1>
JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop
(Call .NET Example 1)
</h1>
<p>
<span id="result">.NET method not executed yet</span>
</p>
@code {
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await JSHost.ImportAsync("CallDotNet1",
"../Pages/CallDotNet1.razor.js");
SetWelcomeMessage();
}
}
}
Para exportar un método de .NET para que se le pueda llamar desde JS, use el atributo [JSExport]
.
En el ejemplo siguiente:
SetWelcomeMessage
llama a una función JS denominadasetMessage
. La función JS llama a .NET para recibir el mensaje de bienvenida deGetMessageFromDotnet
y muestra el mensaje en la interfaz de usuario.GetMessageFromDotnet
es un método .NET con el atributo[JSExport]
que devuelve un mensaje de bienvenida, "¡Hello from Blazor!" en portugués.
CallDotNet1.razor.cs
:
using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;
namespace BlazorSample.Components.Pages;
[SupportedOSPlatform("browser")]
public partial class CallDotNet1
{
[JSImport("setMessage", "CallDotNet1")]
internal static partial void SetWelcomeMessage();
[JSExport]
internal static string GetMessageFromDotnet()
{
return "Olá do Blazor!";
}
}
El espacio de nombres de la aplicación para la clase parcial anterior CallDotNet1
es BlazorSample
. El espacio de nombres del componente es BlazorSample.Components.Pages
. Si usa el componente anterior en una aplicación de prueba local, actualice el espacio de nombres de la aplicación para que coincida con la aplicación. Por ejemplo, el espacio de nombres del componente es ContosoApp.Components.Pages
si el espacio de nombres de la aplicación es ContosoApp
. Para más información, vea Componentes Razor de ASP.NET Core.
En el ejemplo siguiente, se importa una función JS denominada setMessage
desde un archivo combinado JS.
El método setMessage
realiza las acciones siguientes:
- Llama a
globalThis.getDotnetRuntime(0)
para exponer la instancia del entorno de ejecución de .NET de WebAssembly para llamar a métodos .NET exportados. - Obtiene las exportaciones JS del ensamblado de la aplicación. En el ejemplo siguiente, el nombre del ensamblado de la aplicación es
BlazorSample
. - Llama al método
BlazorSample.Components.Pages.CallDotNet1.GetMessageFromDotnet
desde las exportaciones (exports
). El valor devuelto, que es el mensaje de bienvenida, se asigna al texto<span>
del componenteCallDotNet1
. El espacio de nombres de la aplicación esBlazorSample
y el espacio de nombres del componenteCallDotNet1
esBlazorSample.Components.Pages
.
CallDotNet1.razor.js
:
export async function setMessage() {
const { getAssemblyExports } = await globalThis.getDotnetRuntime(0);
var exports = await getAssemblyExports("BlazorSample.dll");
document.getElementById("result").innerText =
exports.BlazorSample.Components.Pages.CallDotNet1.GetMessageFromDotnet();
}
using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;
namespace BlazorSample.Pages;
[SupportedOSPlatform("browser")]
public partial class CallDotNet1
{
[JSImport("setMessage", "CallDotNet1")]
internal static partial void SetWelcomeMessage();
[JSExport]
internal static string GetMessageFromDotnet()
{
return "Olá do Blazor!";
}
}
El espacio de nombres de la aplicación para la clase parcial anterior CallDotNet1
es BlazorSample
. El espacio de nombres del componente es BlazorSample.Pages
. Si usa el componente anterior en una aplicación de prueba local, actualice el espacio de nombres de la aplicación para que coincida con la aplicación. Por ejemplo, el espacio de nombres del componente es ContosoApp.Pages
si el espacio de nombres de la aplicación es ContosoApp
. Para más información, vea Componentes Razor de ASP.NET Core.
En el ejemplo siguiente, se importa una función JS denominada setMessage
desde un archivo combinado JS.
El método setMessage
realiza las acciones siguientes:
- Llama a
globalThis.getDotnetRuntime(0)
para exponer la instancia del entorno de ejecución de .NET de WebAssembly para llamar a métodos .NET exportados. - Obtiene las exportaciones JS del ensamblado de la aplicación. En el ejemplo siguiente, el nombre del ensamblado de la aplicación es
BlazorSample
. - Llama al método
BlazorSample.Pages.CallDotNet1.GetMessageFromDotnet
desde las exportaciones (exports
). El valor devuelto, que es el mensaje de bienvenida, se asigna al texto<span>
del componenteCallDotNet1
. El espacio de nombres de la aplicación esBlazorSample
y el espacio de nombres del componenteCallDotNet1
esBlazorSample.Pages
.
CallDotNet1.razor.js
:
export async function setMessage() {
const { getAssemblyExports } = await globalThis.getDotnetRuntime(0);
var exports = await getAssemblyExports("BlazorSample.dll");
document.getElementById("result").innerText =
exports.BlazorSample.Pages.CallDotNet1.GetMessageFromDotnet();
}
Nota:
La llamada a getAssemblyExports
para obtener las exportaciones puede producirse en un inicializador de JavaScript para la disponibilidad en toda la aplicación.
Varias llamadas de importación de módulos
Una vez cargado un módulo JS, las funciones del módulo JS están disponibles para los componentes y clases de la aplicación, siempre y cuando la aplicación se ejecute en la ventana del explorador o en la pestaña sin que el usuario vuelva a cargar manualmente la aplicación. Se puede llamar varias veces a JSHost.ImportAsync en el mismo módulo sin una penalización de rendimiento significativa cuando:
- El usuario visita un componente que llama a JSHost.ImportAsync para importar un módulo, sale del componente y, a continuación, vuelve al componente donde se llama a JSHost.ImportAsync de nuevo para la misma importación del módulo.
- El mismo módulo lo usan los distintos componentes y JSHost.ImportAsync los carga en cada uno de los componentes.
Uso de un único módulo de JavaScript entre componentes
Antes de seguir las instrucciones de esta sección, lea las secciones Llamada a JavaScript desde .NET y Llamada a .NET desde JavaScript de este artículo, que proporcionan instrucciones generales sobre [JSImport]
la interoperabilidad /[JSExport]
.
En el ejemplo de esta sección se muestra cómo usar JS interoperabilidad desde un módulo de JS compartido en una aplicación del lado cliente. Las instrucciones de esta sección no se aplican a las bibliotecas de clases Razor (RCL).
Se usan los siguientes componentes, clases, métodos de C# y funciones JS:
- Clase
Interop
(Interop.cs
): configura la interoperabilidad de importación y exportación JS con los atributos[JSImport]
y[JSExport]
de un módulo denominadoInterop
.GetWelcomeMessage
: método .NET que llama a la función importadagetMessage
JS.SetWelcomeMessage
: método .NET que llama a la función importadasetMessage
JS.GetMessageFromDotnet
: método de C# exportado que devuelve una cadena de mensaje de bienvenida cuando se le llama desde JS.
- Archivo
wwwroot/js/interop.js
: contiene las funciones JS.getMessage
: devuelve un mensaje de bienvenida cuando lo llama el código de C# en un componente.setMessage
: llama al método de C#GetMessageFromDotnet
y asigna el mensaje de bienvenida devuelto a un elemento DOM<span>
.
Program.cs
llama a JSHost.ImportAsync para cargar el módulo desdewwwroot/js/interop.js
.- Componente
CallJavaScript2
(CallJavaScript2.razor
): llama aGetWelcomeMessage
y muestra el mensaje de bienvenida devuelto en la interfaz de usuario del componente. - Componente
CallDotNet2
(CallDotNet2.razor
): llama aSetWelcomeMessage
.
Interop.cs
:
using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;
namespace BlazorSample.JavaScriptInterop;
[SupportedOSPlatform("browser")]
public partial class Interop
{
[JSImport("getMessage", "Interop")]
internal static partial string GetWelcomeMessage();
[JSImport("setMessage", "Interop")]
internal static partial void SetWelcomeMessage();
[JSExport]
internal static string GetMessageFromDotnet()
{
return "Olá do Blazor!";
}
}
En el ejemplo anterior, el espacio de nombres de la aplicación es BlazorSample
y el espacio de nombres completo para las clases de interoperabilidad de C# es BlazorSample.JavaScriptInterop
.
wwwroot/js/interop.js
:
export function getMessage() {
return 'Olá do Blazor!';
}
export async function setMessage() {
const { getAssemblyExports } = await globalThis.getDotnetRuntime(0);
var exports = await getAssemblyExports("BlazorSample.dll");
document.getElementById("result").innerText =
exports.BlazorSample.JavaScriptInterop.Interop.GetMessageFromDotnet();
}
Haga que el espacio de nombres System.Runtime.InteropServices.JavaScript esté disponible en la parte superior del archivo Program.cs
:
using System.Runtime.InteropServices.JavaScript;
Cargue el módulo en Program.cs
antes de llamar a WebAssemblyHost.RunAsync:
if (OperatingSystem.IsBrowser())
{
await JSHost.ImportAsync("Interop", "../js/interop.js");
}
CallJavaScript2.razor
:
@page "/call-javascript-2"
@rendermode InteractiveWebAssembly
@using BlazorSample.JavaScriptInterop
<h1>
JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop
(Call JS Example 2)
</h1>
@(message is not null ? message : string.Empty)
@code {
private string? message;
protected override void OnInitialized()
{
message = Interop.GetWelcomeMessage();
}
}
@page "/call-javascript-2"
@using BlazorSample.JavaScriptInterop
<h1>
JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop
(Call JS Example 2)
</h1>
@(message is not null ? message : string.Empty)
@code {
private string? message;
protected override void OnInitialized()
{
message = Interop.GetWelcomeMessage();
}
}
CallDotNet2.razor
:
@page "/call-dotnet-2"
@rendermode InteractiveWebAssembly
@using BlazorSample.JavaScriptInterop
<h1>
JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop
(Call .NET Example 2)
</h1>
<p>
<span id="result">.NET method not executed</span>
</p>
@code {
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
Interop.SetWelcomeMessage();
}
}
}
@page "/call-dotnet-2"
@using BlazorSample.JavaScriptInterop
<h1>
JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop
(Call .NET Example 2)
</h1>
<p>
<span id="result">.NET method not executed</span>
</p>
@code {
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
Interop.SetWelcomeMessage();
}
}
}
Importante
En el ejemplo de esta sección, la interoperabilidad JS se usa para mutar un elemento DOM exclusivamente con fines de demostración después de que el componente se represente en OnAfterRender
. Normalmente, solo debe mutar el DOM con JS cuando el objeto no interactúa con Blazor. El enfoque que se muestra en esta sección es similar a los casos en los que se usa una biblioteca de terceros JS en un componente Razor, donde el componente interactúa con la biblioteca JS a través de la interoperabilidad JS, la biblioteca de terceros JS interactúa con parte del DOM y Blazor no está implicado directamente con las actualizaciones de DOM de esa parte del DOM. Para más información, vea Interoperabilidad de JavaScript en Blazor de ASP.NET Core (interoperabilidad de JS).
Recursos adicionales
- Documentación de la API
- Ejecución de .NET desde JavaScript
- En el repositorio
dotnet/runtime
de GitHub:
Comentarios
https://aka.ms/ContentUserFeedback.
Próximamente: A lo largo de 2024 iremos eliminando gradualmente GitHub Issues como mecanismo de comentarios sobre el contenido y lo sustituiremos por un nuevo sistema de comentarios. Para más información, vea:Enviar y ver comentarios de