Interoperabilidade [JSImport]
/[JSExport]
do JavaScript com ASP.NET Core Blazor
Observação
Esta não é a versão mais recente deste artigo. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.
Importante
Essas informações relacionam-se ao produto de pré-lançamento, que poderá ser substancialmente modificado antes do lançamento comercial. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.
Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.
Este artigo explica como interagir com o JavaScript (JS) em componentes do lado do cliente usando a API de interoperabilidade do JavaScript (JS) [JSImport]
/[JSExport]
lançada nos aplicativos que adotam o .NET 7 ou posterior.
O Blazor fornece seu próprio mecanismo de interoperabilidade JS com base na interface IJSRuntime. A interoperabilidade do Blazor para JS é uniformemente suportada nos diversos modos de renderização do Blazor e para os aplicativos Blazor Hybrid. O IJSRuntime permite que os autores de bibliotecas compilem bibliotecas de interoperabilidade JS que podem ser compartilhadas em todo o ecossistema Blazor e continua sendo a abordagem recomendada para a interoperabilidade JS no Blazor. Veja os artigos a seguir:
- Chamar funções JavaScript de métodos .NET no ASP.NET Core Blazor
- Chamar métodos .NET de funções JavaScript no ASP.NET Core Blazor
Este artigo descreve uma abordagem de interoperabilidade JS específica aos componentes do lado do cliente executados no WebAssembly. Essas abordagens são apropriadas quando você espera apenas executar no WebAssembly do lado do cliente. Os autores de bibliotecas podem usar essas abordagens para otimizar a interoperabilidade JS ao verificar, durante a execução do código, se o aplicativo está em execução no WebAssembly em um navegador (OperatingSystem.IsBrowser). As abordagens descritas neste artigo devem ser usadas para substituir a API de interoperabilidade JS sem realizar unmarshaling ao migrar para o .NET 7 ou posterior.
Observação
Este artigo se concentra na interoperabilidade JS em componentes do lado do cliente. Para obter diretrizes sobre como chamar o .NET em aplicativos JavaScript, consulte Executar o .NET do JavaScript.
API de interoperabilidade JavaScript obsoleta
A realização de unmarshaling de interoperabilidade JS usando a API IJSUnmarshalledRuntime está obsoleto no ASP.NET Core no .NET 7 ou posterior. Siga as diretrizes neste artigo para substituir a API obsoleta.
Pré-requisitos
Baixar e instala o .NET 7 ou posterior se ele ainda não estiver instalado no sistema ou se o sistema não tiver a versão mais recente instalada.
Namespace
A API de interoperabilidade JS descrita neste artigo é controlada por atributos no namespace System.Runtime.InteropServices.JavaScript.
Habilitar blocos não seguros
Habilite a propriedade AllowUnsafeBlocks no arquivo de projeto do aplicativo, que permite que o gerador de código no compilador Roslyn use ponteiros para JS interoperabilidade:
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
Aviso
A API de interoperabilidade JS requer a habilitação de AllowUnsafeBlocks. Tenha cuidado ao implementar seu próprio código não seguro em aplicativos .NET, o que pode introduzir riscos de segurança e estabilidade. Para obter mais informações, consulte Código não seguro, tipos de ponteiro e ponteiros de função.
Chamar JavaScript do .NET
Esta seção explica como chamar funções JS do .NET.
No seguinte componente CallJavaScript1
:
- O módulo
CallJavaScript1
é importado de forma assíncrona do arquivo JS posicionado com JSHost.ImportAsync. - A função
getMessage
JS importada é chamada porGetWelcomeMessage
. - A cadeia de caracteres de mensagem de boas-vindas retornada é exibida na interface do usuário por meio do 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();
}
}
Observação
Inclui um código de verificação condicional com OperatingSystem.IsBrowser para garantir que a interoperabilidade JS seja chamada apenas por um componente renderizado no cliente. Isso é importante para bibliotecas/pacotes NuGet direcionados a componentes do lado do servidor, que não podem executar o código fornecido por essa API de interoperabilidade JS.
Para importar uma função JS para chamá-la de C#, use o atributo [JSImport]
em uma assinatura de método C# que corresponda à assinatura de função JS. O primeiro parâmetro para o atributo [JSImport]
é o nome da função JS a ser importada e o segundo parâmetro é o nome do módulo JS.
No exemplo a seguir, getMessage
é uma função JS que retorna um string
para um módulo nomeado CallJavaScript1
. A assinatura do método C# corresponde: nenhum parâmetro é passado para a função JS e a função JS retorna um string
. A função JS é denominada por GetWelcomeMessage
no código 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();
}
O namespace do aplicativo para a classe parcial CallJavaScript1
anterior é BlazorSample
. O namespace do componente será BlazorSample.Components.Pages
. Se estiver usando o componente anterior em um aplicativo de teste local, atualize o namespace para corresponder ao aplicativo. Por exemplo, o namespace será ContosoApp.Components.Pages
se o namespace do aplicativo for ContosoApp
. Para saber mais, consulte Componentes Razor do 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();
}
O namespace do aplicativo para a classe parcial CallJavaScript1
anterior é BlazorSample
. O namespace do componente será BlazorSample.Pages
. Se estiver usando o componente anterior em um aplicativo de teste local, atualize o namespace para corresponder ao aplicativo. Por exemplo, o namespace será ContosoApp.Pages
se o namespace do aplicativo for ContosoApp
. Para saber mais, consulte Componentes Razor do ASP.NET Core.
Na assinatura do método importado, você pode usar tipos .NET para parâmetros e valores retornados, que sofrem realização de marshal automaticamente pelo runtime. Use JSMarshalAsAttribute<T> para controlar como os parâmetros do método importado sofrem realização de marshal. Por exemplo, você pode optar por realizar marshaling de um long
como System.Runtime.InteropServices.JavaScript.JSType.Number ou System.Runtime.InteropServices.JavaScript.JSType.BigInt. Você pode passar Action/Func<TResult> retornos de chamada como parâmetros, que sofrem realização de marshal como funções chamáveis JS. Você pode passar referências de JS e objeto gerenciado e elas sofrem realização de marshal como objetos proxy, mantendo o objeto ativo no limite até que o proxy seja coletado. Você também pode importar e exportar métodos assíncronos com um resultado Task, que sofrem realização de marshal como JS promessas. A maioria dos tipos com marshalling funciona em ambas as direções, como parâmetros e como valores retornados, em métodos importados e exportados, que são abordados na seção Chamar .NET do JavaScript mais adiante neste artigo.
A tabela a seguir indica os mapeamentos de tipo com suporte.
.NET | JavaScript | Nullable |
Task paraPromise |
Opcional JSMarshalAs |
Array of |
---|---|---|---|---|---|
Boolean |
Boolean |
Com suporte | Com suporte | Com suporte | Sem suporte |
Byte |
Number |
Com suporte | Com suporte | Com suporte | Com suporte |
Char |
String |
Com suporte | Com suporte | Com suporte | Sem suporte |
Int16 |
Number |
Com suporte | Com suporte | Com suporte | Sem suporte |
Int32 |
Number |
Com suporte | Com suporte | Com suporte | Com suporte |
Int64 |
Number |
Com suporte | Com suporte | Sem suporte | Sem suporte |
Int64 |
BigInt |
Com suporte | Com suporte | Sem suporte | Sem suporte |
Single |
Number |
Com suporte | Com suporte | Com suporte | Sem suporte |
Double |
Number |
Com suporte | Com suporte | Com suporte | Com suporte |
IntPtr |
Number |
Com suporte | Com suporte | Com suporte | Sem suporte |
DateTime |
Date |
Com suporte | Com suporte | Sem suporte | Sem suporte |
DateTimeOffset |
Date |
Com suporte | Com suporte | Sem suporte | Sem suporte |
Exception |
Error |
Sem suporte | Com suporte | Com suporte | Sem suporte |
JSObject |
Object |
Sem suporte | Com suporte | Com suporte | Com suporte |
String |
String |
Sem suporte | Com suporte | Com suporte | Com suporte |
Object |
Any |
Sem suporte | Com suporte | Sem suporte | Com suporte |
Span<Byte> |
MemoryView |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
Span<Int32> |
MemoryView |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
Span<Double> |
MemoryView |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
ArraySegment<Byte> |
MemoryView |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
ArraySegment<Int32> |
MemoryView |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
ArraySegment<Double> |
MemoryView |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
Task |
Promise |
Sem suporte | Sem suporte | Com suporte | Sem suporte |
Action |
Function |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
Action<T1> |
Function |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
Action<T1, T2> |
Function |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
Action<T1, T2, T3> |
Function |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
Func<TResult> |
Function |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
Func<T1, TResult> |
Function |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
Func<T1, T2, TResult> |
Function |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
Func<T1, T2, T3, TResult> |
Function |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
As seguintes condições se aplicam ao mapeamento de tipos e valores que sofrem realização de marshal:
- A coluna
Array of
indica se o tipo .NET pode sofrer realização de marshal como um JSArray
. Exemplo: C#int[]
(Int32
) mapeado para JSArray
deNumber
s. - Ao passar um valor JS para C# com um valor do tipo errado, a estrutura gera uma exceção na maioria dos casos. A estrutura não executa verificação de tipo em tempo de compilação no JS.
JSObject
,Exception
,Task
eArraySegment
criamGCHandle
e um proxy. Você pode disparar o descarte no código do desenvolvedor ou permitir que a coleta de lixo (GC, na sigla em inglês) do .NET descarte os objetos posteriormente. Esses tipos têm uma sobrecarga significativa de desempenho.Array
: o marshaling de uma matriz cria uma cópia da matriz no JS ou no .NET.MemoryView
MemoryView
é uma classe JS para o runtime do .NET WebAssembly realizar marshaling deSpan
eArraySegment
.- Ao contrário do marshaling de uma matriz, realizar marshaling de um
Span
ouArraySegment
não cria uma cópia da memória subjacente. MemoryView
só pode ter uma instância criada corretamente pelo runtime do WebAssembly do .NET. Portanto, não é possível importar uma função JS como um método .NET que tenha um parâmetro deSpan
ouArraySegment
.MemoryView
criado para umSpan
só é válido durante a chamada de interoperabilidade. ComoSpan
é alocado na pilha de chamadas, que não persiste após a chamada de interoperabilidade, não é possível exportar um método .NET que retorna umSpan
.MemoryView
criado para umArraySegment
sobrevive após a chamada de interoperabilidade e é útil para compartilhar um buffer. Chamardispose()
em umMemoryView
criado para umArraySegment
descarta o proxy e desafixa a matriz .NET subjacente. É recomendável chamardispose()
em um blocotry-finally
paraMemoryView
.
A tabela a seguir indica os mapeamentos de tipo com suporte.
.NET | JavaScript | Nullable |
Task paraPromise |
Opcional JSMarshalAs |
Array of |
---|---|---|---|---|---|
Boolean |
Boolean |
Com suporte | Com suporte | Com suporte | Sem suporte |
Byte |
Number |
Com suporte | Com suporte | Com suporte | Com suporte |
Char |
String |
Com suporte | Com suporte | Com suporte | Sem suporte |
Int16 |
Number |
Com suporte | Com suporte | Com suporte | Sem suporte |
Int32 |
Number |
Com suporte | Com suporte | Com suporte | Com suporte |
Int64 |
Number |
Com suporte | Com suporte | Sem suporte | Sem suporte |
Int64 |
BigInt |
Com suporte | Com suporte | Sem suporte | Sem suporte |
Single |
Number |
Com suporte | Com suporte | Com suporte | Sem suporte |
Double |
Number |
Com suporte | Com suporte | Com suporte | Com suporte |
IntPtr |
Number |
Com suporte | Com suporte | Com suporte | Sem suporte |
DateTime |
Date |
Com suporte | Com suporte | Sem suporte | Sem suporte |
DateTimeOffset |
Date |
Com suporte | Com suporte | Sem suporte | Sem suporte |
Exception |
Error |
Sem suporte | Com suporte | Com suporte | Sem suporte |
JSObject |
Object |
Sem suporte | Com suporte | Com suporte | Com suporte |
String |
String |
Sem suporte | Com suporte | Com suporte | Com suporte |
Object |
Any |
Sem suporte | Com suporte | Sem suporte | Com suporte |
Span<Byte> |
MemoryView |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
Span<Int32> |
MemoryView |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
Span<Double> |
MemoryView |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
ArraySegment<Byte> |
MemoryView |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
ArraySegment<Int32> |
MemoryView |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
ArraySegment<Double> |
MemoryView |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
Task |
Promise |
Sem suporte | Sem suporte | Com suporte | Sem suporte |
Action |
Function |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
Action<T1> |
Function |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
Action<T1, T2> |
Function |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
Action<T1, T2, T3> |
Function |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
Func<TResult> |
Function |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
Func<T1, TResult> |
Function |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
Func<T1, T2, TResult> |
Function |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
Func<T1, T2, T3, TResult> |
Function |
Sem suporte | Sem suporte | Sem suporte | Sem suporte |
As seguintes condições se aplicam ao mapeamento de tipos e valores que sofrem realização de marshal:
- A coluna
Array of
indica se o tipo .NET pode sofrer realização de marshal como um JSArray
. Exemplo: C#int[]
(Int32
) mapeado para JSArray
deNumber
s. - Ao passar um valor JS para C# com um valor do tipo errado, a estrutura gera uma exceção na maioria dos casos. A estrutura não executa verificação de tipo em tempo de compilação no JS.
JSObject
,Exception
,Task
eArraySegment
criamGCHandle
e um proxy. Você pode disparar o descarte no código do desenvolvedor ou permitir que a coleta de lixo (GC, na sigla em inglês) do .NET descarte os objetos posteriormente. Esses tipos têm uma sobrecarga significativa de desempenho.Array
: o marshaling de uma matriz cria uma cópia da matriz no JS ou no .NET.MemoryView
MemoryView
é uma classe JS para o runtime do .NET WebAssembly realizar marshaling deSpan
eArraySegment
.- Ao contrário do marshaling de uma matriz, realizar marshaling de um
Span
ouArraySegment
não cria uma cópia da memória subjacente. MemoryView
só pode ter uma instância criada corretamente pelo runtime do WebAssembly do .NET. Portanto, não é possível importar uma função JS como um método .NET que tenha um parâmetro deSpan
ouArraySegment
.MemoryView
criado para umSpan
só é válido durante a chamada de interoperabilidade. ComoSpan
é alocado na pilha de chamadas, que não persiste após a chamada de interoperabilidade, não é possível exportar um método .NET que retorna umSpan
.MemoryView
criado para umArraySegment
sobrevive após a chamada de interoperabilidade e é útil para compartilhar um buffer. Chamardispose()
em umMemoryView
criado para umArraySegment
descarta o proxy e desafixa a matriz .NET subjacente. É recomendável chamardispose()
em um blocotry-finally
paraMemoryView
.
O nome do módulo [JSImport]
no atributo e a chamada para carregar o módulo no componente com JSHost.ImportAsync devem corresponder e ser exclusivos no aplicativo. Ao criar uma biblioteca para implantação em um pacote NuGet, recomendamos usar o namespace do pacote NuGet como um prefixo em nomes de módulo. No exemplo a seguir, o nome do módulo reflete o pacote Contoso.InteropServices.JavaScript
e uma pasta de classes de interoperabilidade de mensagens do usuário (UserMessages
):
[JSImport("getMessage",
"Contoso.InteropServices.JavaScript.UserMessages.CallJavaScript1")]
As funções acessíveis no namespace global podem ser importadas usando o prefixo globalThis
no nome da função e o atributo [JSImport]
sem fornecer um nome de módulo. No exemplo a seguir, console.log
é prefixado com globalThis
. A função importada é chamada pelo método C# Log
, que aceita uma mensagem de cadeia de caracteres C# (message
) e realiza marshaling da cadeia de caracteres C# em um JSString
para console.log
:
[JSImport("globalThis.console.log")]
internal static partial void Log([JSMarshalAs<JSType.String>] string message);
Exporte scripts de um módulo JavaScript ES6 padrão posicionado com um componente ou com outros ativos estáticos JavaScript em um arquivo JS (por exemplo, wwwroot/js/{FILE NAME}.js
, em que ativos estáticos JS são mantidos em uma pasta chamada js
na pasta do aplicativo wwwroot
e o espaço reservado {FILE NAME}
é o nome do arquivo).
No exemplo a seguir, uma função JS chamada getMessage
é exportada de um arquivo JS posicionado que retorna uma mensagem de boas-vindas, "Olá de Blazor!" em português:
CallJavaScript1.razor.js
:
export function getMessage() {
return 'Olá do Blazor!';
}
Chamar .NET do JavaScript
Esta seção explica como chamar métodos .NET de JS.
O componente CallDotNet1
a seguir chama JS que interage diretamente com o DOM para renderizar a cadeia de caracteres de mensagem de boas-vindas:
- O
CallDotNet
módulo JS é importado de forma assíncrona do arquivo JS posicionado para esse componente. - A função
setMessage
JS importada é chamada porSetWelcomeMessage
. - A mensagem de boas-vindas retornada é exibida por
setMessage
na interface do usuário por meio do campomessage
.
Importante
No exemplo desta seção, a interoperabilidadeJS é usada para modificar um elemento DOM puramente para fins de demonstração depois que o componente é renderizado em OnAfterRender
. Normalmente, você só deve alterar o DOM com JS quando o objeto não interage com Blazor. A abordagem mostrada nesta seção é semelhante aos casos em que uma biblioteca de terceiros JS é usada em um componente Razor, em que o componente interage com a biblioteca JS por meio de interoperabilidade JS, a biblioteca de terceiros JS interage com parte do DOM e Blazor não está envolvida diretamente nas atualizações do DOM para essa parte do DOM. Para obter mais informações, confira Interoperabilidade ASP.NET Core Blazor JavaScript (interoperabilidade 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 um método .NET para que ele possa ser chamado de JS, use o atributo [JSExport]
.
No exemplo a seguir:
SetWelcomeMessage
chama uma função JS nomeadasetMessage
. A função JS chama o .NET para receber a mensagem de boas-vindas deGetMessageFromDotnet
e exibe a mensagem na interface do usuário.GetMessageFromDotnet
é um método .NET com o atributo[JSExport]
que retorna uma mensagem de boas-vindas, "Olá de Blazor!" em 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!";
}
}
O namespace do aplicativo para a classe parcial CallDotNet1
anterior é BlazorSample
. O namespace do componente será BlazorSample.Components.Pages
. Se estiver usando o componente anterior em um aplicativo de teste local, atualize o namespace do aplicativo para corresponder ao aplicativo. Por exemplo, o namespace do componente será ContosoApp.Components.Pages
se o namespace do aplicativo for ContosoApp
. Para saber mais, consulte Componentes Razor do ASP.NET Core.
No exemplo a seguir, uma função JS nomeada setMessage
é importada de um arquivo JS posicionado.
O método setMessage
:
- Chamadas
globalThis.getDotnetRuntime(0)
para expor a instância de runtime do .NET do WebAssembly para chamar métodos .NET exportados. - Obtém as exportações do assembly do aplicativo JS. O nome do assembly do aplicativo no exemplo a seguir é
BlazorSample
. - Chama o método
BlazorSample.Components.Pages.CallDotNet1.GetMessageFromDotnet
das exportações (exports
). O valor retornado, que é a mensagem de boas-vindas, é atribuído ao textoCallDotNet1
do componente<span>
. O namespace do aplicativo éBlazorSample
e o namespace do componenteCallDotNet1
éBlazorSample.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!";
}
}
O namespace do aplicativo para a classe parcial CallDotNet1
anterior é BlazorSample
. O namespace do componente será BlazorSample.Pages
. Se estiver usando o componente anterior em um aplicativo de teste local, atualize o namespace do aplicativo para corresponder ao aplicativo. Por exemplo, o namespace do componente será ContosoApp.Pages
se o namespace do aplicativo for ContosoApp
. Para saber mais, consulte Componentes Razor do ASP.NET Core.
No exemplo a seguir, uma função JS nomeada setMessage
é importada de um arquivo JS posicionado.
O método setMessage
:
- Chamadas
globalThis.getDotnetRuntime(0)
para expor a instância de runtime do .NET do WebAssembly para chamar métodos .NET exportados. - Obtém as exportações do assembly do aplicativo JS. O nome do assembly do aplicativo no exemplo a seguir é
BlazorSample
. - Chama o método
BlazorSample.Pages.CallDotNet1.GetMessageFromDotnet
das exportações (exports
). O valor retornado, que é a mensagem de boas-vindas, é atribuído ao textoCallDotNet1
do componente<span>
. O namespace do aplicativo éBlazorSample
e o namespace do componenteCallDotNet1
éBlazorSample.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();
}
Observação
A chamada de getAssemblyExports
para obter as exportações pode ocorrer em um inicializador JavaScript para disponibilidade em todo o aplicativo.
Várias chamadas de importação de módulo
Depois que um módulo JS é carregado, as funções do módulo ficam disponíveis para os componentes e classes do aplicativo, desde que o aplicativo esteja em execução na janela ou guia do navegador JS sem que o usuário recarregue o aplicativo manualmente. JSHost.ImportAsync pode ser chamado várias vezes no mesmo módulo sem uma penalidade de desempenho significativa quando:
- O usuário visita um componente que chama JSHost.ImportAsync para importar um módulo, navega para longe do componente e retorna para o componente em que JSHost.ImportAsync é chamado novamente para a mesma importação de módulo.
- O mesmo módulo é usado por diferentes componentes e carregado por JSHost.ImportAsync em cada um dos componentes.
Uso de um único módulo JavaScript entre componentes
Antes de seguir as diretrizes nesta seção, leia as seções Chamar JavaScript do .NET e Chamar .NET do JavaScript deste artigo, que fornecem diretrizes gerais sobre [JSImport]
/interoperabilidade [JSExport]
.
O exemplo nesta seção mostra como usar a interoperabilidade JS de um módulo JS compartilhado em um aplicativo do lado do cliente. As diretrizes nesta seção não se aplicam a RCLs (bibliotecas de classes) Razor.
Os componentes, classes, métodos C# e funções JS a seguir são usados:
- Classe
Interop
(Interop.cs
): configura a interoperabilidade JS de importação e exportação com os atributos[JSImport]
e[JSExport]
para um módulo nomeadoInterop
.GetWelcomeMessage
: método .NET que chama a funçãogetMessage
JS importada.SetWelcomeMessage
: método .NET que chama a funçãosetMessage
JS importada.GetMessageFromDotnet
: um método C# exportado que retorna uma cadeia de caracteres de mensagem de boas-vindas quando chamado de JS.
- Arquivo
wwwroot/js/interop.js
: contém as funções JS.getMessage
: retorna uma mensagem de boas-vindas quando chamada pelo código C# em um componente.setMessage
: chama o métodoGetMessageFromDotnet
C# e atribui a mensagem de boas-vindas retornada a um elemento<span>
DOM.
Program.cs
chama JSHost.ImportAsync para carregar o módulo dewwwroot/js/interop.js
.- Componente
CallJavaScript2
(CallJavaScript2.razor
): chamaGetWelcomeMessage
e exibe a mensagem de boas-vindas retornada na interface do usuário do componente. - Componente
CallDotNet2
(CallDotNet2.razor
): chamaSetWelcomeMessage
.
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!";
}
}
No exemplo anterior, o namespace do aplicativo é BlazorSample
e o namespace completo das classes de interoperabilidade C# é 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();
}
Disponibilize o namespace System.Runtime.InteropServices.JavaScript na parte superior do arquivo Program.cs
:
using System.Runtime.InteropServices.JavaScript;
Carregue o módulo em Program.cs
antes de WebAssemblyHost.RunAsync ser chamado:
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
No exemplo desta seção, a interoperabilidadeJS é usada para modificar um elemento DOM puramente para fins de demonstração depois que o componente é renderizado em OnAfterRender
. Normalmente, você só deve alterar o DOM com JS quando o objeto não interage com Blazor. A abordagem mostrada nesta seção é semelhante aos casos em que uma biblioteca de terceiros JS é usada em um componente Razor, em que o componente interage com a biblioteca JS por meio de interoperabilidade JS, a biblioteca de terceiros JS interage com parte do DOM e Blazor não está envolvida diretamente nas atualizações do DOM para essa parte do DOM. Para obter mais informações, confira Interoperabilidade ASP.NET Core Blazor JavaScript (interoperabilidade JS).
Recursos adicionais
- Documentação da API
- Executar .NET do JavaScript
- No repositório do GitHub
dotnet/runtime
:
Comentários
https://aka.ms/ContentUserFeedback.
Em breve: Ao longo de 2024, eliminaremos os problemas do GitHub como o mecanismo de comentários para conteúdo e o substituiremos por um novo sistema de comentários. Para obter mais informações, consulteEnviar e exibir comentários de