从 ASP.NET Core Blazor 中的 JavaScript 函数调用 .NET 方法Call .NET methods from JavaScript functions in ASP.NET Core Blazor

本文内容

作者:Javier Calvarro NelsonDaniel RothLuke Latham

重要

Blazor WebAssembly 为预览版状态

ASP.NET Core 3.0 支持 Blazor Server。Blazor WebAssembly 在 ASP.NET Core 3.1 中为预览版。

Blazor 应用可通过 .NET 方法调用 JavaScript 函数,也可通过 JavaScript 函数调用 .NET 方法。这被称为 JavaScript 互操作(JS 互操作) 。

本文介绍如何从 JavaScript 调用 .NET 方法。要详细了解如何通过 .NET 调用 JavaScript 函数,请参阅 在 ASP.NET Core Blazor 中从 .NET 方法调用 JavaScript 函数

查看或下载示例代码如何下载

静态 .NET 方法调用Static .NET method call

要从 JavaScript 调用静态 .NET 方法,请使用 DotNet.invokeMethodDotNet.invokeMethodAsync 函数。传入要调用的静态方法的标识符、包含该函数的程序集的名称以及任意自变量。异步版本是支持 Blazor 服务器方案的首选。该 .NET 方法必须是公共的静态方法,并具有 [JSInvokable] 特性。当前不支持调用开放式泛型方法。

该示例应用包含一个 C# 方法,用于返回 int 数组。JSInvokable 特性应用于该方法。

Pages/JsInterop.razor :

  1. <button type="button" class="btn btn-primary"
  2. onclick="exampleJsFunctions.returnArrayAsyncJs()">
  3. Trigger .NET static method ReturnArrayAsync
  4. </button>
  5. @code {
  6. [JSInvokable]
  7. public static Task<int[]> ReturnArrayAsync()
  8. {
  9. return Task.FromResult(new int[] { 1, 2, 3 });
  10. }
  11. }

为客户端提供的 JavaScript 会调用 C# .net 方法。

wwwroot/exampleJsInterop.js :

  1. window.exampleJsFunctions = {
  2. showPrompt: function (text) {
  3. return prompt(text, 'Type your name here');
  4. },
  5. displayWelcome: function (welcomeMessage) {
  6. document.getElementById('welcome').innerText = welcomeMessage;
  7. },
  8. returnArrayAsyncJs: function () {
  9. DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
  10. .then(data => {
  11. data.push(4);
  12. console.log(data);
  13. });
  14. },
  15. sayHello: function (dotnetHelper) {
  16. return dotnetHelper.invokeMethodAsync('SayHello')
  17. .then(r => console.log(r));
  18. }
  19. };

如果选择了“触发 .NET 静态方法 ReturnArrayAsync”按钮,请在浏览器的 Web 开发人员工具中检查控制台输出 。

控制台输出为:

  1. Array(4) [ 1, 2, 3, 4 ]

第四个数组值推送到 ReturnArrayAsync 返回的数组 (data.push(4);)。

默认情况下,方法标识符为方法名称,但你可使用 JSInvokableAttribute 构造函数指定其他标识符:

  1. @code {
  2. [JSInvokable("DifferentMethodName")]
  3. public static Task<int[]> ReturnArrayAsync()
  4. {
  5. return Task.FromResult(new int[] { 1, 2, 3 });
  6. }
  7. }

在客户端 JavaScript 文件中:

  1. returnArrayAsyncJs: function () {
  2. DotNet.invokeMethodAsync('BlazorSample', 'DifferentMethodName')
  3. .then(data => {
  4. data.push(4);
  5. console.log(data);
  6. });
  7. }

实例方法调用Instance method call

还可以从 JavaScript 调用 .NET 实例方法。从 JavaScript 调用 .NET 实例方法:

  • 按引用向 JavaScript 传递 .NET 实例:
    • DotNetObjectReference.Create 进行静态调用。
    • DotNetObjectReference 实例中包装实例,并在 DotNetObjectReference 实例上调用 Create。处置 DotNetObjectReference 对象(本部分稍后会展示一个示例)。
  • 使用 invokeMethodinvokeMethodAsync 函数在实例上调用 .NET 实例方法。在从 JavaScript 调用其他 .NET 方法时,也可以将 .NET 实例作为自变量传递。

备注

示例应用会将消息记录到客户端控制台。对于示例应用展示的以下示例,请在浏览器的开发人员工具中检查浏览器的控制台输出。

选择“触发 .NET 实例方法 HelloHelper.SayHello”按钮时,将调用 ExampleJsInterop.CallHelloHelperSayHello,并将名称 Blazor 传递到方法 。

Pages/JsInterop.razor :

  1. <button type="button" class="btn btn-primary" @onclick="TriggerNetInstanceMethod">
  2. Trigger .NET instance method HelloHelper.SayHello
  3. </button>
  4. @code {
  5. public async Task TriggerNetInstanceMethod()
  6. {
  7. var exampleJsInterop = new ExampleJsInterop(JSRuntime);
  8. await exampleJsInterop.CallHelloHelperSayHello("Blazor");
  9. }
  10. }

