Взаимодействие JavaScript [JSImport]/[JSExport] с ASP.NET Core Blazor

Примечание.

Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 8 этой статьи.

Внимание

Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

В текущем выпуске см . версию .NET 8 этой статьи.

В этой статье объясняется, как взаимодействовать с JavaScript () в клиентских компонентах с помощью API взаимодействия JavaScript (JSJS), [JSImport]/[JSExport] выпущенного для приложений, использующих .NET 7 или более поздней версии.

Blazor предоставляет собственный JS механизм взаимодействия на IJSRuntime основе интерфейса. BlazorJS Взаимодействие поддерживается Blazor в режимах отрисовки и для Blazor Hybrid приложений. IJSRuntimeтакже позволяет авторам библиотек создавать JS библиотеки взаимодействия для совместного использования в экосистеме Blazor и остается рекомендуемым подходом для JS взаимодействия.Blazor См. следующие статьи:

В этой статье описывается альтернативный JS подход взаимодействия, характерный для клиентских компонентов, выполняемых в WebAssembly. Эти подходы подходы подходят только для выполнения только на стороне клиента WebAssembly. Авторы библиотеки могут использовать эти подходы для оптимизации JS взаимодействия, проверка во время выполнения кода, если приложение работает в WebAssembly в браузере (OperatingSystem.IsBrowser). Подходы, описанные в этой статье, следует использовать для замены устаревшего немаршилированного JS API взаимодействия при миграции на .NET 7 или более поздней версии.

Примечание.

В этой статье основное внимание уделяется JS взаимодействиям в клиентских компонентах. Рекомендации по вызову .NET в приложениях JavaScript см. в статье Запуск .NET из JavaScript.

Устаревший API взаимодействия JavaScript

Немарсхоллированные JS взаимодействия с ПОМОЩЬЮ IJSUnmarshalledRuntime API устарели в ASP.NET Core в .NET 7 или более поздней версии. Следуйте инструкциям из этой статьи, чтобы заменить устаревший API.

Необходимые компоненты

Скачайте и установите .NET 7 или более поздней версии , если она еще не установлена в системе или если у системы нет последней версии.

Пространство имен

API взаимодействия, описанный JS в этой статье, управляется атрибутами в System.Runtime.InteropServices.JavaScript пространстве имен.

Включение небезопасных блоков

AllowUnsafeBlocks Включите свойство в файле проекта приложения, который позволяет генератору кода в компиляторе Roslyn использовать указатели для JS взаимодействия:

<PropertyGroup>
  <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

Предупреждение

JS API взаимодействия требует включенияAllowUnsafeBlocks. Будьте осторожны при реализации собственного небезопасного кода в приложениях .NET, что может привести к рискам безопасности и стабильности. Дополнительные сведения см. в разделе "Небезопасный код", "типы указателей" и указатели функций.

Вызов JavaScript из .NET

В этом разделе объясняется, как вызывать JS функции из .NET.

Следующий компонент CallJavaScript1:

  • Модуль CallJavaScript1 импортируется асинхронно из файла с сортировкойJSJSHost.ImportAsync.
  • Импортированная getMessageJS функция вызывается GetWelcomeMessage.
  • Возвращаемая строка приветственного сообщения отображается в пользовательском интерфейсе 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();
    }
}

Примечание.

Включите условный проверка в код, OperatingSystem.IsBrowser чтобы убедиться, что JS взаимодействие вызывается только компонентом, отображаемым на клиенте. Это важно для библиотек и пакетов NuGet, предназначенных для компонентов на стороне сервера, которые не могут выполнять код, предоставленный этим JS API взаимодействия.

Чтобы импортировать JS функцию для вызова из C#, используйте [JSImport] атрибут в сигнатуре метода C#, которая соответствует JS сигнатуре функции. Первым параметром атрибута [JSImport] является имя функции для JS импорта, а второй параметр — имя JS модуля.

В следующем примере — это функция, getMessage которая возвращает string для модуля с именемCallJavaScript1.JS Сигнатура метода C# совпадает: параметры не передаются JS в функцию, а JS функция возвращает значение string. Функция JS вызывается в коде GetWelcomeMessage 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();
}

Пространство имен приложения для предыдущего CallJavaScript1 частичного класса BlazorSample. Пространство имен компонента .BlazorSample.Components.Pages При использовании предыдущего компонента в локальном тестовом приложении обновите пространство имен, чтобы оно соответствовало приложению. Например, пространство имен — это ContosoApp.Components.Pages пространство ContosoAppимен приложения. Дополнительные сведения см. в статье Компоненты Razor 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();
}

