BlazorServer中C#与JavaScript的相互调用
前言:
虽然BlazorServer中推荐使用C#在razor页面中的替代JavaScript来完成逻辑的编写,但当需要使用第三方的javascript文件/组件里的内容时,则难免要在C#中调用其方法或对象。反之当你的(用到第三方组件的)Javascript代码想要和后台交互时,则需要调用C#的代码。好在BlazorServer中这两种通信都是支持的。下面将介绍其具体的实现方式。
🌮一.C#调用JavaScript方法
Blazor提供了IJSRuntime组件来提供与JavaScript的交互。
🍎 BlazorServer启动时就已经创建了IJSRuntime的实例,所以你可以直接使用构造方法注入
public class CustomService
{
private readonly IJSRuntime _runtime;
public CustomService(IJSRuntime runtime)
{
_runtime = runtime;
}
}
🍌在razor页面(组件)中也是直接获取即可
page "/mytest"
<!--直接使用@inject标签获取即可-->
@inject IJSRuntime runtime
<h3>MyTest</h3>
1.调取公用函数
page "/mytest"
<!--直接使用@inject标签获取即可-->
@inject IJSRuntime runtime
<h3>MyTest</h3>
<button type="button" @onclick="DoNothing">点击</button>
@code {
public void DoNothing()
{
await runtime.InvokeVoidAsync("alert",new object[1] { "FUCKYOU" }); //无返回值
//runtime.InvokeAsync<>(); 有返回值
}
}
测试结果:
2.调取外部JavaScript函数
上面的只单独调用公共函数的时候不多,大多数时候需要从别的地方获取。调用方法如下
现有一自定义js文件如下(TestScript.js)
function WhatTheHell() {
alert("WTF");
}
function WhatTheHell_2() {
alert("这次有返回值");
return 123
}
function WhatTheHell_3(param) {
alert("有返回值及参数");
console.log(JSON.stringify(param));
return 10086
}
先将其放到BlazorServer的js文件指定目录下(wwwroot/js/)
再在_Host.cshtml中引入该js文件
在razor页面中使用
@page "/mytest"
@inject IJSRuntime runtime
<h3>MyTest</h3>
<button type="button" @onclick="MethodOne">方法一(无返回值和参数)</button> <br/>
<button type="button" @onclick="MethodTwo">方法二(无返回值)</button> <br/>
<button type="button" @onclick="MethodThree">方法三(返回值和参数)</button> <br/>
@code {
public async void MethodOne()
{
await runtime.InvokeVoidAsync("WhatTheHell",null);
}
public async void MethodTwo()
{
var num = await runtime.InvokeAsync<int>("WhatTheHell_2",null);
Console.WriteLine("获取js的返回值为" + num);
}
public async void MethodThree()
{
var num = await runtime.InvokeAsync<int>("WhatTheHell_3", new object[1] { "尼哥" });
Console.WriteLine("获取js的返回值为" + num);
}
}
测试结果为:
当JS的返回值为复杂对象时,则推荐使用IJSObjectReference来获取,具体可以参考
IJSObjectReference 接口 (Microsoft.JSInterop) | Microsoft Learn
🍕 二.JavaScript调用C#方法
在JavaScript中调用C#的方法则比较复杂,需要考虑到静态/动态区分的问题
🌀1.静态方法的调用
DotNet.invokeMethodAsync('AssemblyName', 'Namespace.ClassName', 'MethodName', arg1, arg2);
这将调用指定程序集(AssemblyName)、命名空间(Namespace[可以省略])和类名(ClassName)中的静态方法(MethodName),并传递arg1和arg2作为参数。
例:
@page "/jstest"
@inject IJSRuntime runtime
<h3>Jsusecsharp</h3>
<span style="font-size:36px">到达世界最高城 @Title</span>
<button type="button" @onclick="Change">前往朝圣</button>
@code {
public static string Title = "沈阳!";
public async void Change()
{
await runtime.InvokeVoidAsync("use_csharp",null);
}
[JSInvokable]
public static void ChangeTheTitle()
{
Title = "理塘";
}
}
js文件
async function use_csharp() {
await DotNet.invokeMethodAsync('BlazorApp2','ChangeTheTitle', null);
}
测试结果:
✈️ 2…动态方法的调用
下面是微软文档的内容
若要从 JavaScript (JS) 调用实例 .NET 方法,请执行以下操作:
-
通过将实例包装在 DotNetObjectReference 中并对其调用 Create,将 .NET 实例通过引用传递给 JS。
-
使用传递的 DotNetObjectReference 中的
invokeMethodAsync
(推荐)或invokeMethod
(仅限 Blazor WebAssembly)从 JS 调用 .NET 实例方法。 传入实例 .NET 方法的标识符以及任意自变量。 在从 JS 调用其他 .NET 方法时,也可以将 .NET 实例作为参数传递。如下示例中:
dotNetHelper
为 DotNetObjectReference。{.NET METHOD ID}
占位符是 .NET 方法标识符。{ARGUMENTS}
占位符是要传递给该方法的以逗号分隔的可选参数,其中每个参数都必须是可执行 JSON 序列化的。
⛵️ 总结:
动态方法的调用需要传递实例(使用DotNetObjectReference对象),需要在方法中设置实例参数,再由实例进行invoke操作。
例:
@page "/jstest"
@using BlazorApp2.Utils
@inject IJSRuntime runtime
<h3>Jsusecsharp</h3>
<span style="font-size:36px">到达世界最高城 @Title</span>
<button type="button" @onclick="Change">前往朝圣</button>
@code {
public static string Title = "沈阳!";
//用于传递给JS的实例
private DotNetObjectReference<Jsusecsharp> objref;
protected override void OnInitialized()
{
objref = DotNetObjectReference.Create(this);
}
public async void Change()
{
//将实例作为参数传给调用的JS
await runtime.InvokeVoidAsync("use_csharp_dy",objref);
}
/// <summary>
/// 静态方法
/// </summary>
[JSInvokable]
public static void ChangeTheTitle()
{
Title = "理塘";
}
[JSInvokable("ChangeTheTitle_2")]
public void ChangeTheTitle_2()
{
Title = "通辽";
}
}
JS:
async function use_csharp_dy(instance) {
//instance 即为razor中的objref,由其进行调用
await instance.invokeMethodAsync('ChangeTheTitle_2', null);
}
参数结果:
未完。。。。。