CallHelloHelperSayHello 使用 HelloHelper 的新实例调用 JavaScript 函数 sayHello

JsInteropClasses/ExampleJsInterop.cs :

  1. public class ExampleJsInterop : IDisposable
  2. {
  3. private readonly IJSRuntime _jsRuntime;
  4. private DotNetObjectReference<HelloHelper> _objRef;
  5. public ExampleJsInterop(IJSRuntime jsRuntime)
  6. {
  7. _jsRuntime = jsRuntime;
  8. }
  9. public ValueTask<string> CallHelloHelperSayHello(string name)
  10. {
  11. _objRef = DotNetObjectReference.Create(new HelloHelper(name));
  12. return _jsRuntime.InvokeAsync<string>(
  13. "exampleJsFunctions.sayHello",
  14. _objRef);
  15. }
  16. public void Dispose()
  17. {
  18. _objRef?.Dispose();
  19. }
  20. }

wwwroot/exampleJsInterop.js :

  1. window.exampleJsFunctions = {
  2. showPrompt: function (text) {
  3. return prompt(text, 'Type your name here');
  4. },
  5. displayWelcome: function (welcomeMessage) {
  6. document.getElementById('welcome').innerText = welcomeMessage;
  7. },
  8. returnArrayAsyncJs: function () {
  9. DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
  10. .then(data => {
  11. data.push(4);
  12. console.log(data);
  13. });
  14. },
  15. sayHello: function (dotnetHelper) {
  16. return dotnetHelper.invokeMethodAsync('SayHello')
  17. .then(r => console.log(r));
  18. }
  19. };

该名称将传递给 HelloHelper 的构造函数,该构造函数设置 HelloHelper.Name 属性。执行 JavaScript 函数 sayHello 时,HelloHelper.SayHello 返回 Hello, {Name}! 消息,JavaScript 函数将该消息写入控制台。

JsInteropClasses/HelloHelper.cs :

  1. public class HelloHelper
  2. {
  3. public HelloHelper(string name)
  4. {
  5. Name = name;
  6. }
  7. public string Name { get; set; }
  8. [JSInvokable]
  9. public string SayHello() => $"Hello, {Name}!";
  10. }

浏览器 Web 开发人员工具中的控制台输出:

  1. Hello, Blazor!

为避免内存泄露并允许对创建 DotNetObjectReference 的组件进行垃圾回收,请处置类中创建 DotNetObjectReference 实例的对象:

  1. public class ExampleJsInterop : IDisposable
  2. {
  3. private readonly IJSRuntime _jsRuntime;
  4. private DotNetObjectReference<HelloHelper> _objRef;
  5. public ExampleJsInterop(IJSRuntime jsRuntime)
  6. {
  7. _jsRuntime = jsRuntime;
  8. }
  9. public ValueTask<string> CallHelloHelperSayHello(string name)
  10. {
  11. _objRef = DotNetObjectReference.Create(new HelloHelper(name));
  12. return _jsRuntime.InvokeAsync<string>(
  13. "exampleJsFunctions.sayHello",
  14. _objRef);
  15. }
  16. public void Dispose()
  17. {
  18. _objRef?.Dispose();
  19. }
  20. }

还可以在组件中实现上述 ExampleJsInterop 类中所示的模式:

  1. @page "/JSInteropComponent"
  2. @using BlazorSample.JsInteropClasses
  3. @implements IDisposable
  4. @inject IJSRuntime JSRuntime
  5. <h1>JavaScript Interop</h1>
  6. <button type="button" class="btn btn-primary" @onclick="TriggerNetInstanceMethod">
  7. Trigger .NET instance method HelloHelper.SayHello
  8. </button>
  9. @code {
  10. private DotNetObjectReference<HelloHelper> _objRef;
  11. public async Task TriggerNetInstanceMethod()
  12. {
  13. _objRef = DotNetObjectReference.Create(new HelloHelper("Blazor"));
  14. await JSRuntime.InvokeAsync<string>(
  15. "exampleJsFunctions.sayHello",
  16. _objRef);
  17. }
  18. public void Dispose()
  19. {
  20. _objRef?.Dispose();
  21. }
  22. }

在类库中共享互操作代码Share interop code in a class library

可在类库中包含 JS 互操作代码,以便能在 NuGet 包中共享代码。

类库会处理在生成的程序集中嵌入 JavaScript 资源的操作。JavaScript 文件位于 wwwroot 文件夹中 。工具负责在生成库时嵌入资源。

按引用任何其他 NuGet 包的方式在应用的项目文件中引用生成的 NuGet 包。包还原后,应用代码可如同是 C# 一样调入 JavaScript。

有关详细信息,请参阅 ASP.NET Core Razor 组件类库

其他资源Additional resources