Пространство имен приложения для предыдущего CallJavaScript1 частичного класса BlazorSample. Пространство имен компонента .BlazorSample.Pages При использовании предыдущего компонента в локальном тестовом приложении обновите пространство имен, чтобы оно соответствовало приложению. Например, пространство имен — это ContosoApp.Pages пространство ContosoAppимен приложения. Дополнительные сведения см. в статье Компоненты Razor ASP.NET Core.

В импортированной сигнатуре метода можно использовать типы .NET для параметров и возвращаемых значений, которые автоматически маршалируются средой выполнения. Используется JSMarshalAsAttribute<T> для управления маршаллами импортированных параметров метода. Например, можно выбрать маршалировать как longSystem.Runtime.InteropServices.JavaScript.JSType.Number или System.Runtime.InteropServices.JavaScript.JSType.BigInt. Обратные вызовы можно передавать Action/Func<TResult> в качестве параметров, которые маршалируются как вызываемые JS функции. Вы можете передавать JS как ссылки на управляемые объекты, так и маршалируются как прокси-объекты, сохраняя объект в живых по границе, пока прокси-сервер не собирает мусор. Вы также можете импортировать и экспортировать асинхронные методы с результатом Task , которые маршалируются в качестве JS обещаний. Большинство маршаллированных типов работают в обоих направлениях в качестве параметров и возвращаемых значений в импортированных и экспортированных методах, которые рассматриваются в разделе Call .NET из JavaScript далее в этой статье.

В следующей таблице указаны поддерживаемые сопоставления типов.

.NET JavaScript Nullable Task➔toPromise JSMarshalAs Дополнительные Array of
Boolean Boolean Поддерживается Поддерживается Поддерживается Не поддерживаются
Byte Number Поддерживается Поддерживается Поддерживается Поддерживается
Char String Поддерживается Поддерживается Поддерживается Не поддерживаются
Int16 Number Поддерживается Поддерживается Поддерживается Не поддерживаются
Int32 Number Поддерживается Поддерживается Поддерживается Поддерживается
Int64 Number Поддерживается Поддерживается Не поддерживаются Не поддерживаются
Int64 BigInt Поддерживается Поддерживается Не поддерживаются Не поддерживаются
Single Number Поддерживается Поддерживается Поддерживается Не поддерживаются
Double Number Поддерживается Поддерживается Поддерживается Поддерживается
IntPtr Number Поддерживается Поддерживается Поддерживается Не поддерживаются
DateTime Date Поддерживается Поддерживается Не поддерживаются Не поддерживаются
DateTimeOffset Date Поддерживается Поддерживается Не поддерживаются Не поддерживаются
Exception Error Не поддерживаются Поддерживается Поддерживается Не поддерживаются
JSObject Object Не поддерживаются Поддерживается Поддерживается Поддерживается
String String Не поддерживаются Поддерживается Поддерживается Поддерживается
Object Any Не поддерживаются Поддерживается Не поддерживаются Поддерживается
Span<Byte> MemoryView Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
Span<Int32> MemoryView Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
Span<Double> MemoryView Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
ArraySegment<Byte> MemoryView Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
ArraySegment<Int32> MemoryView Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
ArraySegment<Double> MemoryView Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
Task Promise Не поддерживаются Не поддерживаются Поддерживается Не поддерживаются
Action Function Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
Action<T1> Function Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
Action<T1, T2> Function Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
Action<T1, T2, T3> Function Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
Func<TResult> Function Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
Func<T1, TResult> Function Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
Func<T1, T2, TResult> Function Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
Func<T1, T2, T3, TResult> Function Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются

Следующие условия применяются к сопоставлению типов и маршализированным значениям:

  • Столбец Array of указывает, можно ли маршалировать тип .NET в виде JSArray. Пример: C# int[] (Int32) сопоставлен с JSArrayNumbers.
  • При передаче JS значения в C# со значением неправильного типа платформа создает исключение в большинстве случаев. Платформа не выполняет тип времени компиляции проверка в JS.
  • JSObjectTask, Exceptionи создание GCHandle и ArraySegment прокси-сервер. Вы можете активировать удаление в коде разработчика или разрешить сборку мусора .NET (GC) удалять объекты позже. Эти типы несут значительные затраты на производительность.
  • Array: маршалинг массива создает копию массива в JS или .NET.
  • MemoryView
    • MemoryViewJS— это класс среды выполнения .NET WebAssembly для маршалирования Span и ArraySegment.
    • В отличие от маршалинга массива, маршалинг или SpanArraySegment не создает копию базовой памяти.
    • MemoryView может быть правильно создано средой выполнения .NET WebAssembly. Поэтому невозможно импортировать JS функцию как метод .NET, имеющий параметр Span или ArraySegment.
    • MemoryView создается только для Span срока вызова взаимодействия. Как Span и в стеке вызовов, который не сохраняется после вызова взаимодействия, невозможно экспортировать метод .NET, который возвращает Span.
    • MemoryView создано для ArraySegment выживания после вызова взаимодействия и полезно для совместного использования буфера. Вызов dispose() созданного MemoryViewArraySegment для удаления прокси-сервера и открепляет базовый массив .NET. Рекомендуется вызывать dispose() блок try-finally для MemoryView.

