Взаимодействие JavaScript [JSImport]
/[JSExport]
с проектом приложения браузера WebAssembly
Примечание.
Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 9 этой статьи.
Предупреждение
Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в политике поддержки .NET и .NET Core. В текущем выпуске см . версию .NET 9 этой статьи.
Внимание
Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
В текущем выпуске см . версию .NET 9 этой статьи.
В этой статье объясняется, как настроить проект приложения браузера WebAssembly для запуска .NET из JavaScript (JS) с помощью JS[JSImport]
/[JSExport]
взаимодействия. Дополнительные сведения и примеры см. в статье JavaScript "[JSImport]'/[JSExport]" interop in .NET WebAssembly.
Дополнительные рекомендации см. в руководстве по настройке и размещению приложений .NET WebAssembly в репозитории GitHub .NET Runtime (dotnet/runtime
).
Существующие JS приложения могут использовать расширенную поддержку WebAssembly на стороне клиента для повторного использования библиотек .NET из JS или для создания романа. Приложения и платформы на основе NET.
Примечание.
В этой статье рассматривается запуск .NET из JS приложений без каких-либо зависимостей Blazor. Рекомендации по использованию [JSImport]
/[JSExport]
взаимодействия в приложениях см. в Blazor WebAssembly разделе взаимодействия JavaScript JSImport/JSExport с ASP.NET Core.Blazor
Эти подходы подходы подходят только при ожидании Blazor запуска приложения в WebAssembly (WASM). Библиотеки могут проверить среду выполнения, чтобы определить, работает WASM ли приложение путем вызова OperatingSystem.IsBrowser.
Необходимые компоненты
Пакет SDK для .NET (последняя версия)
Установите рабочую нагрузку wasm-tools
в командной оболочке администрирования, которая приводит к соответствующим целевым объектам MSBuild:
dotnet workload install wasm-tools
Средства также можно установить с помощью установщика Visual Studio в ASP.NET и рабочей нагрузке веб-разработки в установщике Visual Studio. Выберите параметр средств сборки .NET WebAssembly из списка необязательных компонентов.
При необходимости установите рабочую нагрузку wasm-experimental
, которая добавляет следующие экспериментальные шаблоны проектов:
- Приложение браузера WebAssembly для начала работы с .NET в WebAssembly в приложении браузера.
- Консольное приложение WebAssembly для начала работы с узлом.jsконсольное приложение на основе.
После установки рабочей нагрузки эти новые шаблоны можно выбрать при создании нового проекта. Эта рабочая нагрузка не требуется, если планируется интегрировать JS[JSExport]
[JSImport]
/взаимодействие в существующее JS приложение.
dotnet workload install wasm-experimental
Шаблоны также можно установить из пакета NuGet с помощью следующей Microsoft.NET.Runtime.WebAssembly.Templates
команды:
dotnet new install Microsoft.NET.Runtime.WebAssembly.Templates
Дополнительные сведения см. в разделе " Экспериментальная рабочая нагрузка и шаблоны проектов ".
Пространство имен
API взаимодействия, описанный JS в этой статье, управляется атрибутами в System.Runtime.InteropServices.JavaScript пространстве имен.
Конфигурация проекта
Чтобы настроить проект (.csproj
) для включения JS взаимодействия:
Задайте моникер целевой платформы (
{TARGET FRAMEWORK}
заполнитель):<TargetFramework>{TARGET FRAMEWORK}</TargetFramework>
Поддерживается .NET 7 (
net7.0
) или более поздней версии.AllowUnsafeBlocks Включите свойство, которое позволяет генератору кода в компиляторе Roslyn использовать указатели для JS взаимодействия:
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
Предупреждение
JS API взаимодействия требует включенияAllowUnsafeBlocks. Будьте осторожны при реализации собственного небезопасного кода в приложениях .NET, что может привести к рискам безопасности и стабильности. Дополнительные сведения см. в разделе "Небезопасный код", "типы указателей" и указатели функций.
Ниже приведен пример файла проекта (.csproj
) после настройки. Заполнитель {TARGET FRAMEWORK}
— это целевая платформа:
<Project Sdk="Microsoft.NET.Sdk.WebAssembly">
<PropertyGroup>
<TargetFramework>{TARGET FRAMEWORK}</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
</Project>
Задайте моникер целевой платформы:
<TargetFramework>net7.0</TargetFramework>
Поддерживается .NET 7 (
net7.0
) или более поздней версии.Укажите
browser-wasm
идентификатор среды выполнения:<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
Укажите тип выходных данных исполняемого файла:
<OutputType>Exe</OutputType>
AllowUnsafeBlocks Включите свойство, которое позволяет генератору кода в компиляторе Roslyn использовать указатели для JS взаимодействия:
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
Предупреждение
JS API взаимодействия требует включенияAllowUnsafeBlocks. Будьте осторожны при реализации собственного небезопасного кода в приложениях .NET, что может привести к рискам безопасности и стабильности. Дополнительные сведения см. в разделе "Небезопасный код", "типы указателей" и указатели функций.
Укажите
WasmMainJSPath
, чтобы указать файл на диске. Этот файл публикуется с приложением, но использование файла не требуется, если вы интегрируете .NET в существующее JS приложение.В следующем примере JS файл на диске доступен
main.js
, но любое JS имя файла является допустимым:<WasmMainJSPath>main.js</WasmMainJSPath>
Пример файла проекта (.csproj
) после настройки:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
<OutputType>Exe</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<WasmMainJSPath>main.js</WasmMainJSPath>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
Взаимодействие JavaScript в WASM
API в следующем примере импортируются из dotnet.js
. Эти API позволяют настраивать именованные модули, которые можно импортировать в код C# и вызывать методы, предоставляемые кодом .NET, в том числе Program.Main
.
Внимание
Импорт и экспорт в этой статье определяются с точки зрения .NET:
- Методы импорта JS приложения, чтобы их можно было вызывать из .NET.
- Приложение экспортирует методы .NET, чтобы их можно было вызывать из JS.
В следующем примере :
Файл
dotnet.js
используется для создания и запуска среды выполнения .NET WebAssembly.dotnet.js
создается в рамках выходных данных сборки приложения.Внимание
Чтобы интегрироваться с существующим приложением, скопируйте содержимое выходной папки публикации† в ресурсы развертывания существующего приложения, чтобы его можно было обслуживать вместе с rest приложением. Для рабочих развертываний опубликуйте приложение с
dotnet publish -c Release
помощью команды в командной оболочке и разверните содержимое выходной папки с помощью приложения.† Папка вывода публикации — это целевое расположение профиля публикации. По умолчанию для Release профиля в .NET 8 или более поздней версии используется
bin/Release/{TARGET FRAMEWORK}/publish
{TARGET FRAMEWORK}
заполнитель — целевая платформа (например,net8.0
).dotnet.create()
настраивает среду выполнения .NET WebAssembly.
setModuleImports
связывает имя с модулем функций для импорта JS в .NET. Модуль JS содержитdom.setInnerText
функцию, которая принимает и селектор элементов и время для отображения текущего времени стоп-часов в пользовательском интерфейсе. Имя модуля может быть любой строкой (она не должна быть именем файла), но она должна соответствовать имени, используемому сJSImportAttribute
(описано далее в этой статье). Функцияdom.setInnerText
импортируется в C# и вызывается методомSetInnerText
C#. ЭтотSetInnerText
метод показан далее в этом разделе.exports.StopwatchSample.Reset()
вызовы в .NET (StopwatchSample.Reset
) из JS. МетодReset
C# перезапускает стоп-часы, если он запущен или сбрасывает его, если он не запущен. ЭтотReset
метод показан далее в этом разделе.exports.StopwatchSample.Toggle()
вызовы в .NET (StopwatchSample.Toggle
) из JS. МетодToggle
C# запускает или останавливает стоп-часы в зависимости от того, запущен ли он в данный момент или нет. ЭтотToggle
метод показан далее в этом разделе.runMain()
выполняетсяProgram.Main
.
setModuleImports
связывает имя с модулем функций для импорта JS в .NET. Модуль JS содержит функцию, которая возвращает текущийwindow.location.href
адрес страницы (URL-адрес). Имя модуля может быть любой строкой (она не должна быть именем файла), но она должна соответствовать имени, используемому сJSImportAttribute
(описано далее в этой статье). Функцияwindow.location.href
импортируется в C# и вызывается методомGetHRef
C#. ЭтотGetHRef
метод показан далее в этом разделе.exports.MyClass.Greeting()
вызовы в .NET (MyClass.Greeting
) из JS. МетодGreeting
C# возвращает строку, содержащую результат вызоваwindow.location.href
функции. ЭтотGreeting
метод показан далее в этом разделе.dotnet.run()
выполняетсяProgram.Main
.
JS модуль:
import { dotnet } from './_framework/dotnet.js'
const { setModuleImports, getAssemblyExports, getConfig, runMain } = await dotnet
.withApplicationArguments("start")
.create();
setModuleImports('main.js', {
dom: {
setInnerText: (selector, time) =>
document.querySelector(selector).innerText = time
}
});
const config = getConfig();
const exports = await getAssemblyExports(config.mainAssemblyName);
document.getElementById('reset').addEventListener('click', e => {
exports.StopwatchSample.Reset();
e.preventDefault();
});
const pauseButton = document.getElementById('pause');
pauseButton.addEventListener('click', e => {
const isRunning = exports.StopwatchSample.Toggle();
pauseButton.innerText = isRunning ? 'Pause' : 'Start';
e.preventDefault();
});
await runMain();
import { dotnet } from './_framework/dotnet.js'
const { setModuleImports, getAssemblyExports, getConfig } = await dotnet
.withDiagnosticTracing(false)
.withApplicationArgumentsFromQuery()
.create();
setModuleImports('main.js', {
window: {
location: {
href: () => globalThis.window.location.href
}
}
});
const config = getConfig();
const exports = await getAssemblyExports(config.mainAssemblyName);
const text = exports.MyClass.Greeting();
console.log(text);
document.getElementById('out').innerHTML = text;
await dotnet.run();
import { dotnet } from './dotnet.js'
const is_browser = typeof window != "undefined";
if (!is_browser) throw new Error(`Expected to be running in a browser`);
const { setModuleImports, getAssemblyExports, getConfig } =
await dotnet.create();
setModuleImports("main.js", {
window: {
location: {
href: () => globalThis.window.location.href
}
}
});
const config = getConfig();
const exports = await getAssemblyExports(config.mainAssemblyName);
const text = exports.MyClass.Greeting();
console.log(text);
document.getElementById("out").innerHTML = text;
await dotnet.run();
Чтобы импортировать JS функцию, чтобы ее можно было вызвать из C#, используйте новую JSImportAttribute сигнатуру соответствующего метода. Первым параметром JSImportAttribute является имя функции для JS импорта, а второй параметр — имя модуля.
В следующем примере dom.setInnerText
функция вызывается из main.js
модуля при SetInnerText
вызове метода:
[JSImport("dom.setInnerText", "main.js")]
internal static partial void SetInnerText(string selector, string content);
В следующем примере window.location.href
функция вызывается из main.js
модуля при GetHRef
вызове метода:
[JSImport("window.location.href", "main.js")]
internal static partial string GetHRef();
В импортированной сигнатуре метода можно использовать типы .NET для параметров и возвращаемых значений, которые автоматически маршалируются средой выполнения. Используется JSMarshalAsAttribute<T> для управления маршаллами импортированных параметров метода. Например, можно выбрать маршалировать как long
System.Runtime.InteropServices.JavaScript.JSType.Number или System.Runtime.InteropServices.JavaScript.JSType.BigInt. Обратные вызовы можно передавать Action/Func<TResult> в качестве параметров, которые маршалируются как вызываемые JS функции. Вы можете передавать JS как ссылки на управляемые объекты, так и маршалируются как прокси-объекты, сохраняя объект в живых по границе, пока прокси-сервер не собирает мусор. Вы также можете импортировать и экспортировать асинхронные методы с результатом Task , которые маршалируются в качестве JS обещаний. Большинство маршаллированных типов работают в обоих направлениях в качестве параметров и возвращаемых значений в импортированных и экспортированных методах.
Дополнительные сведения о сопоставлении типов и примеры см . в статье JavaScript "[JSImport]"/[JSExport]" interop in .NET WebAssembly.
Функции, доступные в глобальном пространстве имен, можно импортировать с помощью globalThis
префикса в имени функции и с помощью атрибута [JSImport]
без предоставления имени модуля. В следующем примере console.log
префикс с префиксом globalThis
. Импортированная функция вызывается методом C#Log
, который принимает строковое сообщение C# (message
) и маршалирует строку C# дляString
JSconsole.log
:
[JSImport("globalThis.console.log")]
internal static partial void Log([JSMarshalAs<JSType.String>] string message);
Чтобы экспортировать метод .NET, чтобы его можно было вызвать из JS, используйте метод JSExportAttribute.
В следующем примере каждый метод экспортируется JS в функции и может вызываться из JS функций:
- Метод
Toggle
запускает или останавливает секундомер в зависимости от состояния выполнения. - Метод
Reset
перезапускает стоп-часы, если он запущен или сбрасывает его, если он не запущен. - Метод
IsRunning
указывает, запущен ли стоп-часы.
[JSExport]
internal static bool Toggle()
{
if (stopwatch.IsRunning)
{
stopwatch.Stop();
return false;
}
else
{
stopwatch.Start();
return true;
}
}
[JSExport]
internal static void Reset()
{
if (stopwatch.IsRunning)
stopwatch.Restart();
else
stopwatch.Reset();
Render();
}
[JSExport]
internal static bool IsRunning() => stopwatch.IsRunning;
В следующем примере Greeting
метод возвращает строку, содержащую результат вызова GetHRef
метода. Как показано ранее, GetHref
метод C# вызывает JS window.location.href
функцию из main.js
модуля. window.location.href
возвращает текущий адрес страницы (URL-адрес):
[JSExport]
internal static string Greeting()
{
var text = $"Hello, World! Greetings from {GetHRef()}";
Console.WriteLine(text);
return text;
}
Экспериментальная рабочая нагрузка и шаблоны проектов
Чтобы продемонстрировать функциональные JS возможности взаимодействия и получить JS шаблоны проектов взаимодействия, установите рабочую нагрузку wasm-experimental
:
dotnet workload install wasm-experimental
wasm-experimental
Рабочая нагрузка содержит два шаблона проекта: wasmbrowser
и wasmconsole
. Эти шаблоны являются экспериментальными в настоящее время, что означает, что рабочий процесс разработчика для шаблонов развивается. Однако api и .NET JS , используемые в шаблонах, поддерживаются в .NET 8 и предоставляют основу для использования .NET в WASM JS.
Шаблоны также можно установить из пакета NuGet с помощью следующей Microsoft.NET.Runtime.WebAssembly.Templates
команды:
dotnet new install Microsoft.NET.Runtime.WebAssembly.Templates
Приложение браузера
Вы можете создать приложение браузера с wasmbrowser
шаблоном из командной строки, которое создает веб-приложение, демонстрирующее использование .NET и JS вместе в браузере:
dotnet new wasmbrowser
Кроме того, в Visual Studio можно создать приложение с помощью WebAssembly Browser App шаблона проекта.
Создайте приложение из Visual Studio или с помощью .NET CLI:
dotnet build
Создайте и запустите приложение из Visual Studio или с помощью .NET CLI:
dotnet run
Кроме того, установите и используйте dotnet serve
команду:
dotnet serve -d:bin/$(Configuration)/{TARGET FRAMEWORK}/publish
В предыдущем примере {TARGET FRAMEWORK}
заполнитель — это моникер целевой платформы.
Узел.js консольное приложение
Консольное приложение можно создать с wasmconsole
помощью шаблона, которое создает приложение, которое выполняется в WASM качестве узла или консольного приложения версии 8:js
dotnet new wasmconsole
Кроме того, в Visual Studio можно создать приложение с помощью WebAssembly Console App шаблона проекта.
Создайте приложение из Visual Studio или с помощью .NET CLI:
dotnet build
Создайте и запустите приложение из Visual Studio или с помощью .NET CLI:
dotnet run
Кроме того, запустите любой статический файловый сервер из выходного каталога публикации, содержащего main.mjs
файл:
node bin/$(Configuration)/{TARGET FRAMEWORK}/{PATH}/main.mjs
В предыдущем примере {TARGET FRAMEWORK}
заполнитель — это моникер целевой платформы, а {PATH}
заполнитель — путь к файлу main.mjs
.
Дополнительные ресурсы
- Взаимодействие JavaScript '[JSImport]/'[JSExport]' в .NET WebAssembly
- Взаимодействие JavaScript JSImport/JSExport с ASP.NET Core Blazor
- Документация по API
- В репозитории
dotnet/runtime
GitHub: - Использование .NET из любого приложения JavaScript в .NET 7
ASP.NET Core