В следующей таблице указаны поддерживаемые сопоставления типов.

.NET JavaScript Nullable Task➔toPromise JSMarshalAs Дополнительные Array of
Boolean Boolean Поддерживается Поддерживается Поддерживается Не поддерживаются
Byte Number Поддерживается Поддерживается Поддерживается Поддерживается
Char String Поддерживается Поддерживается Поддерживается Не поддерживаются
Int16 Number Поддерживается Поддерживается Поддерживается Не поддерживаются
Int32 Number Поддерживается Поддерживается Поддерживается Поддерживается
Int64 Number Поддерживается Поддерживается Не поддерживаются Не поддерживаются
Int64 BigInt Поддерживается Поддерживается Не поддерживаются Не поддерживаются
Single Number Поддерживается Поддерживается Поддерживается Не поддерживаются
Double Number Поддерживается Поддерживается Поддерживается Поддерживается
IntPtr Number Поддерживается Поддерживается Поддерживается Не поддерживаются
DateTime Date Поддерживается Поддерживается Не поддерживаются Не поддерживаются
DateTimeOffset Date Поддерживается Поддерживается Не поддерживаются Не поддерживаются
Exception Error Не поддерживаются Поддерживается Поддерживается Не поддерживаются
JSObject Object Не поддерживаются Поддерживается Поддерживается Поддерживается
String String Не поддерживаются Поддерживается Поддерживается Поддерживается
Object Any Не поддерживаются Поддерживается Не поддерживаются Поддерживается
Span<Byte> MemoryView Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
Span<Int32> MemoryView Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
Span<Double> MemoryView Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
ArraySegment<Byte> MemoryView Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
ArraySegment<Int32> MemoryView Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
ArraySegment<Double> MemoryView Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
Task Promise Не поддерживаются Не поддерживаются Поддерживается Не поддерживаются
Action Function Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
Action<T1> Function Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
Action<T1, T2> Function Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
Action<T1, T2, T3> Function Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
Func<TResult> Function Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
Func<T1, TResult> Function Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
Func<T1, T2, TResult> Function Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются
Func<T1, T2, T3, TResult> Function Не поддерживаются Не поддерживаются Не поддерживаются Не поддерживаются

Следующие условия применяются к сопоставлению типов и маршализированным значениям:

  • Столбец Array of указывает, можно ли маршалировать тип .NET в виде JSArray. Пример: C# int[] (Int32) сопоставлен с JSArrayNumbers.
  • При передаче JS значения в C# со значением неправильного типа платформа создает исключение в большинстве случаев. Платформа не выполняет тип времени компиляции проверка в JS.
  • JSObjectTask, Exceptionи создание GCHandle и ArraySegment прокси-сервер. Вы можете активировать удаление в коде разработчика или разрешить сборку мусора .NET (GC) удалять объекты позже. Эти типы несут значительные затраты на производительность.
  • Array: маршалинг массива создает копию массива в JS или .NET.
  • MemoryView
    • MemoryViewJS— это класс среды выполнения .NET WebAssembly для маршалирования Span и ArraySegment.
    • В отличие от маршалинга массива, маршалинг или SpanArraySegment не создает копию базовой памяти.
    • MemoryView может быть правильно создано средой выполнения .NET WebAssembly. Поэтому невозможно импортировать JS функцию как метод .NET, имеющий параметр Span или ArraySegment.
    • MemoryView создается только для Span срока вызова взаимодействия. Как Span и в стеке вызовов, который не сохраняется после вызова взаимодействия, невозможно экспортировать метод .NET, который возвращает Span.
    • MemoryView создано для ArraySegment выживания после вызова взаимодействия и полезно для совместного использования буфера. Вызов dispose() созданного MemoryViewArraySegment для удаления прокси-сервера и открепляет базовый массив .NET. Рекомендуется вызывать dispose() блок try-finally для MemoryView.

Имя модуля в атрибуте [JSImport] и вызов загрузки модуля в компоненте JSHost.ImportAsync должен совпадать и быть уникальным в приложении. При создании библиотеки для развертывания в пакете NuGet рекомендуется использовать пространство имен пакета NuGet в качестве префикса в именах модулей. В следующем примере имя модуля отражает Contoso.InteropServices.JavaScript пакет и папку классов взаимодействия с сообщением пользователя (UserMessages):

[JSImport("getMessage", 
    "Contoso.InteropServices.JavaScript.UserMessages.CallJavaScript1")]

Функции, доступные в глобальном пространстве имен, можно импортировать с помощью globalThis префикса в имени функции и с помощью атрибута [JSImport] без предоставления имени модуля. В следующем примере console.log префикс с префиксом globalThis. Импортированная функция вызывается методом C#Log, который принимает строковое сообщение C# (message) и маршалирует строку C# дляStringJSconsole.log:

[JSImport("globalThis.console.log")]
internal static partial void Log([JSMarshalAs<JSType.String>] string message);

Экспорт скриптов из стандартного модуля JavaScript ES6 с компонентом или размещением с другими статическими ресурсами JavaScript в JS файле (например, wwwroot/js/{FILE NAME}.jsесли JS статические ресурсы хранятся в папке js приложенияwwwroot, а {FILE NAME} заполнитель — это имя файла).

В следующем примере JS функция с именем getMessage экспортируется из коллакуированного JS файла, возвращающего приветственное сообщение "Hello from Blazor!" на португальском языке:

CallJavaScript1.razor.js:

export function getMessage() {
  return 'Olá do Blazor!';
}

Вызов .NET из JavaScript

В этом разделе объясняется, как вызывать методы .NET из JS.

CallDotNet1 Следующий компонент вызываетJS, который напрямую взаимодействует с DOM для отрисовки строки приветственного сообщения:

  • Модуль CallDotNetJS импортируется асинхронно из файла с сортировкой JS для этого компонента.
  • Импортированная setMessageJS функция вызывается SetWelcomeMessage.
  • Возвращенное приветственное сообщение отображается setMessage в пользовательском интерфейсе через message поле.

Внимание

В этом примере JS взаимодействие используется для мутации элемента DOM исключительно для демонстрационных целей после отрисовки OnAfterRenderкомпонента. Как правило, следует изменять только DOM, JS если объект не взаимодействует Blazor. Подход, показанный в этом разделе, аналогичен случаям JS , когда сторонняя библиотека используется в Razor компоненте, где компонент взаимодействует с JS библиотекой через JS взаимодействие, сторонняя JS библиотека взаимодействует с частью DOM и Blazor не участвует непосредственно с обновлениями DOM для этой части DOM. Дополнительные сведения см. в разделе Взаимодействие JavaScript приложения Blazor ASP.NET Core (взаимодействие 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();
        }
    }
}

Чтобы экспортировать метод .NET, чтобы его можно было вызвать, JSиспользуйте [JSExport] атрибут.

В следующем примере :

  • SetWelcomeMessage вызывает функцию JS с именем setMessage. Функция JS вызывается в .NET для получения приветственного сообщения и GetMessageFromDotnet отображает сообщение в пользовательском интерфейсе.
  • GetMessageFromDotnet — это метод .NET с [JSExport] атрибутом, который возвращает приветственное сообщение " Hello from Blazor!" в португальском языке.

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!";
    }
}

Пространство имен приложения для предыдущего CallDotNet1 частичного класса BlazorSample. Пространство имен компонента .BlazorSample.Components.Pages При использовании предыдущего компонента в локальном тестовом приложении обновите пространство имен приложения, чтобы оно соответствовало приложению. Например, пространство имен компонента — это ContosoApp.Components.Pages пространство ContosoAppимен приложения. Дополнительные сведения см. в статье Компоненты Razor ASP.NET Core.

В следующем примере JS функция с именем setMessage импортируется из файлов с сортировкой JS .

Метод setMessage:

  • Вызовы globalThis.getDotnetRuntime(0) для предоставления экземпляра среды выполнения .NET WebAssembly для вызова экспортированных методов .NET.
  • Получает экспорт сборки JS приложения. Имя сборки приложения в следующем примере BlazorSample.
  • BlazorSample.Components.Pages.CallDotNet1.GetMessageFromDotnet Вызывает метод из экспорта (exports). Возвращаемое значение, которое является приветственным сообщением, назначается CallDotNet1 тексту компонента <span> . Пространство имен приложения — это BlazorSampleпространство имен, а CallDotNet1 пространство имен компонента — 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!";
    }
}

Пространство имен приложения для предыдущего CallDotNet1 частичного класса BlazorSample. Пространство имен компонента .BlazorSample.Pages При использовании предыдущего компонента в локальном тестовом приложении обновите пространство имен приложения, чтобы оно соответствовало приложению. Например, пространство имен компонента — это ContosoApp.Pages пространство ContosoAppимен приложения. Дополнительные сведения см. в статье Компоненты Razor ASP.NET Core.

В следующем примере JS функция с именем setMessage импортируется из файлов с сортировкой JS .

Метод setMessage:

  • Вызовы globalThis.getDotnetRuntime(0) для предоставления экземпляра среды выполнения .NET WebAssembly для вызова экспортированных методов .NET.
  • Получает экспорт сборки JS приложения. Имя сборки приложения в следующем примере BlazorSample.
  • BlazorSample.Pages.CallDotNet1.GetMessageFromDotnet Вызывает метод из экспорта (exports). Возвращаемое значение, которое является приветственным сообщением, назначается CallDotNet1 тексту компонента <span> . Пространство имен приложения — это BlazorSampleпространство имен, а CallDotNet1 пространство имен компонента — 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();
}

Примечание.

Вызов getAssemblyExports для получения экспортов может выполняться в инициализаторе JavaScript для доступности в приложении.

Несколько вызовов импорта модуля

JS После загрузки модуля функции модуля JS доступны для компонентов и классов приложения, пока приложение выполняется в окне браузера или на вкладке без перезагрузки приложения вручную. JSHost.ImportAsync можно вызывать несколько раз в одном модуле без значительного штрафа производительности, если:

  • Пользователь посещает компонент, вызывающий JSHost.ImportAsync импорт модуля, перемещается от компонента, а затем возвращается к компоненту, где JSHost.ImportAsync вызывается снова для импорта одного модуля.
  • Один и тот же модуль используется разными компонентами и загружается JSHost.ImportAsync в каждом из компонентов.

Использование одного модуля JavaScript для компонентов

Прежде чем следовать инструкциям в этом разделе, ознакомьтесь с разделами JavaScript для вызова JavaScript из .NET и вызова .NET из разделов этой статьи, которые предоставляют общие рекомендации по [JSImport]/[JSExport] взаимодействиям.

В этом разделе показано, как использовать JS взаимодействие из общего JS модуля в клиентском приложении. Руководство в этом разделе не применимо к Razor библиотекам классов (RCLs).

Используются следующие компоненты, классы, методы C# и JS функции:

  • Interop класс (Interop.cs): настройка взаимодействия импорта и экспорта JS с [JSImport][JSExport] атрибутами для модуля с именем Interop.
    • GetWelcomeMessage: метод .NET, вызывающий импортированную getMessageJS функцию.
    • SetWelcomeMessage: метод .NET, вызывающий импортированную setMessageJS функцию.
    • GetMessageFromDotnet: экспортируемый метод C#, который возвращает строку приветственного сообщения при вызове из JS.
  • wwwroot/js/interop.js файл: содержит JS функции.
    • getMessage: возвращает приветственное сообщение при вызове кода C# в компоненте.
    • setMessage: вызывает GetMessageFromDotnet метод C# и назначает возвращенное приветственное сообщение элементу DOM <span> .
  • Program.cs вызовы JSHost.ImportAsync для загрузки модуля из wwwroot/js/interop.js.
  • CallJavaScript2 компонент (CallJavaScript2.razor): вызовы GetWelcomeMessage и отображение возвращаемого приветственного сообщения в пользовательском интерфейсе компонента.
  • CallDotNet2 компонент (CallDotNet2.razor): вызовы SetWelcomeMessage.

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!";
    }
}

В предыдущем примере пространство имен приложения — BlazorSampleэто пространство имен и полное пространство имен для классов BlazorSample.JavaScriptInteropвзаимодействия C#.

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();
}

Сделайте System.Runtime.InteropServices.JavaScript пространство имен доступным в верхней части Program.cs файла:

using System.Runtime.InteropServices.JavaScript;

Загрузите модуль Program.cs перед 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();
        }
    }
}

Внимание

В этом примере JS взаимодействие используется для мутации элемента DOM исключительно для демонстрационных целей после отрисовки OnAfterRenderкомпонента. Как правило, следует изменять только DOM, JS если объект не взаимодействует Blazor. Подход, показанный в этом разделе, аналогичен случаям JS , когда сторонняя библиотека используется в Razor компоненте, где компонент взаимодействует с JS библиотекой через JS взаимодействие, сторонняя JS библиотека взаимодействует с частью DOM и Blazor не участвует непосредственно с обновлениями DOM для этой части DOM. Дополнительные сведения см. в разделе Взаимодействие JavaScript приложения Blazor ASP.NET Core (взаимодействие JS).

Дополнительные ресурсы